diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 1860b948d609..a9db65a51518 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -534,15 +534,10 @@ void CXXRecordDecl::addedMember(Decl *D) { SMKind |= SMF_MoveConstructor; } - // C++ [dcl.init.aggr]p1: - // An aggregate is an array or a class with no user-declared - // constructors [...]. // C++11 [dcl.init.aggr]p1: DR1518 - // An aggregate is an array or a class with no user-provided, explicit, or - // inherited constructors - if (getASTContext().getLangOpts().CPlusPlus11 - ? (Constructor->isUserProvided() || Constructor->isExplicit()) - : !Constructor->isImplicit()) + // An aggregate is an array or a class with no user-provided, explicit, or + // inherited constructors + if (Constructor->isUserProvided() || Constructor->isExplicit()) data().Aggregate = false; } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 515a6676d400..5bb5518c58b9 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4539,23 +4539,21 @@ static void TryValueInitialization(Sema &S, if (const RecordType *RT = T->getAs()) { if (CXXRecordDecl *ClassDecl = dyn_cast(RT->getDecl())) { bool NeedZeroInitialization = true; - if (!S.getLangOpts().CPlusPlus11) { - // C++98: - // -- if T is a class type (clause 9) with a user-declared constructor - // (12.1), then the default constructor for T is called (and the - // initialization is ill-formed if T has no accessible default - // constructor); - if (ClassDecl->hasUserDeclaredConstructor()) - NeedZeroInitialization = false; - } else { - // C++11: - // -- if T is a class type (clause 9) with either no default constructor - // (12.1 [class.ctor]) or a default constructor that is user-provided - // or deleted, then the object is default-initialized; - CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl); - if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted()) - NeedZeroInitialization = false; - } + // C++98: + // -- if T is a class type (clause 9) with a user-declared constructor + // (12.1), then the default constructor for T is called (and the + // initialization is ill-formed if T has no accessible default + // constructor); + // C++11: + // -- if T is a class type (clause 9) with either no default constructor + // (12.1 [class.ctor]) or a default constructor that is user-provided + // or deleted, then the object is default-initialized; + // + // Note that the C++11 rule is the same as the C++98 rule if there are no + // defaulted or deleted constructors, so we just use it unconditionally. + CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl); + if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted()) + NeedZeroInitialization = false; // -- if T is a (possibly cv-qualified) non-union class type without a // user-provided or deleted default constructor, then the object is diff --git a/clang/test/CodeGenCXX/global-init.cpp b/clang/test/CodeGenCXX/global-init.cpp index e806af9eacb4..8144a97ce8bf 100644 --- a/clang/test/CodeGenCXX/global-init.cpp +++ b/clang/test/CodeGenCXX/global-init.cpp @@ -170,6 +170,8 @@ namespace test7 { const B &b2 = B(); const int b3 = B().n; + // CHECK-NOT: @_ZN5test7L2c1E + // CHECK: call void @llvm.memset{{.*}} @_ZN5test7L2c1E // CHECK-NOT: @_ZN5test7L2c1E // CHECK: @_ZN5test7L2c2E // CHECK-NOT: @_ZN5test7L2c3E diff --git a/clang/test/CodeGenCXX/value-init.cpp b/clang/test/CodeGenCXX/value-init.cpp index 735dc6163990..fc4e0d3a55e0 100644 --- a/clang/test/CodeGenCXX/value-init.cpp +++ b/clang/test/CodeGenCXX/value-init.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s struct A { virtual ~A(); @@ -315,6 +315,14 @@ namespace PR20256 { // CHECK: } } +// CHECK-LABEL: define {{.*}}@_Z20explicitly_defaultedv +int explicitly_defaulted() { + struct A { A() = default; int n; }; + // CHECK: call void @llvm.memset + A a = A(); + return a.n; +} // CHECK-LABEL: } + // CHECK-LABEL: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr // CHECK: call void @llvm.memset.p0i8.i64 // CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev diff --git a/clang/test/SemaCXX/aggregate-init-cxx98.cpp b/clang/test/SemaCXX/aggregate-init-cxx98.cpp new file mode 100644 index 000000000000..332801f0822c --- /dev/null +++ b/clang/test/SemaCXX/aggregate-init-cxx98.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -std=c++98 -verify %s + +struct A { + A() = default; // expected-warning {{C++11}} + int n; +}; +A a = {0}; diff --git a/clang/test/SemaCXX/aggregate-initialization.cpp b/clang/test/SemaCXX/aggregate-initialization.cpp index b41696346639..7b6abd22acc7 100644 --- a/clang/test/SemaCXX/aggregate-initialization.cpp +++ b/clang/test/SemaCXX/aggregate-initialization.cpp @@ -4,8 +4,6 @@ // Verify that using an initializer list for a non-aggregate looks for // constructors.. -// Note that due to a (likely) standard bug, this is technically an aggregate, -// but we do not treat it as one. struct NonAggr1 { // expected-note 2 {{candidate constructor}} NonAggr1(int, int) { } // expected-note {{candidate constructor}}