[cfe-commits] r146607 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp test/SemaCXX/constant-expression-cxx11.cpp test/SemaCXX/static-assert.cpp

Richard Smith richard-llvm at metafoo.co.uk
Wed Dec 14 15:32:26 PST 2011


Author: rsmith
Date: Wed Dec 14 17:32:26 2011
New Revision: 146607

URL: http://llvm.org/viewvc/llvm-project?rev=146607&view=rev
Log:
Produce more detailed diagnostics when static_assert condition is not an ICE.

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
    cfe/trunk/test/SemaCXX/static-assert.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=146607&r1=146606&r2=146607&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Dec 14 17:32:26 2011
@@ -6002,10 +6002,12 @@
   /// 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.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=146607&r1=146606&r2=146607&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Dec 14 17:32:26 2011
@@ -9636,18 +9636,15 @@
   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))

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=146607&r1=146606&r2=146607&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Dec 14 17:32:26 2011
@@ -9232,30 +9232,45 @@
   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 @@
     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);

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=146607&r1=146606&r2=146607&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Wed Dec 14 17:32:26 2011
@@ -141,7 +141,7 @@
 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 @@
 
 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 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 @@
 // 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 @@
   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 @@
 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 @@
 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, "");
 
 }

Modified: cfe/trunk/test/SemaCXX/static-assert.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/static-assert.cpp?rev=146607&r1=146606&r2=146607&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/static-assert.cpp (original)
+++ cfe/trunk/test/SemaCXX/static-assert.cpp Wed Dec 14 17:32:26 2011
@@ -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 @@
 
 S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}}
 S<int> s2;
-





More information about the cfe-commits mailing list