diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 6 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 51 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 22 | ||||
-rw-r--r-- | test/SemaCXX/static-assert.cpp | 5 |
5 files changed, 56 insertions, 41 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 34e5174f41..88b3f595b2 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6002,10 +6002,12 @@ public: /// in the global scope. bool CheckObjCDeclScope(Decl *D); - /// VerifyIntegerConstantExpression - verifies that an expression is an ICE, + /// VerifyIntegerConstantExpression - Verifies that an expression is an ICE, /// and reports the appropriate diagnostics. Returns false on success. /// Can optionally return the value of the expression. - bool VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result = 0); + bool VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result = 0, + unsigned DiagId = 0, + bool AllowFold = true); /// VerifyBitField - verifies that a bit field expression is an ICE and has /// the correct width, and that the field type is valid. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index fb0307fb28..2176afa92d 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -9636,18 +9636,15 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr_); if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) { - llvm::APSInt Value(32); - if (!AssertExpr->isIntegerConstantExpr(Value, Context)) { - Diag(StaticAssertLoc, - diag::err_static_assert_expression_is_not_constant) << - AssertExpr->getSourceRange(); + llvm::APSInt Cond; + if (VerifyIntegerConstantExpression(AssertExpr, &Cond, + diag::err_static_assert_expression_is_not_constant, + /*AllowFold=*/false)) return 0; - } - if (Value == 0) { + if (!Cond) Diag(StaticAssertLoc, diag::err_static_assert_failed) << AssertMessage->getString() << AssertExpr->getSourceRange(); - } } if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression)) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d9626369d9..8231cda75e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9232,30 +9232,45 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, return isInvalid; } -bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ - // FIXME: In C++11, this evaluates the expression even if it's not an ICE. - // Don't evaluate it a second time below just to get the diagnostics. - llvm::APSInt ICEResult; - if (E->isIntegerConstantExpr(ICEResult, Context)) { - if (Result) - *Result = ICEResult; - return false; +bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result, + unsigned DiagID, bool AllowFold) { + // Circumvent ICE checking in C++11 to avoid evaluating the expression twice + // in the non-ICE case. + if (!getLangOptions().CPlusPlus0x) { + if (E->isIntegerConstantExpr(Context)) { + if (Result) + *Result = E->EvaluateKnownConstInt(Context); + return false; + } } Expr::EvalResult EvalResult; llvm::SmallVector<PartialDiagnosticAt, 8> Notes; EvalResult.Diag = &Notes; - if (!E->EvaluateAsRValue(EvalResult, Context) || !EvalResult.Val.isInt() || - EvalResult.HasSideEffects) { - Diag(E->getExprLoc(), diag::err_expr_not_ice) << E->getSourceRange(); + // Try to evaluate the expression, and produce diagnostics explaining why it's + // not a constant expression as a side-effect. + bool Folded = E->EvaluateAsRValue(EvalResult, Context) && + EvalResult.Val.isInt() && !EvalResult.HasSideEffects; + + // In C++11, we can rely on diagnostics being produced for any expression + // which is not a constant expression. If no diagnostics were produced, then + // this is a constant expression. + if (Folded && getLangOptions().CPlusPlus0x && Notes.empty()) { + if (Result) + *Result = EvalResult.Val.getInt(); + return false; + } + + if (!Folded || !AllowFold) { + Diag(E->getSourceRange().getBegin(), + DiagID ? DiagID : diag::err_expr_not_ice) << E->getSourceRange(); // We only show the notes if they're not the usual "invalid subexpression" // or if they are actually in a subexpression. - if (!Notes.empty() && - (Notes.size() != 1 || - Notes[0].second.getDiagID() != diag::note_invalid_subexpr_in_const_expr - || Notes[0].first != E->IgnoreParens()->getExprLoc())) { + if (Notes.size() != 1 || + Notes[0].second.getDiagID() != diag::note_invalid_subexpr_in_const_expr + || Notes[0].first != E->IgnoreParens()->getExprLoc()) { for (unsigned I = 0, N = Notes.size(); I != N; ++I) Diag(Notes[I].first, Notes[I].second); } @@ -9263,10 +9278,10 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ return true; } - Diag(E->getExprLoc(), diag::ext_expr_not_ice) << E->getSourceRange(); + Diag(E->getSourceRange().getBegin(), diag::ext_expr_not_ice) + << E->getSourceRange(); - if (Notes.size() && - Diags.getDiagnosticLevel(diag::ext_expr_not_ice, E->getExprLoc()) + if (Diags.getDiagnosticLevel(diag::ext_expr_not_ice, E->getExprLoc()) != DiagnosticsEngine::Ignored) for (unsigned I = 0, N = Notes.size(); I != N; ++I) Diag(Notes[I].first, Notes[I].second); diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index f284bd6133..4b59157ea6 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -141,7 +141,7 @@ static_assert(F(1, 0) == 1, ""); static_assert(F(2, "test") == 2, ""); static_assert(F(3, &F) == 3, ""); int k = 0; -static_assert(F(4, k) == 3, ""); // expected-error {{constant expression}} +static_assert(F(4, k) == 3, ""); // expected-error {{constant expression}} expected-note {{subexpression}} } @@ -414,7 +414,9 @@ static_assert(sum_xs == 15, ""); constexpr int ZipFoldR(int (*F)(int x, int y, int c), int n, const int *xs, const int *ys, int c) { - return n ? F(*xs, *ys, ZipFoldR(F, n-1, xs+1, ys+1, c)) : c; + return n ? F( + *xs, // expected-note {{subexpression not valid}} + *ys, ZipFoldR(F, n-1, xs+1, ys+1, c)) : c; } constexpr int MulAdd(int x, int y, int c) { return x * y + c; } constexpr int InnerProduct = ZipFoldR(MulAdd, 5, xs, ys, 0); @@ -434,7 +436,7 @@ constexpr int xs_1 = p[-4]; // expected-error {{constant expression}} constexpr int zs[2][2][2][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; static_assert(zs[0][0][0][0] == 1, ""); static_assert(zs[1][1][1][1] == 16, ""); -static_assert(zs[0][0][0][2] == 3, ""); // expected-error {{constant expression}} +static_assert(zs[0][0][0][2] == 3, ""); // expected-error {{constant expression}} expected-note {{subexpression}} static_assert((&zs[0][0][0][2])[-1] == 2, ""); static_assert(**(**(zs + 1) + 1) == 11, ""); static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1) == 11, ""); @@ -505,7 +507,7 @@ constexpr const E &e1 = E(); // expected-error {{constant expression}} // We notice this when evaluating an expression which uses it, but not when // checking its initializer. constexpr E e2 = E(); // unexpected-error {{constant expression}} -static_assert(e2.p == &e2.p, ""); // unexpected-error {{constant expression}} +static_assert(e2.p == &e2.p, ""); // unexpected-error {{constant expression}} unexpected-note {{subexpression}} // FIXME: We don't pass through the fact that 'this' is ::e3 when checking the // initializer of this declaration. constexpr E e3; // unexpected-error {{constant expression}} @@ -533,10 +535,10 @@ struct G { constexpr G() : t(&t) {} } constexpr g; -static_assert(g.t.u1.a == 42, ""); // expected-error {{constant expression}} +static_assert(g.t.u1.a == 42, ""); // expected-error {{constant expression}} expected-note {{subexpression}} static_assert(g.t.u1.b == 42, ""); static_assert(g.t.u2.c == 42, ""); -static_assert(g.t.u2.d == 42, ""); // expected-error {{constant expression}} +static_assert(g.t.u2.d == 42, ""); // expected-error {{constant expression}} expected-note {{subexpression}} struct S { int a, b; @@ -580,10 +582,10 @@ constexpr AggregateInit agg1 = { "hello"[0] }; static_assert(strcmp_ce(&agg1.c, "hello") == 0, ""); static_assert(agg1.n == 0, ""); static_assert(agg1.d == 0.0, ""); -static_assert(agg1.arr[-1] == 0, ""); // expected-error {{constant expression}} +static_assert(agg1.arr[-1] == 0, ""); // expected-error {{constant expression}} expected-note {{subexpression}} static_assert(agg1.arr[0] == 0, ""); static_assert(agg1.arr[4] == 0, ""); -static_assert(agg1.arr[5] == 0, ""); // expected-error {{constant expression}} +static_assert(agg1.arr[5] == 0, ""); // expected-error {{constant expression}} expected-note {{subexpression}} static_assert(agg1.p == nullptr, ""); namespace SimpleDerivedClass { @@ -706,8 +708,8 @@ constexpr U u[4] = { { .a = 0 }, { .b = 1 }, { .a = 2 }, { .b = 3 } }; // expect static_assert(u[0].a == 0, ""); static_assert(u[0].b, ""); // expected-error {{constant expression}} static_assert(u[1].b == 1, ""); -static_assert((&u[1].b)[1] == 2, ""); // expected-error {{constant expression}} -static_assert(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} +static_assert((&u[1].b)[1] == 2, ""); // expected-error {{constant expression}} expected-note {{subexpression}} +static_assert(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} expected-note {{subexpression}} static_assert((&(u[1]) + 1 + 1)->b == 3, ""); } diff --git a/test/SemaCXX/static-assert.cpp b/test/SemaCXX/static-assert.cpp index 0991a5f89c..2b44e81d3e 100644 --- a/test/SemaCXX/static-assert.cpp +++ b/test/SemaCXX/static-assert.cpp @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -int f(); +int f(); // expected-note {{declared here}} -static_assert(f(), "f"); // expected-error {{static_assert expression is not an integral constant expression}} +static_assert(f(), "f"); // expected-error {{static_assert expression is not an integral constant expression}} expected-note {{non-constexpr function 'f' cannot be used in a constant expression}} static_assert(true, "true is not false"); static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}} @@ -27,4 +27,3 @@ template<typename T> struct S { S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}} S<int> s2; - |