From 215f423ff22981327e56769150496a9000c2ba53 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 11 Feb 2015 02:41:33 +0000 Subject: [PATCH] Add a warning for direct-list-initialization of a variable with a deduced type (or of a lambda init-capture, which is sort-of such a variable). The semantics of such constructs will change when we implement N3922, so we intend to warn on this in Clang 3.6 then change the semantics in Clang 3.7. llvm-svn: 228792 --- clang/include/clang/Basic/DiagnosticGroups.td | 3 +++ clang/include/clang/Basic/DiagnosticParseKinds.td | 4 ++++ clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 ++++ clang/lib/Parse/ParseExprCXX.cpp | 11 ++++++++--- clang/lib/Sema/SemaDecl.cpp | 8 ++++++++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp | 4 ++-- clang/test/Parser/cxx0x-lambda-expressions.cpp | 2 +- clang/test/Parser/objcxx0x-lambda-expressions.mm | 2 +- clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp | 1 + 9 files changed, 32 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 75d40b1..215ff06 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -750,3 +750,6 @@ def SerializedDiagnostics : DiagGroup<"serialized-diagnostics">; // A warning group for warnings about code that clang accepts when // compiling CUDA C/C++ but which is not compatible with the CUDA spec. def CudaCompat : DiagGroup<"cuda-compat">; + +// A warning group for things that will change semantics in the future. +def FutureCompat : DiagGroup<"future-compat">; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 39d3c18..c8915a7 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -804,6 +804,10 @@ def warn_cxx98_compat_lambda : Warning< def err_lambda_missing_parens : Error< "lambda requires '()' before %select{'mutable'|return type|" "attribute specifier}0">; +def warn_init_capture_direct_list_init : Warning< + "direct list initialization of a lambda init-capture will change meaning in " + "a future version of Clang; insert an '=' to avoid a change in behavior">, + InGroup; // Availability attribute def err_expected_version : Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5c66952..f14d709 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1645,6 +1645,10 @@ def err_auto_var_init_multiple_expressions : Error< def err_auto_var_init_paren_braces : Error< "cannot deduce type for variable %0 with type %1 from " "parenthesized initializer list">; +def warn_auto_var_direct_list_init : Warning< + "direct list initialization of a variable with a deduced type will change " + "meaning in a future version of Clang; insert an '=' to avoid a change in " + "behavior">, InGroup; def err_auto_new_ctor_multiple_expressions : Error< "new expression for type %0 contains multiple constructor arguments">; def err_auto_missing_trailing_return : Error< diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 445967b..f21d5be 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -894,11 +894,16 @@ Optional Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, // to save the necessary state, and restore it later. EnterExpressionEvaluationContext EC(Actions, Sema::PotentiallyEvaluated); - TryConsumeToken(tok::equal); + bool HadEquals = TryConsumeToken(tok::equal); - if (!SkippedInits) + if (!SkippedInits) { + // Warn on constructs that will change meaning when we implement N3922 + if (!HadEquals && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_init_capture_direct_list_init) + << FixItHint::CreateInsertion(Tok.getLocation(), "="); + } Init = ParseInitializer(); - else if (Tok.is(tok::l_brace)) { + } else if (Tok.is(tok::l_brace)) { BalancedDelimiterTracker Braces(*this, tok::l_brace); Braces.consumeOpen(); Braces.skipToEnd(); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f187ee2..c058778 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8716,6 +8716,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, CheckVariableDeclarationType(VDecl); if (VDecl->isInvalidDecl()) return; + + // If all looks well, warn if this is a case that will change meaning when + // we implement N3922. + if (DirectInit && !CXXDirectInit && isa(Init)) { + Diag(Init->getLocStart(), + diag::warn_auto_var_direct_list_init) + << FixItHint::CreateInsertion(Init->getLocStart(), "="); + } } // dllimport cannot be used on variable definitions. diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp index 6be200d..1228c74 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp @@ -48,7 +48,7 @@ auto bad_init_2 = [a(1, 2)] {}; // expected-error {{initializer for lambda captu auto bad_init_3 = [&a(void_fn())] {}; // expected-error {{cannot form a reference to 'void'}} auto bad_init_4 = [a(void_fn())] {}; // expected-error {{has incomplete type 'void'}} auto bad_init_5 = [a(overload_fn)] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer of type ' void pack_1(T...t) { (void)[a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}} template void pack_1<>(); // expected-note {{instantiation of}} @@ -61,7 +61,7 @@ auto a = [a(4), b = 5, &c = static_cast(0)] { using T = decltype(c); using T = const int &; }; -auto b = [a{0}] {}; // expected-error {{include }} +auto b = [a{0}] {}; // expected-error {{include }} expected-warning {{will change meaning in a future version of Clang}} struct S { S(); S(S&&); }; template struct remove_reference { typedef T type; }; diff --git a/clang/test/Parser/cxx0x-lambda-expressions.cpp b/clang/test/Parser/cxx0x-lambda-expressions.cpp index 6f69d80..c2bf6fd 100644 --- a/clang/test/Parser/cxx0x-lambda-expressions.cpp +++ b/clang/test/Parser/cxx0x-lambda-expressions.cpp @@ -61,7 +61,7 @@ class C { int z; void init_capture() { [n(0)] () mutable -> int { return ++n; }; // expected-warning{{extension}} - [n{0}] { return; }; // expected-error {{}} expected-warning{{extension}} + [n{0}] { return; }; // expected-error {{}} expected-warning{{extension}} expected-warning{{will change meaning in a future version}} [n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}} expected-warning{{extension}} [n = {0}] { return; }; // expected-error {{}} expected-warning{{extension}} [a([&b = z]{})](){}; // expected-warning 2{{extension}} diff --git a/clang/test/Parser/objcxx0x-lambda-expressions.mm b/clang/test/Parser/objcxx0x-lambda-expressions.mm index bef576a..3954a80 100644 --- a/clang/test/Parser/objcxx0x-lambda-expressions.mm +++ b/clang/test/Parser/objcxx0x-lambda-expressions.mm @@ -21,7 +21,7 @@ class C { [foo(bar)] () {}; [foo = bar] () {}; - [foo{bar}] () {}; // expected-error {{}} + [foo{bar}] () {}; // expected-error {{}} expected-warning {{will change meaning}} [foo = {bar}] () {}; // expected-error {{}} [foo(bar) baz] () {}; // expected-error {{called object type 'int' is not a function}} diff --git a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index e7b5153..a78f022 100644 --- a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -117,6 +117,7 @@ void argument_deduction() { void auto_deduction() { auto l = {1, 2, 3, 4}; + auto l2 {1, 2, 3, 4}; // expected-warning {{will change meaning in a future version of Clang}} static_assert(same_type>::value, ""); auto bl = {1, 2.0}; // expected-error {{cannot deduce}} -- 2.7.4