]> granicus.if.org Git - clang/commitdiff
Implement C++11 constant expression cast restrictions.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 12 Dec 2011 12:46:16 +0000 (12:46 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 12 Dec 2011 12:46:16 +0000 (12:46 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146371 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticASTKinds.td
lib/AST/ExprConstant.cpp
test/SemaCXX/constant-expression-cxx11.cpp

index 705c95b7fc276058d40570e46f63c8744ced0b2c..e16f768b2a9bb71f989a4e3a5a1114f00100b0f0 100644 (file)
@@ -12,6 +12,9 @@ let Component = "AST" in {
 //def note_comma_in_ice : Note<
 //  "C does not permit evaluated commas in an integer constant expression">;
 def note_expr_divide_by_zero : Note<"division by zero">;
+def note_constexpr_invalid_cast : Note<
+  "%select{reinterpret_cast|dynamic_cast|reinterpreting cast}0 not allowed "
+  "in a constant expression">;
 
 // inline asm related.
 let CategoryName = "Inline Assembly Issue" in {
index 1bf1693b222e665d8ad4299814c41cf5655bfdf0..62d70dd978284f136e1bc7fa38880451f11a4863 100644 (file)
@@ -1616,6 +1616,15 @@ public:
   RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
     { return StmtVisitorTy::Visit(E->getExpr()); }
 
+  RetTy VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
+    CCEDiag(E, diag::note_constexpr_invalid_cast) << 0;
+    return static_cast<Derived*>(this)->VisitCastExpr(E);
+  }
+  RetTy VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
+    CCEDiag(E, diag::note_constexpr_invalid_cast) << 1;
+    return static_cast<Derived*>(this)->VisitCastExpr(E);
+  }
+
   RetTy VisitBinaryOperator(const BinaryOperator *E) {
     switch (E->getOpcode()) {
     default:
@@ -1988,6 +1997,7 @@ public:
       return LValueExprEvaluatorBaseTy::VisitCastExpr(E);
 
     case CK_LValueBitCast:
+      this->CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
       if (!Visit(E->getSubExpr()))
         return false;
       Result.Designator.setInvalid();
@@ -2213,6 +2223,11 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
   case CK_CPointerToObjCPointerCast:
   case CK_BlockPointerToObjCPointerCast:
   case CK_AnyPointerToBlockPointerCast:
+    // Bitcasts to cv void* are static_casts, not reinterpret_casts, so are
+    // permitted in constant expressions in C++11. Bitcasts from cv void* are
+    // also static_casts, but we disallow them as a resolution to DR1312.
+    if (!E->getType()->isVoidPointerType())
+      CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
     if (!Visit(SubExpr))
       return false;
     Result.Designator.setInvalid();
@@ -2251,6 +2266,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
     return ValueInitialization(E);
 
   case CK_IntegralToPointer: {
+    CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+
     CCValue Value;
     if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
       break;
@@ -3826,6 +3843,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
   }
 
   case CK_PointerToIntegral: {
+    CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+
     LValue LV;
     if (!EvaluatePointer(SubExpr, LV, Info))
       return false;
index 3ba87b3d91e9b6cf5994d5190717aea6086eff6f..55762b4ea4ce17092029e22063db5168bb481d68 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-linux -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple i686-linux -fsyntax-only -verify -std=c++11 -pedantic %s -Wno-comment
 
 namespace StaticAssertFoldTest {
 
@@ -165,7 +165,7 @@ namespace FunctionCast {
   constexpr int f() { return 1; }
   typedef double (*DoubleFn)();
   typedef int (*IntFn)();
-  int a[(int)DoubleFn(f)()]; // expected-error {{variable length array}}
+  int a[(int)DoubleFn(f)()]; // expected-error {{variable length array}} expected-warning{{extension}}
   int b[(int)IntFn(f)()];    // ok
 }
 
@@ -297,6 +297,31 @@ constexpr S* sptr = &s;
 // test elsewhere.
 constexpr bool dyncast = sptr == dynamic_cast<S*>(sptr);
 
+struct Str {
+  // FIXME: In C++ mode, we should say 'integral' not 'integer'
+  int a : dynamic_cast<S*>(sptr) == dynamic_cast<S*>(sptr); // \
+    expected-warning {{not integer constant expression}} \
+    expected-note {{dynamic_cast not allowed in a constant expression}}
+  int b : reinterpret_cast<S*>(sptr) == reinterpret_cast<S*>(sptr); // \
+    expected-warning {{not integer constant expression}} \
+    expected-note {{reinterpret_cast not allowed in a constant expression}}
+  int c : (S*)(long)(sptr) == (S*)(long)(sptr); // \
+    expected-warning {{not integer constant expression}} \
+    expected-note {{reinterpreting cast not allowed in a constant expression}}
+  int d : (S*)(42) == (S*)(42); // \
+    expected-warning {{not integer constant expression}} \
+    expected-note {{reinterpreting cast not allowed in a constant expression}}
+  int e : (Str*)(sptr) == (Str*)(sptr); // \
+    expected-warning {{not integer constant expression}} \
+    expected-note {{reinterpreting cast not allowed in a constant expression}}
+  int f : &(Str&)(*sptr) == &(Str&)(*sptr); // \
+    expected-warning {{not integer constant expression}} \
+    expected-note {{reinterpreting cast not allowed in a constant expression}}
+  int g : (S*)(void*)(sptr) == sptr; // \
+    expected-warning {{not integer constant expression}} \
+    expected-note {{reinterpreting cast not allowed in a constant expression}}
+};
+
 extern char externalvar[];
 // FIXME: This is not a constant expression; check we reject this and move this
 // test elsewhere.
@@ -414,7 +439,7 @@ 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, "");
 
-constexpr int arr[40] = { 1, 2, 3, [8] = 4 };
+constexpr int arr[40] = { 1, 2, 3, [8] = 4 }; // expected-warning {{extension}}
 constexpr int SumNonzero(const int *p) {
   return *p + (*p ? SumNonzero(p+1) : 0);
 }
@@ -677,7 +702,7 @@ union U {
   int b;
 };
 
-constexpr U u[4] = { { .a = 0 }, { .b = 1 }, { .a = 2 }, { .b = 3 } };
+constexpr U u[4] = { { .a = 0 }, { .b = 1 }, { .a = 2 }, { .b = 3 } }; // expected-warning 4{{extension}}
 static_assert(u[0].a == 0, "");
 static_assert(u[0].b, ""); // expected-error {{constant expression}}
 static_assert(u[1].b == 1, "");