From 2203f2c236decff724df42ceff926ef1effd6ca8 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 23 Jul 2014 05:16:10 +0000 Subject: [PATCH] Improve diagnostic on default-initializing const variables (PR20208). This tweaks the diagnostic wording slighly, and adds a fixit on a note. An alternative would be to add the fixit directly on the diagnostic, see the review thread linked to from the bug for a few notes on that approach. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@213725 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 4 +++- lib/Sema/SemaInit.cpp | 23 ++++++++++++++++++- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp | 4 ++-- .../dcl.fct.def/dcl.fct.def.default/p2.cpp | 4 ++-- test/CXX/dcl.decl/dcl.init/p6.cpp | 6 ++--- test/CXX/drs/dr0xx.cpp | 2 +- test/CXX/drs/dr4xx.cpp | 2 +- test/SemaCXX/constant-expression-cxx11.cpp | 2 +- test/SemaCXX/constexpr-value-init.cpp | 6 ++--- test/SemaCXX/cxx0x-cursory-default-delete.cpp | 2 +- .../cxx1y-variable-templates_in_class.cpp | 4 ++-- 11 files changed, 41 insertions(+), 18 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8e5fe2713b..f0975bdc51 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5203,7 +5203,9 @@ def err_address_space_qualified_delete : Error< def err_default_init_const : Error< "default initialization of an object of const type %0" - "%select{| requires a user-provided default constructor}1">; + "%select{| without a user-provided default constructor}1">; +def note_add_initializer : Note< + "add an explicit initializer to initialize %0">; def err_delete_operand : Error<"cannot delete expression of type %0">; def ext_delete_void_ptr_operand : ExtWarn< "cannot delete expression with pointer-to-'void' type %0">; diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3aa46ea1df..947be780e0 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -6455,6 +6455,26 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity, "Inconsistent init list check result."); } +/// Prints a fixit for adding a null initializer for |Entity|. Call this only +/// right after emitting a diagnostic. +static void maybeEmitZeroInitializationFixit(Sema &S, + InitializationSequence &Sequence, + const InitializedEntity &Entity) { + if (Entity.getKind() != InitializedEntity::EK_Variable) + return; + + VarDecl *VD = cast(Entity.getDecl()); + if (VD->getInit() || VD->getLocEnd().isMacroID()) + return; + + QualType VariableTy = VD->getType().getCanonicalType(); + SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd()); + std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc); + + S.Diag(Loc, diag::note_add_initializer) + << VD << FixItHint::CreateInsertion(Loc, Init); +} + bool InitializationSequence::Diagnose(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -6785,7 +6805,8 @@ bool InitializationSequence::Diagnose(Sema &S, << Entity.getName(); } else { S.Diag(Kind.getLocation(), diag::err_default_init_const) - << DestType << (bool)DestType->getAs(); + << DestType << (bool)DestType->getAs(); + maybeEmitZeroInitializationFixit(S, *this, Entity); } break; diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp index 2412a145f8..5f102e7458 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp @@ -17,7 +17,7 @@ extern int (*const d)(int); // A variable declaration which uses the constexpr specifier shall have an // initializer and shall be initialized by a constant expression. -constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}} +constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'ni1'}} constexpr struct C { C(); } ni2; // expected-error {{cannot have non-literal type 'const struct C'}} expected-note 3{{has no constexpr constructors}} constexpr double &ni3; // expected-error {{declaration of reference variable 'ni3' requires an initializer}} @@ -34,4 +34,4 @@ struct pixel { int x, y; }; constexpr pixel ur = { 1294, 1024 }; // ok -constexpr pixel origin; // expected-error {{default initialization of an object of const type 'const pixel' requires a user-provided default constructor}} +constexpr pixel origin; // expected-error {{default initialization of an object of const type 'const pixel' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'origin'}} diff --git a/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp index b9a1bc5288..81876192ca 100644 --- a/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp +++ b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp @@ -36,7 +36,7 @@ struct S3 { constexpr S3 s3a = S3(0); constexpr S3 s3b = s3a; constexpr S3 s3c = S3(); -constexpr S3 s3d; // expected-error {{default initialization of an object of const type 'const S3' requires a user-provided default constructor}} +constexpr S3 s3d; // expected-error {{default initialization of an object of const type 'const S3' without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 's3d'}} struct S4 { S4() = default; @@ -119,6 +119,6 @@ namespace PR13492 { }; void f() { - const B b; // expected-error {{default initialization of an object of const type 'const PR13492::B' requires a user-provided default constructor}} + const B b; // expected-error {{default initialization of an object of const type 'const PR13492::B' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'b'}} } } diff --git a/test/CXX/dcl.decl/dcl.init/p6.cpp b/test/CXX/dcl.decl/dcl.init/p6.cpp index 514fd0c9b6..76b7e7625d 100644 --- a/test/CXX/dcl.decl/dcl.init/p6.cpp +++ b/test/CXX/dcl.decl/dcl.init/p6.cpp @@ -10,15 +10,15 @@ struct NoUserDefault : public MakeNonPOD { }; struct HasUserDefault { HasUserDefault(); }; void test_const_default_init() { - const NoUserDefault x1; // expected-error{{default initialization of an object of const type 'const NoUserDefault' requires a user-provided default constructor}} + const NoUserDefault x1; // expected-error{{default initialization of an object of const type 'const NoUserDefault' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'x1'}} const HasUserDefault x2; - const int x3; // expected-error{{default initialization of an object of const type 'const int'}} + const int x3; // expected-error{{default initialization of an object of const type 'const int'}} expected-note{{add an explicit initializer to initialize 'x3'}} } // rdar://8501008 struct s0 {}; struct s1 { static const s0 foo; }; -const struct s0 s1::foo; // expected-error{{default initialization of an object of const type 'const struct s0' requires a user-provided default constructor}} +const struct s0 s1::foo; // expected-error{{default initialization of an object of const type 'const struct s0' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'foo'}} template struct s2 { diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp index 29e1720b1b..144b51d5ee 100644 --- a/test/CXX/drs/dr0xx.cpp +++ b/test/CXX/drs/dr0xx.cpp @@ -852,7 +852,7 @@ namespace dr77 { // dr77: yes namespace dr78 { // dr78: sup ???? // Under DR78, this is valid, because 'k' has static storage duration, so is // zero-initialized. - const int k; // expected-error {{default initialization of an object of const}} + const int k; // expected-error {{default initialization of an object of const}} expected-note{{add an explicit initializer to initialize 'k'}} } // dr79: na diff --git a/test/CXX/drs/dr4xx.cpp b/test/CXX/drs/dr4xx.cpp index 815dbfc0b4..bbb9ee46c1 100644 --- a/test/CXX/drs/dr4xx.cpp +++ b/test/CXX/drs/dr4xx.cpp @@ -1201,7 +1201,7 @@ namespace dr497 { // dr497: yes struct S { mutable int i; }; - const S cs; // expected-error {{default initialization}} + const S cs; // expected-error {{default initialization}} expected-note {{add an explicit initializer}} int S::*pm = &S::i; cs.*pm = 88; } diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 09d93fa73a..86c2c110f4 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1177,7 +1177,7 @@ namespace ExternConstexpr { void f() { extern constexpr int i; // expected-error {{constexpr variable declaration must be a definition}} constexpr int j = 0; - constexpr int k; // expected-error {{default initialization of an object of const type}} + constexpr int k; // expected-error {{default initialization of an object of const type}} expected-note{{add an explicit initializer to initialize 'k'}} } } diff --git a/test/SemaCXX/constexpr-value-init.cpp b/test/SemaCXX/constexpr-value-init.cpp index 9ad1129019..3657c18ddb 100644 --- a/test/SemaCXX/constexpr-value-init.cpp +++ b/test/SemaCXX/constexpr-value-init.cpp @@ -14,7 +14,7 @@ void f() { constexpr A a; // expected-error {{constant expression}} expected-note {{in call to 'A()'}} } -constexpr B b1; // expected-error {{requires a user-provided default constructor}} +constexpr B b1; // expected-error {{without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'b1'}} constexpr B b2 = B(); // ok static_assert(b2.a.a == 1, ""); static_assert(b2.a.b == 2, ""); @@ -23,9 +23,9 @@ struct C { int c; }; struct D : C { int d; }; -constexpr C c1; // expected-error {{requires a user-provided default constructor}} +constexpr C c1; // expected-error {{without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 'c1'}} constexpr C c2 = C(); // ok -constexpr D d1; // expected-error {{requires a user-provided default constructor}} +constexpr D d1; // expected-error {{without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 'd1'}} constexpr D d2 = D(); // ok with DR1452 static_assert(D().c == 0, ""); static_assert(D().d == 0, ""); diff --git a/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/test/SemaCXX/cxx0x-cursory-default-delete.cpp index 07a7842266..375cf4a1ac 100644 --- a/test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ b/test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -25,7 +25,7 @@ void fn1 () { non_const_copy ncc2 = ncc; ncc = ncc2; const non_const_copy cncc{}; - const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' requires a user-provided default constructor}} + const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'cncc1'}} non_const_copy ncc3 = cncc; // expected-error {{no matching}} ncc = cncc; // expected-error {{no viable overloaded}} }; diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp index 1e5e834b6d..f6f77f0100 100644 --- a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -58,13 +58,13 @@ namespace out_of_line { template static CONST T b = T(100); template static CONST T b; }; - template CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}} + template CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'a'}} template CONST T B4::a; template CONST int B4::a; // expected-note {{in instantiation of}} template CONST int B4::a; template CONST T B4::b; - template CONST T B4::b; // expected-error {{default initialization of an object of const type 'const int'}} + template CONST T B4::b; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'b'}} template CONST int B4::b; template CONST int B4::b; // expected-note {{in instantiation of}} } -- 2.40.0