[cfe-commits] r159733 - in /cfe/trunk: lib/Sema/SemaInit.cpp test/CodeGenCXX/const-init-cxx11.cpp test/CodeGenCXX/constructor-init.cpp test/SemaCXX/constant-expression-cxx11.cpp test/SemaCXX/cxx0x-initializer-constructor.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Thu Jul 5 01:39:21 PDT 2012
Author: rsmith
Date: Thu Jul 5 03:39:21 2012
New Revision: 159733
URL: http://llvm.org/viewvc/llvm-project?rev=159733&view=rev
Log:
PR13273: When performing list-initialization with an empty initializer list,
actually perform value initialization rather than trying to fake it with a call
to the default constructor. Fixes various bugs related to the previously-missing
zero-initialization in this case.
I've also moved this and the other list initialization 'special case' from
TryConstructorInitialization into TryListInitialization where they belong.
Modified:
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp
cfe/trunk/test/CodeGenCXX/constructor-init.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=159733&r1=159732&r2=159733&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Jul 5 03:39:21 2012
@@ -2708,84 +2708,39 @@
}
}
-/// \brief When initializing from init list via constructor, deal with the
-/// empty init list and std::initializer_list special cases.
+/// \brief When initializing from init list via constructor, handle
+/// initialization of an object of type std::initializer_list<T>.
///
-/// \return True if this was a special case, false otherwise.
-static bool TryListConstructionSpecialCases(Sema &S,
- InitListExpr *List,
- CXXRecordDecl *DestRecordDecl,
- QualType DestType,
- InitializationSequence &Sequence) {
- // C++11 [dcl.init.list]p3:
- // List-initialization of an object or reference of type T is defined as
- // follows:
- // - If T is an aggregate, aggregate initialization is performed.
- if (DestType->isAggregateType())
+/// \return true if we have handled initialization of an object of type
+/// std::initializer_list<T>, false otherwise.
+static bool TryInitializerListConstruction(Sema &S,
+ InitListExpr *List,
+ QualType DestType,
+ InitializationSequence &Sequence) {
+ QualType E;
+ if (!S.isStdInitializerList(DestType, &E))
return false;
- // - Otherwise, if the initializer list has no elements and T is a class
- // type with a default constructor, the object is value-initialized.
- if (List->getNumInits() == 0) {
- if (CXXConstructorDecl *DefaultConstructor =
- S.LookupDefaultConstructor(DestRecordDecl)) {
- if (DefaultConstructor->isDeleted() ||
- S.isFunctionConsideredUnavailable(DefaultConstructor)) {
- // Fake an overload resolution failure.
- OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
- DeclAccessPair FoundDecl = DeclAccessPair::make(DefaultConstructor,
- DefaultConstructor->getAccess());
- if (FunctionTemplateDecl *ConstructorTmpl =
- dyn_cast<FunctionTemplateDecl>(DefaultConstructor))
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
- ArrayRef<Expr*>(), CandidateSet,
- /*SuppressUserConversions*/ false);
- else
- S.AddOverloadCandidate(DefaultConstructor, FoundDecl,
- ArrayRef<Expr*>(), CandidateSet,
- /*SuppressUserConversions*/ false);
- Sequence.SetOverloadFailure(
- InitializationSequence::FK_ListConstructorOverloadFailed,
- OR_Deleted);
- } else
- Sequence.AddConstructorInitializationStep(DefaultConstructor,
- DefaultConstructor->getAccess(),
- DestType,
- /*MultipleCandidates=*/false,
- /*FromInitList=*/true,
- /*AsInitList=*/false);
+ // Check that each individual element can be copy-constructed. But since we
+ // have no place to store further information, we'll recalculate everything
+ // later.
+ InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
+ S.Context.getConstantArrayType(E,
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ List->getNumInits()),
+ ArrayType::Normal, 0));
+ InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
+ 0, HiddenArray);
+ for (unsigned i = 0, n = List->getNumInits(); i < n; ++i) {
+ Element.setElementIndex(i);
+ if (!S.CanPerformCopyInitialization(Element, List->getInit(i))) {
+ Sequence.SetFailed(
+ InitializationSequence::FK_InitListElementCopyFailure);
return true;
}
}
-
- // - Otherwise, if T is a specialization of std::initializer_list, [...]
- QualType E;
- if (S.isStdInitializerList(DestType, &E)) {
- // Check that each individual element can be copy-constructed. But since we
- // have no place to store further information, we'll recalculate everything
- // later.
- InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
- S.Context.getConstantArrayType(E,
- llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
- List->getNumInits()),
- ArrayType::Normal, 0));
- InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
- 0, HiddenArray);
- for (unsigned i = 0, n = List->getNumInits(); i < n; ++i) {
- Element.setElementIndex(i);
- if (!S.CanPerformCopyInitialization(Element, List->getInit(i))) {
- Sequence.SetFailed(
- InitializationSequence::FK_InitListElementCopyFailure);
- return true;
- }
- }
- Sequence.AddStdInitializerListConstructionStep(DestType);
- return true;
- }
-
- // Not a special case.
- return false;
+ Sequence.AddStdInitializerListConstructionStep(DestType);
+ return true;
}
static OverloadingResult
@@ -2886,11 +2841,6 @@
CXXRecordDecl *DestRecordDecl
= cast<CXXRecordDecl>(DestRecordType->getDecl());
- if (InitListSyntax &&
- TryListConstructionSpecialCases(S, cast<InitListExpr>(Args[0]),
- DestRecordDecl, DestType, Sequence))
- return;
-
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
@@ -2917,15 +2867,21 @@
// constructors of the class T and the argument list consists of the
// initializer list as a single argument.
if (InitListSyntax) {
+ InitListExpr *ILE = cast<InitListExpr>(Args[0]);
AsInitializerList = true;
- Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs,
- CandidateSet, ConStart, ConEnd, Best,
- CopyInitialization, AllowExplicit,
- /*OnlyListConstructor=*/true,
- InitListSyntax);
+
+ // If the initializer list has no elements and T has a default constructor,
+ // the first phase is omitted.
+ if (ILE->getNumInits() != 0 ||
+ (!DestRecordDecl->hasDeclaredDefaultConstructor() &&
+ !DestRecordDecl->needsImplicitDefaultConstructor()))
+ Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs,
+ CandidateSet, ConStart, ConEnd, Best,
+ CopyInitialization, AllowExplicit,
+ /*OnlyListConstructor=*/true,
+ InitListSyntax);
// Time to unwrap the init list.
- InitListExpr *ILE = cast<InitListExpr>(Args[0]);
Args = ILE->getInits();
NumArgs = ILE->getNumInits();
}
@@ -2933,7 +2889,7 @@
// C++11 [over.match.list]p1:
// - If no viable initializer-list constructor is found, overload resolution
// is performed again, where the candidate functions are all the
- // constructors of the class T nad the argument list consists of the
+ // constructors of the class T and the argument list consists of the
// elements of the initializer list.
if (Result == OR_No_Viable_Function) {
AsInitializerList = false;
@@ -2951,7 +2907,7 @@
return;
}
- // C++0x [dcl.init]p6:
+ // C++11 [dcl.init]p6:
// If a program calls for the default initialization of an object
// of a const-qualified type T, T shall be a class type with a
// user-provided default constructor.
@@ -3018,6 +2974,12 @@
Qualifiers T2Quals,
InitializationSequence &Sequence);
+static void TryValueInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ InitializationSequence &Sequence,
+ InitListExpr *InitList = 0);
+
static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -3113,14 +3075,31 @@
return;
}
+ // C++11 [dcl.init.list]p3:
+ // - If T is an aggregate, aggregate initialization is performed.
if (!DestType->isAggregateType()) {
if (S.getLangOpts().CPlusPlus0x) {
+ // - Otherwise, if the initializer list has no elements and T is a
+ // class type with a default constructor, the object is
+ // value-initialized.
+ if (InitList->getNumInits() == 0) {
+ CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
+ if (RD->hasDeclaredDefaultConstructor() ||
+ RD->needsImplicitDefaultConstructor()) {
+ TryValueInitialization(S, Entity, Kind, Sequence, InitList);
+ return;
+ }
+ }
+
+ // - Otherwise, if T is a specialization of std::initializer_list<E>,
+ // an initializer_list object constructed [...]
+ if (TryInitializerListConstruction(S, InitList, DestType, Sequence))
+ return;
+
+ // - Otherwise, if T is a class type, constructors are considered.
Expr *Arg = InitList;
- // A direct-initializer is not list-syntax, i.e. there's no special
- // treatment of "A a({1, 2});".
- TryConstructorInitialization(S, Entity, Kind, &Arg, 1, DestType,
- Sequence,
- Kind.getKind() != InitializationKind::IK_Direct);
+ TryConstructorInitialization(S, Entity, Kind, &Arg, 1, DestType,
+ Sequence, /*InitListSyntax*/true);
} else
Sequence.SetFailed(
InitializationSequence::FK_InitListBadDestinationType);
@@ -3605,7 +3584,11 @@
static void TryValueInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
- InitializationSequence &Sequence) {
+ InitializationSequence &Sequence,
+ InitListExpr *InitList) {
+ assert((!InitList || InitList->getNumInits() == 0) &&
+ "Shouldn't use value-init for non-empty init lists");
+
// C++98 [dcl.init]p5, C++11 [dcl.init]p7:
//
// To value-initialize an object of type T means:
@@ -3616,17 +3599,15 @@
if (const RecordType *RT = T->getAs<RecordType>()) {
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // 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);
+ bool NeedZeroInitialization = true;
if (!S.getLangOpts().CPlusPlus0x) {
+ // 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())
- // FIXME: we really want to refer to a single subobject of the array,
- // but Entity doesn't have a way to capture that (yet).
- return TryConstructorInitialization(S, Entity, Kind, 0, 0,
- T, Sequence);
+ NeedZeroInitialization = false;
} else {
// C++11:
// -- if T is a class type (clause 9) with either no default constructor
@@ -3634,8 +3615,7 @@
// or deleted, then the object is default-initialized;
CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl);
if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted())
- return TryConstructorInitialization(S, Entity, Kind, 0, 0,
- T, Sequence);
+ NeedZeroInitialization = false;
}
// -- if T is a (possibly cv-qualified) non-union class type without a
@@ -3644,8 +3624,19 @@
// default-initialized;
// FIXME: The 'non-union' here is a defect (not yet assigned an issue
// number). Update the quotation when the defect is resolved.
- Sequence.AddZeroInitializationStep(Entity.getType());
- return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
+ if (NeedZeroInitialization)
+ Sequence.AddZeroInitializationStep(Entity.getType());
+
+ // If this is list-value-initialization, pass the empty init list on when
+ // building the constructor call. This affects the semantics of a few
+ // things (such as whether an explicit default constructor can be called).
+ Expr *InitListAsExpr = InitList;
+ Expr **Args = InitList ? &InitListAsExpr : 0;
+ unsigned NumArgs = InitList ? 1 : 0;
+ bool InitListSyntax = InitList;
+
+ return TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, T,
+ Sequence, InitListSyntax);
}
}
@@ -4100,8 +4091,8 @@
AddArrayInitStep(DestType);
}
}
- // Note: as a GNU C++ extension, we allow initialization of a
- // class member from a parenthesized initializer list.
+ // Note: as a GNU C++ extension, we allow list-initialization of a
+ // class member of array type from a parenthesized initializer list.
else if (S.getLangOpts().CPlusPlus &&
Entity.getKind() == InitializedEntity::EK_Member &&
Initializer && isa<InitListExpr>(Initializer)) {
@@ -4901,7 +4892,6 @@
case SK_QualificationConversionXValue:
case SK_QualificationConversionRValue:
case SK_ConversionSequence:
- case SK_ListConstructorCall:
case SK_ListInitialization:
case SK_UnwrapInitList:
case SK_RewrapInitList:
@@ -4921,6 +4911,7 @@
}
case SK_ConstructorInitialization:
+ case SK_ListConstructorCall:
case SK_ZeroInitialization:
break;
}
@@ -5211,7 +5202,8 @@
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(
Entity.getType().getNonReferenceType());
bool UseTemporary = Entity.getType()->isReferenceType();
- InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
+ assert(Args.size() == 1 && "expected a single argument for list init");
+ InitListExpr *InitList = cast<InitListExpr>(Args.get()[0]);
S.Diag(InitList->getExprLoc(), diag::warn_cxx98_compat_ctor_list_init)
<< InitList->getSourceRange();
MultiExprArg Arg(InitList->getInits(), InitList->getNumInits());
@@ -5259,7 +5251,8 @@
step_iterator NextStep = Step;
++NextStep;
if (NextStep != StepEnd &&
- NextStep->Kind == SK_ConstructorInitialization) {
+ (NextStep->Kind == SK_ConstructorInitialization ||
+ NextStep->Kind == SK_ListConstructorCall)) {
// The need for zero-initialization is recorded directly into
// the call to the object's constructor within the next step.
ConstructorInitRequiresZeroInit = true;
Modified: cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp?rev=159733&r1=159732&r2=159733&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp Thu Jul 5 03:39:21 2012
@@ -309,6 +309,20 @@
static nsMemoryImpl sGlobalMemory;
}
+namespace PR13273 {
+ struct U {
+ int t;
+ U() = default;
+ };
+
+ struct S : U {
+ S() = default;
+ };
+
+ // CHECK: @_ZN7PR13273L1sE = {{.*}} zeroinitializer
+ const S s {};
+}
+
// Constant initialization tests go before this point,
// dynamic initialization tests go after.
Modified: cfe/trunk/test/CodeGenCXX/constructor-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/constructor-init.cpp?rev=159733&r1=159732&r2=159733&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/constructor-init.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/constructor-init.cpp Thu Jul 5 03:39:21 2012
@@ -131,6 +131,26 @@
}
}
+// Check that we emit a zero initialization step for list-value-initialization
+// which calls a trivial default constructor.
+namespace PR13273 {
+ struct U {
+ int t;
+ U() = default;
+ };
+
+ struct S : U {
+ S() = default;
+ };
+
+ // CHECK: define {{.*}}@_ZN7PR132731fEv(
+ int f() {
+ // CHECK-NOT: }
+ // CHECK: llvm.memset{{.*}}i8 0
+ return (new S{})->t;
+ }
+}
+
template<typename T>
struct X {
X(const X &);
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=159733&r1=159732&r2=159733&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Thu Jul 5 03:39:21 2012
@@ -1302,3 +1302,19 @@
constexpr Foo id(Foo x) { return x; }
constexpr Foo res(id(Foo()));
}
+
+namespace PR13273 {
+ struct U {
+ int t;
+ U() = default;
+ };
+
+ struct S : U {
+ S() = default;
+ };
+
+ // S's default constructor isn't constexpr, because U's default constructor
+ // doesn't initialize 't', but it's trivial, so value-initialization doesn't
+ // actually call it.
+ static_assert(S{}.t == 0, "");
+}
Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp?rev=159733&r1=159732&r2=159733&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp Thu Jul 5 03:39:21 2012
@@ -279,5 +279,28 @@
{
c->foo({ nullptr, 1 }); // expected-error{{initialization of incomplete type 'const PR12498::ArrayRef'}}
}
+}
+
+namespace explicit_default {
+ struct A {
+ explicit A(); // expected-note{{here}}
+ };
+ A a {}; // ok
+ // This is copy-list-initialization, and we choose an explicit constructor
+ // (even though we do so via value-initialization), so the initialization is
+ // ill-formed.
+ A b = {}; // expected-error{{chosen constructor is explicit}}
+}
+
+namespace init_list_default {
+ struct A {
+ A(std::initializer_list<int>);
+ };
+ A a {}; // calls initializer list constructor
+ struct B {
+ B();
+ B(std::initializer_list<int>) = delete;
+ };
+ B b {}; // calls default constructor
}
More information about the cfe-commits
mailing list