aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2019-03-08 22:06:48 +0000
committerYi Kong <yikong@google.com>2019-04-02 01:13:24 -0700
commit61f23aed99296fe3545155f3f4352221eb024559 (patch)
treeea5249a18431d55ef14a6cdcb90613efd1f56883
parent649b4adfc45b26ae937fe597ef6134d244f89686 (diff)
downloadclang-61f23aed99296fe3545155f3f4352221eb024559.tar.gz
[8.0 Regression] Fix handling of `__builtin_constant_p` inside template arguments, enumerators, case statements, and the enable_if attribute.
Summary: The following code is accepted by Clang 7 and prior but rejected by the upcoming 8 release and in trunk [1] ``` // error {{never produces a constant expression}} void foo(const char* s) __attribute__((enable_if(__builtin_constant_p(*s) == false, "trap"))) {} void test() { foo("abc"); } ``` Prior to Clang 8, the call to `__builtin_constant_p` was a constant expression returning false. Currently, it's not a valid constant expression. The bug is caused because we failed to set `InConstantContext` when attempting to evaluate unevaluated constant expressions. [1] https://godbolt.org/z/ksAjmq Reviewers: rsmith, hans, sbenza Reviewed By: rsmith Subscribers: kristina, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D59038 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@355743 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/ExprConstant.cpp3
-rw-r--r--test/SemaCXX/constant-expression-cxx1y.cpp24
-rw-r--r--test/SemaCXX/enable_if.cpp8
3 files changed, 35 insertions, 0 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 19e6b53b09..603e9c1ad8 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -11076,6 +11076,7 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage,
const ASTContext &Ctx) const {
EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
EvalInfo Info(Ctx, Result, EM);
+ Info.InConstantContext = true;
if (!::Evaluate(Result.Val, Info, this))
return false;
@@ -11716,6 +11717,7 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
const Expr *This) const {
Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpressionUnevaluated);
+ Info.InConstantContext = true;
LValue ThisVal;
const LValue *ThisPtr = nullptr;
@@ -11799,6 +11801,7 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
EvalInfo Info(FD->getASTContext(), Status,
EvalInfo::EM_PotentialConstantExpressionUnevaluated);
+ Info.InConstantContext = true;
// Fabricate a call stack frame to give the arguments a plausible cover story.
ArrayRef<const Expr*> Args;
diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp
index 3c57ac573f..ed51cca82e 100644
--- a/test/SemaCXX/constant-expression-cxx1y.cpp
+++ b/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -1135,3 +1135,27 @@ constexpr bool indirect_builtin_constant_p(const char *__s) {
return __builtin_constant_p(*__s);
}
constexpr bool n = indirect_builtin_constant_p("a");
+
+__attribute__((enable_if(indirect_builtin_constant_p("a") == n, "OK")))
+int test_in_enable_if() { return 0; }
+int n2 = test_in_enable_if();
+
+template <bool n = indirect_builtin_constant_p("a")>
+int test_in_template_param() { return 0; }
+int n3 = test_in_template_param();
+
+void test_in_case(int n) {
+ switch (n) {
+ case indirect_builtin_constant_p("abc"):
+ break;
+ }
+}
+enum InEnum1 {
+ ONE = indirect_builtin_constant_p("abc")
+};
+enum InEnum2 : int {
+ TWO = indirect_builtin_constant_p("abc")
+};
+enum class InEnum3 {
+ THREE = indirect_builtin_constant_p("abc")
+};
diff --git a/test/SemaCXX/enable_if.cpp b/test/SemaCXX/enable_if.cpp
index ba520b047a..4bc974dafc 100644
--- a/test/SemaCXX/enable_if.cpp
+++ b/test/SemaCXX/enable_if.cpp
@@ -514,3 +514,11 @@ namespace TypeOfFn {
static_assert(is_same<__typeof__(foo)*, decltype(&foo)>::value, "");
}
+
+namespace InConstantContext {
+void foo(const char *s) __attribute__((enable_if(((void)__builtin_constant_p(*s), true), "trap"))) {}
+
+void test() {
+ InConstantContext::foo("abc");
+}
+} // namespace InConstantContext