Fix defaulted-functions-in-C++98 extension to give the functions the same

effect they would have in C++11. In particular, they do not prevent
value-initialization from performing zero-initialization, nor do they prevent a
struct from being an aggregate.

llvm-svn: 290229
This commit is contained in:
Richard Smith 2016-12-21 01:57:02 +00:00
parent 7779484313
commit 505ef81422
6 changed files with 36 additions and 28 deletions

View File

@ -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;
}

View File

@ -4539,23 +4539,21 @@ static void TryValueInitialization(Sema &S,
if (const RecordType *RT = T->getAs<RecordType>()) {
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(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

View File

@ -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

View File

@ -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

View File

@ -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};

View File

@ -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}}