From 4337dc776074ac0143b49823890303f952d3d9ae Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 21 May 2011 17:52:48 +0000 Subject: [PATCH] Teach Sema::ActOnUninitializedDecl() not to try to interpret when one should use a constructor to default-initialize a variable. InitializationSequence knows the rules for default initialization, better. Fixes . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131796 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDecl.cpp | 88 +++++++++---------- .../basic.lookup/basic.lookup.argdep/p4.cpp | 3 + test/CXX/dcl.decl/dcl.init/p6.cpp | 12 +++ 3 files changed, 58 insertions(+), 45 deletions(-) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2501e7f4d4..a5a494877f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5616,55 +5616,53 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, return; } - const RecordType *Record - = Context.getBaseElementType(Type)->getAs(); - if (Record && getLangOptions().CPlusPlus && !getLangOptions().CPlusPlus0x && - cast(Record->getDecl())->isPOD()) { - // C++03 [dcl.init]p9: - // If no initializer is specified for an object, and the - // object is of (possibly cv-qualified) non-POD class type (or - // array thereof), the object shall be default-initialized; if - // the object is of const-qualified type, the underlying class - // type shall have a user-declared default - // constructor. Otherwise, if no initializer is specified for - // a non- static object, the object and its subobjects, if - // any, have an indeterminate initial value); if the object - // or any of its subobjects are of const-qualified type, the - // program is ill-formed. - // C++0x [dcl.init]p11: - // If no initializer is specified for an object, the object is - // default-initialized; [...]. - } else { - // Check for jumps past the implicit initializer. C++0x - // clarifies that this applies to a "variable with automatic - // storage duration", not a "local variable". - // C++0x [stmt.dcl]p3 - // A program that jumps from a point where a variable with automatic - // storage duration is not ins cope to a point where it is in scope is - // ill-formed unless the variable has scalar type, class type with a - // trivial defautl constructor and a trivial destructor, a cv-qualified - // version of one of these types, or an array of one of the preceding - // types and is declared without an initializer. - if (getLangOptions().CPlusPlus && Var->hasLocalStorage() && Record) { + // Check for jumps past the implicit initializer. C++0x + // clarifies that this applies to a "variable with automatic + // storage duration", not a "local variable". + // C++0x [stmt.dcl]p3 + // A program that jumps from a point where a variable with automatic + // storage duration is not in scope to a point where it is in scope is + // ill-formed unless the variable has scalar type, class type with a + // trivial default constructor and a trivial destructor, a cv-qualified + // version of one of these types, or an array of one of the preceding + // types and is declared without an initializer. + if (getLangOptions().CPlusPlus && Var->hasLocalStorage()) { + if (const RecordType *Record + = Context.getBaseElementType(Type)->getAs()) { CXXRecordDecl *CXXRecord = cast(Record->getDecl()); - if (!getLangOptions().CPlusPlus0x || - !CXXRecord->hasTrivialDefaultConstructor() || - !CXXRecord->hasTrivialDestructor()) + if ((!getLangOptions().CPlusPlus0x && !CXXRecord->isPOD()) || + (getLangOptions().CPlusPlus0x && + (!CXXRecord->hasTrivialDefaultConstructor() || + (!CXXRecord->hasTrivialDestructor())))) getCurFunction()->setHasBranchProtectedScope(); } - - InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); - InitializationKind Kind - = InitializationKind::CreateDefault(Var->getLocation()); - - InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); - ExprResult Init = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, 0, 0)); - if (Init.isInvalid()) - Var->setInvalidDecl(); - else if (Init.get()) - Var->setInit(MaybeCreateExprWithCleanups(Init.get())); } + + // C++03 [dcl.init]p9: + // If no initializer is specified for an object, and the + // object is of (possibly cv-qualified) non-POD class type (or + // array thereof), the object shall be default-initialized; if + // the object is of const-qualified type, the underlying class + // type shall have a user-declared default + // constructor. Otherwise, if no initializer is specified for + // a non- static object, the object and its subobjects, if + // any, have an indeterminate initial value); if the object + // or any of its subobjects are of const-qualified type, the + // program is ill-formed. + // C++0x [dcl.init]p11: + // If no initializer is specified for an object, the object is + // default-initialized; [...]. + InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); + InitializationKind Kind + = InitializationKind::CreateDefault(Var->getLocation()); + + InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, 0, 0)); + if (Init.isInvalid()) + Var->setInvalidDecl(); + else if (Init.get()) + Var->setInit(MaybeCreateExprWithCleanups(Init.get())); CheckCompleteVariableDeclaration(Var); } diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp index 1e5a823663..ccadf416c9 100644 --- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp +++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp @@ -45,6 +45,9 @@ namespace Test { namespace test1 { template class A { template friend void foo(A &, U); // expected-note {{not viable: 1st argument ('const A') would lose const qualifier}} + + public: + A(); }; void test() { diff --git a/test/CXX/dcl.decl/dcl.init/p6.cpp b/test/CXX/dcl.decl/dcl.init/p6.cpp index da6f5b5369..514fd0c9b6 100644 --- a/test/CXX/dcl.decl/dcl.init/p6.cpp +++ b/test/CXX/dcl.decl/dcl.init/p6.cpp @@ -14,3 +14,15 @@ void test_const_default_init() { const HasUserDefault x2; 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' requires a user-provided default constructor}} + +template +struct s2 { + static const s0 foo; +}; + +template<> const struct s0 s2::foo; // okay -- 2.40.0