From: Richard Smith Date: Sat, 23 Sep 2017 18:27:11 +0000 (+0000) Subject: Don't warn about runtime behavior problems in variable initializers that we X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eaedd47dbde3c4312be1b89b02368be78780ca34;p=clang Don't warn about runtime behavior problems in variable initializers that we know are going to be constant-evaluated. Any relevant diagnostics should be produced by constant expression evaluation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314067 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 7784126377..75b09cf218 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -15179,10 +15179,24 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, if (Statement && getCurFunctionOrMethodDecl()) { FunctionScopes.back()->PossiblyUnreachableDiags. push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement)); + return true; } - else - Diag(Loc, PD); - + + // The initializer of a constexpr variable or of the first declaration of a + // static data member is not syntactically a constant evaluated constant, + // but nonetheless is always required to be a constant expression, so we + // can skip diagnosing. + // FIXME: Using the mangling context here is a hack. + if (auto *VD = dyn_cast_or_null( + ExprEvalContexts.back().ManglingContextDecl)) { + if (VD->isConstexpr() || + (VD->isStaticDataMember() && VD->isFirstDecl() && !VD->isInline())) + break; + // FIXME: For any other kind of variable, we should build a CFG for its + // initializer and check whether the context in question is reachable. + } + + Diag(Loc, PD); return true; } diff --git a/test/CXX/class/class.static/class.static.data/p3.cpp b/test/CXX/class/class.static/class.static.data/p3.cpp index 413017d133..5640bc30ad 100644 --- a/test/CXX/class/class.static/class.static.data/p3.cpp +++ b/test/CXX/class/class.static/class.static.data/p3.cpp @@ -50,4 +50,4 @@ U u2; // expected-note {{here}} static_assert(U::a == 0, ""); -constexpr int outofline = (U::d, 0); // expected-note {{here}} expected-warning {{unused}} +constexpr int outofline = (U::d, 0); // expected-note {{here}} diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp index 6d46bf5d77..4daed23bf9 100644 --- a/test/CXX/expr/expr.const/p2-0x.cpp +++ b/test/CXX/expr/expr.const/p2-0x.cpp @@ -145,19 +145,19 @@ namespace UndefinedBehavior { constexpr int int_min = ~0x7fffffff; constexpr int minus_int_min = -int_min; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}} - constexpr int div0 = 3 / 0; // expected-error {{constant expression}} expected-note {{division by zero}} expected-warning {{undefined}} - constexpr int mod0 = 3 % 0; // expected-error {{constant expression}} expected-note {{division by zero}} expected-warning {{undefined}} + constexpr int div0 = 3 / 0; // expected-error {{constant expression}} expected-note {{division by zero}} + constexpr int mod0 = 3 % 0; // expected-error {{constant expression}} expected-note {{division by zero}} constexpr int int_min_div_minus_1 = int_min / -1; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}} constexpr int int_min_mod_minus_1 = int_min % -1; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}} - constexpr int shl_m1 = 0 << -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} expected-warning {{negative}} + constexpr int shl_m1 = 0 << -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} constexpr int shl_0 = 0 << 0; // ok constexpr int shl_31 = 0 << 31; // ok - constexpr int shl_32 = 0 << 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type 'int' (32}} expected-warning {{>= width of type}} + constexpr int shl_32 = 0 << 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type 'int' (32}} constexpr int shl_unsigned_negative = unsigned(-3) << 1; // ok constexpr int shl_unsigned_into_sign = 1u << 31; // ok constexpr int shl_unsigned_overflow = 1024u << 31; // ok - constexpr int shl_signed_negative = (-3) << 1; // expected-warning {{shifting a negative signed value is undefined}} // expected-error {{constant expression}} expected-note {{left shift of negative value -3}} + constexpr int shl_signed_negative = (-3) << 1; // expected-error {{constant expression}} expected-note {{left shift of negative value -3}} constexpr int shl_signed_ok = 1 << 30; // ok constexpr int shl_signed_into_sign = 1 << 31; // ok (DR1457) constexpr int shl_signed_into_sign_2 = 0x7fffffff << 1; // ok (DR1457) @@ -166,10 +166,10 @@ namespace UndefinedBehavior { constexpr int shl_signed_overflow = 1024 << 31; // expected-error {{constant expression}} expected-note {{signed left shift discards bits}} expected-warning {{requires 43 bits to represent}} constexpr int shl_signed_ok2 = 1024 << 20; // ok - constexpr int shr_m1 = 0 >> -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} expected-warning {{negative}} + constexpr int shr_m1 = 0 >> -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} constexpr int shr_0 = 0 >> 0; // ok constexpr int shr_31 = 0 >> 31; // ok - constexpr int shr_32 = 0 >> 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type}} expected-warning {{>= width of type}} + constexpr int shr_32 = 0 >> 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type}} struct S { int m; diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index b1575077cd..e64f2d5a33 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -328,7 +328,7 @@ struct Str { extern char externalvar[]; constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}} expected-note {{reinterpret_cast}} -constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} expected-warning {{unspecified}} +constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} static_assert(0 != "foo", ""); } @@ -364,7 +364,7 @@ void foo() { constexpr B b3 { { 1 }, { 2 } }; // expected-error {{constant expression}} expected-note {{reference to temporary}} expected-note {{here}} } -constexpr B &&b4 = ((1, 2), 3, 4, B { {10}, {{20}} }); // expected-warning 4{{unused}} +constexpr B &&b4 = ((1, 2), 3, 4, B { {10}, {{20}} }); static_assert(&b4 != &b2, ""); // Proposed DR: copy-elision doesn't trigger lifetime extension. @@ -1965,7 +1965,7 @@ namespace NeverConstantTwoWays { constexpr int n = // expected-error {{must be initialized by a constant expression}} (int *)(long)&n == &n ? // expected-note {{reinterpret_cast}} - 1 / 0 : // expected-warning {{division by zero}} + 1 / 0 : 0; } diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp index 547470db5c..648ee4153f 100644 --- a/test/SemaTemplate/instantiate-static-var.cpp +++ b/test/SemaTemplate/instantiate-static-var.cpp @@ -5,7 +5,7 @@ template class X { public: - static const T value = 10 / Divisor; // expected-error{{in-class initializer for static data member is not a constant expression}} expected-warning {{division by zero}} + static const T value = 10 / Divisor; // expected-error{{in-class initializer for static data member is not a constant expression}} }; int array1[X::value == 5? 1 : -1];