From: Richard Smith Date: Mon, 12 Dec 2011 12:46:16 +0000 (+0000) Subject: Implement C++11 constant expression cast restrictions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c216a01c96d83bd9a90e214af64913e93d39aacc;p=clang Implement C++11 constant expression cast restrictions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146371 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index 705c95b7fc..e16f768b2a 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -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 { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 1bf1693b22..62d70dd978 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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(this)->VisitCastExpr(E); + } + RetTy VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) { + CCEDiag(E, diag::note_constexpr_invalid_cast) << 1; + return static_cast(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; diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 3ba87b3d91..55762b4ea4 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -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(sptr); +struct Str { + // FIXME: In C++ mode, we should say 'integral' not 'integer' + int a : dynamic_cast(sptr) == dynamic_cast(sptr); // \ + expected-warning {{not integer constant expression}} \ + expected-note {{dynamic_cast not allowed in a constant expression}} + int b : reinterpret_cast(sptr) == reinterpret_cast(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, "");