diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-07-05 08:39:21 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-07-05 08:39:21 +0000 |
commit | f4bb8d06c4f1665f89a9e9ddd61f2a2d26904da0 (patch) | |
tree | d0ff432696864702c52b6353671386a07ffc4b10 /lib/Sema/SemaInit.cpp | |
parent | e07c5f897e8da88959c93a9d98f1b441da649eb6 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159733 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaInit.cpp')
-rw-r--r-- | lib/Sema/SemaInit.cpp | 211 |
1 files changed, 102 insertions, 109 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3c32dbb10b..903c0c4b18 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2708,84 +2708,39 @@ static void MaybeProduceObjCObject(Sema &S, } } -/// \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 @@ static void TryConstructorInitialization(Sema &S, 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 @@ static void TryConstructorInitialization(Sema &S, // 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 @@ static void TryConstructorInitialization(Sema &S, // 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 @@ static void TryConstructorInitialization(Sema &S, 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 @@ static void TryReferenceInitializationCore(Sema &S, 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 @@ static void TryListInitialization(Sema &S, 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 TryStringLiteralInitialization(Sema &S, 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 @@ static void TryValueInitialization(Sema &S, 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 @@ static void TryValueInitialization(Sema &S, // 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 @@ static void TryValueInitialization(Sema &S, // 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 @@ InitializationSequence::InitializationSequence(Sema &S, 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 @@ InitializationSequence::Perform(Sema &S, 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 @@ InitializationSequence::Perform(Sema &S, } case SK_ConstructorInitialization: + case SK_ListConstructorCall: case SK_ZeroInitialization: break; } @@ -5211,7 +5202,8 @@ InitializationSequence::Perform(Sema &S, 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 @@ InitializationSequence::Perform(Sema &S, 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; |