diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 7 | ||||
-rw-r--r-- | include/clang/Sema/Initialization.h | 15 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 64 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp | 4 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp | 4 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.init/p6.cpp | 6 | ||||
-rw-r--r-- | test/CXX/drs/dr0xx.cpp | 2 | ||||
-rw-r--r-- | test/CXX/drs/dr4xx.cpp | 4 | ||||
-rw-r--r-- | test/FixIt/fixit.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/attr-selectany.cpp | 12 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/constexpr-value-init.cpp | 6 | ||||
-rw-r--r-- | test/SemaCXX/cxx0x-cursory-default-delete.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/cxx1y-variable-templates_in_class.cpp | 4 |
14 files changed, 97 insertions, 43 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4ac4c19a58..d4ec5cc277 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5470,8 +5470,11 @@ def err_address_space_qualified_delete : Error< def err_default_init_const : Error< "default initialization of an object of const type %0" "%select{| without a user-provided default constructor}1">; -def note_add_initializer : Note< - "add an explicit initializer to initialize %0">; +def ext_default_init_const : ExtWarn< + "default initialization of an object of const type %0" + "%select{| without a user-provided default constructor}1 " + "is a Microsoft extension">, + InGroup<Microsoft>; 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/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 6110d22bb9..74de00ff25 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -844,6 +844,21 @@ private: /// \brief The incomplete type that caused a failure. QualType FailedIncompleteType; + + /// \brief The fixit that needs to be applied to make this initialization + /// succeed. + std::string ZeroInitializationFixit; + SourceLocation ZeroInitializationFixitLoc; + +public: + /// \brief Call for initializations are invalid but that would be valid + /// zero initialzations if Fixit was applied. + void SetZeroInitializationFixit(const std::string& Fixit, SourceLocation L) { + ZeroInitializationFixit = Fixit; + ZeroInitializationFixitLoc = L; + } + +private: /// \brief Prints a follow-up note that highlights the location of /// the initialized entity, if it's remote. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 75ccc4ea76..3ee1a7f8ad 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -3101,6 +3101,28 @@ void InitializationSequence::SetOverloadFailure(FailureKind Failure, // Attempt initialization //===----------------------------------------------------------------------===// +/// Tries to add a zero initializer. Returns true if that worked. +static bool +maybeRecoverWithZeroInitialization(Sema &S, InitializationSequence &Sequence, + const InitializedEntity &Entity) { + if (Entity.getKind() != InitializedEntity::EK_Variable) + return false; + + VarDecl *VD = cast<VarDecl>(Entity.getDecl()); + if (VD->getInit() || VD->getLocEnd().isMacroID()) + return false; + + QualType VariableTy = VD->getType().getCanonicalType(); + SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd()); + std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc); + if (!Init.empty()) { + Sequence.AddZeroInitializationStep(Entity.getType()); + Sequence.SetZeroInitializationFixit(Init, Loc); + return true; + } + return false; +} + static void MaybeProduceObjCObject(Sema &S, InitializationSequence &Sequence, const InitializedEntity &Entity) { @@ -3339,7 +3361,8 @@ static void TryConstructorInitialization(Sema &S, if (Kind.getKind() == InitializationKind::IK_Default && Entity.getType().isConstQualified() && !cast<CXXConstructorDecl>(Best->Function)->isUserProvided()) { - Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); + if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity)) + Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); return; } @@ -4231,7 +4254,8 @@ static void TryDefaultInitialization(Sema &S, // a const-qualified type T, T shall be a class type with a user-provided // default constructor. if (DestType.isConstQualified() && S.getLangOpts().CPlusPlus) { - Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); + if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity)) + Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); return; } @@ -5749,6 +5773,21 @@ InitializationSequence::Perform(Sema &S, Diagnose(S, Entity, Kind, Args); return ExprError(); } + if (!ZeroInitializationFixit.empty()) { + unsigned DiagID = diag::err_default_init_const; + if (Decl *D = Entity.getDecl()) + if (S.getLangOpts().MSVCCompat && D->hasAttr<SelectAnyAttr>()) + DiagID = diag::ext_default_init_const; + + // The initialization would have succeeded with this fixit. Since the fixit + // is on the error, we need to build a valid AST in this case, so this isn't + // handled in the Failed() branch above. + QualType DestType = Entity.getType(); + S.Diag(Kind.getLocation(), DiagID) + << DestType << (bool)DestType->getAs<RecordType>() + << FixItHint::CreateInsertion(ZeroInitializationFixitLoc, + ZeroInitializationFixit); + } if (getKind() == DependentSequence) { // If the declaration is a non-dependent, incomplete array type @@ -6549,26 +6588,6 @@ 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<VarDecl>(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, @@ -6900,7 +6919,6 @@ bool InitializationSequence::Diagnose(Sema &S, } else { S.Diag(Kind.getLocation(), diag::err_default_init_const) << DestType << (bool)DestType->getAs<RecordType>(); - 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 5f102e7458..0aaedcc076 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'}} expected-note {{add an explicit initializer to initialize 'ni1'}} +constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}} 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' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'origin'}} +constexpr pixel origin; // expected-error {{default initialization of an object of const type 'const pixel' without a user-provided default constructor}} 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 81876192ca..5cf281c185 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' without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 's3d'}} +constexpr S3 s3d; // expected-error {{default initialization of an object of const type 'const S3' without a user-provided default constructor}} 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' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'b'}} + const B b; // expected-error {{default initialization of an object of const type 'const PR13492::B' without a user-provided default constructor}} } } diff --git a/test/CXX/dcl.decl/dcl.init/p6.cpp b/test/CXX/dcl.decl/dcl.init/p6.cpp index 76b7e7625d..e404a1ebc1 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' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'x1'}} + const NoUserDefault x1; // expected-error{{default initialization of an object of const type 'const NoUserDefault' without a user-provided default constructor}} const HasUserDefault x2; - const int x3; // expected-error{{default initialization of an object of const type 'const int'}} expected-note{{add an explicit initializer to initialize 'x3'}} + const int x3; // expected-error{{default initialization of an object of const type 'const int'}} } // 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' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'foo'}} +const struct s0 s1::foo; // expected-error{{default initialization of an object of const type 'const struct s0' without a user-provided default constructor}} template<typename T> struct s2 { diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp index 8a4334f875..6119f3d306 100644 --- a/test/CXX/drs/dr0xx.cpp +++ b/test/CXX/drs/dr0xx.cpp @@ -864,7 +864,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}} expected-note{{add an explicit initializer to initialize 'k'}} + const int k; // expected-error {{default initialization of an object of const}} } // dr79: na diff --git a/test/CXX/drs/dr4xx.cpp b/test/CXX/drs/dr4xx.cpp index 42c6774dd1..bbe5ee6faa 100644 --- a/test/CXX/drs/dr4xx.cpp +++ b/test/CXX/drs/dr4xx.cpp @@ -1202,9 +1202,9 @@ namespace dr497 { // dr497: yes struct S { mutable int i; }; - const S cs; // expected-error {{default initialization}} expected-note {{add an explicit initializer}} + const S cs; // expected-error {{default initialization}} int S::*pm = &S::i; - cs.*pm = 88; + cs.*pm = 88; // expected-error {{not assignable}} } void after() { diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp index 6c2fb7faf1..512713aa52 100644 --- a/test/FixIt/fixit.cpp +++ b/test/FixIt/fixit.cpp @@ -387,3 +387,11 @@ struct conversion_operator { // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:32}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:44-[[@LINE-2]]:44}:" conversion_operator::* const" }; + +struct const_zero_init { + int a; +}; +const const_zero_init czi; // expected-error {{default initialization of an object of const type 'const const_zero_init'}} +// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"{}" +int use_czi = czi.a; + diff --git a/test/SemaCXX/attr-selectany.cpp b/test/SemaCXX/attr-selectany.cpp index c27a915921..7d9cf7aea4 100644 --- a/test/SemaCXX/attr-selectany.cpp +++ b/test/SemaCXX/attr-selectany.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 %s // MSVC produces similar diagnostics. __declspec(selectany) void foo() { } // expected-error{{'selectany' can only be applied to data items with external linkage}} @@ -34,3 +34,13 @@ __declspec(selectany) X x(1); namespace { class Internal {}; } __declspec(selectany) auto x8 = Internal(); // expected-error {{'selectany' can only be applied to data items with external linkage}} + + +// The D3D11 headers do something like this. MSVC doesn't error on this at +// all, even without the __declspec(selectany), in violation of the standard. +// We fall back to a warning for selectany to accept headers. +struct SomeStruct {}; +extern const __declspec(selectany) SomeStruct some_struct; // expected-warning {{default initialization of an object of const type 'const SomeStruct' without a user-provided default constructor is a Microsoft extension}} + +// Without selectany, this should stay an error. +const SomeStruct some_struct2; // expected-error {{default initialization of an object of const type 'const SomeStruct' without a user-provided default constructor}} diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 9c62e9eb6d..3a1f6c6bd1 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1179,7 +1179,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}} expected-note{{add an explicit initializer to initialize 'k'}} + constexpr int k; // expected-error {{default initialization of an object of const type}} } } diff --git a/test/SemaCXX/constexpr-value-init.cpp b/test/SemaCXX/constexpr-value-init.cpp index 3657c18ddb..0651111335 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 {{without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'b1'}} +constexpr B b1; // expected-error {{without a user-provided default constructor}} 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 {{without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 'c1'}} +constexpr C c1; // expected-error {{without a user-provided default constructor}} constexpr C c2 = C(); // ok -constexpr D d1; // expected-error {{without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 'd1'}} +constexpr D d1; // expected-error {{without a user-provided default constructor}} 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 e333403af2..dfca17ad7c 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' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'cncc1'}} + 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}} 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 93a2095c9b..9ff73daa82 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<typename T, typename T0> static CONST T b = T(100); template<typename T> static CONST T b<T,int>; }; - template<typename T, typename T0> 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<int, char>'}} + template<typename T, typename T0> CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}} template<typename T> CONST T B4::a<T,int>; template CONST int B4::a<int,char>; // expected-note {{in instantiation of}} template CONST int B4::a<int,int>; template<typename T, typename T0> CONST T B4::b; - template<typename T> CONST T B4::b<T,int>; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'b<int, int>'}} + template<typename T> CONST T B4::b<T,int>; // expected-error {{default initialization of an object of const type 'const int'}} template CONST int B4::b<int,char>; template CONST int B4::b<int,int>; // expected-note {{in instantiation of}} } |