diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2011-11-27 16:50:07 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2011-11-27 16:50:07 +0000 |
commit | 13dc8f98f6108dca8aaa9721567ed5a2d9911e0f (patch) | |
tree | c574193fb93fa87e8b2d568d1bf5cda53baa4b8a /lib/Sema/SemaInit.cpp | |
parent | 1376ba9dddccc02e8c187bbfa4c66f2c0938b0c0 (diff) |
Reference initialization with initializer lists.
This supports single-element initializer lists for references according to DR1288, as well as creating temporaries and binding to them for other initializer lists.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145186 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaInit.cpp')
-rw-r--r-- | lib/Sema/SemaInit.cpp | 235 |
1 files changed, 211 insertions, 24 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 9480f63712..a95a257131 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -989,8 +989,7 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, } Expr *expr = IList->getInit(Index); - if (isa<InitListExpr>(expr)) { - // FIXME: Allowed in C++11. + if (isa<InitListExpr>(expr) && !SemaRef.getLangOptions().CPlusPlus0x) { if (!VerifyOnly) SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) << DeclType << IList->getSourceRange(); @@ -2385,6 +2384,8 @@ void InitializationSequence::Step::Destroy() { case SK_QualificationConversionLValue: case SK_ListInitialization: case SK_ListConstructorCall: + case SK_UnwrapInitList: + case SK_RewrapInitList: case SK_ConstructorInitialization: case SK_ZeroInitialization: case SK_CAssignment: @@ -2761,6 +2762,21 @@ void InitializationSequence::AddProduceObjCObjectStep(QualType T) { Steps.push_back(S); } +void InitializationSequence::RewrapReferenceInitList(QualType T, + InitListExpr *Syntactic) { + assert(Syntactic->getNumInits() == 1 && + "Can only rewrap trivial init lists."); + Step S; + S.Kind = SK_UnwrapInitList; + S.Type = Syntactic->getInit(0)->getType(); + Steps.insert(Steps.begin(), S); + + S.Kind = SK_RewrapInitList; + S.Type = T; + S.WrappingSyntacticList = Syntactic; + Steps.push_back(S); +} + void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { setSequenceKind(FailedSequence); @@ -2799,6 +2815,114 @@ static void MaybeProduceObjCObject(Sema &S, } } +static bool +ResolveOverloadedFunctionForReferenceBinding(Sema &S, + Expr *Initializer, + QualType &SourceType, + QualType &UnqualifiedSourceType, + QualType UnqualifiedTargetType, + InitializationSequence &Sequence) { + if (S.Context.getCanonicalType(UnqualifiedSourceType) == + S.Context.OverloadTy) { + DeclAccessPair Found; + bool HadMultipleCandidates = false; + if (FunctionDecl *Fn + = S.ResolveAddressOfOverloadedFunction(Initializer, + UnqualifiedTargetType, + false, Found, + &HadMultipleCandidates)) { + Sequence.AddAddressOverloadResolutionStep(Fn, Found, + HadMultipleCandidates); + SourceType = Fn->getType(); + UnqualifiedSourceType = SourceType.getUnqualifiedType(); + } else if (!UnqualifiedTargetType->isRecordType()) { + Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); + return true; + } + } + return false; +} + +static void TryReferenceInitializationCore(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + QualType cv1T1, QualType T1, + Qualifiers T1Quals, + QualType cv2T2, QualType T2, + Qualifiers T2Quals, + InitializationSequence &Sequence); + +static void TryListInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitListExpr *InitList, + InitializationSequence &Sequence); + +/// \brief Attempt list initialization of a reference. +static void TryReferenceListInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitListExpr *InitList, + InitializationSequence &Sequence) +{ + // First, catch C++03 where this isn't possible. + if (!S.getLangOptions().CPlusPlus0x) { + Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList); + return; + } + + QualType DestType = Entity.getType(); + QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); + Qualifiers T1Quals; + QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals); + + // Reference initialization via an initializer list works thus: + // If the initializer list consists of a single element that is + // reference-related to the referenced type, bind directly to that element + // (possibly creating temporaries). + // Otherwise, initialize a temporary with the initializer list and + // bind to that. + if (InitList->getNumInits() == 1) { + Expr *Initializer = InitList->getInit(0); + QualType cv2T2 = Initializer->getType(); + Qualifiers T2Quals; + QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals); + + // If this fails, creating a temporary wouldn't work either. + if (ResolveOverloadedFunctionForReferenceBinding(S, Initializer, cv2T2, T2, + T1, Sequence)) + return; + + SourceLocation DeclLoc = Initializer->getLocStart(); + bool dummy1, dummy2, dummy3; + Sema::ReferenceCompareResult RefRelationship + = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1, + dummy2, dummy3); + if (RefRelationship >= Sema::Ref_Related) { + // Try to bind the reference here. + TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1, + T1Quals, cv2T2, T2, T2Quals, Sequence); + if (Sequence) + Sequence.RewrapReferenceInitList(cv1T1, InitList); + return; + } + } + + // Not reference-related. Create a temporary and bind to that. + InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1); + + TryListInitialization(S, TempEntity, Kind, InitList, Sequence); + if (Sequence) { + if (DestType->isRValueReferenceType() || + (T1Quals.hasConst() && !T1Quals.hasVolatile())) + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); + else + Sequence.SetFailed( + InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary); + } +} + /// \brief Attempt list initialization (C++0x [dcl.init.list]) static void TryListInitialization(Sema &S, const InitializedEntity &Entity, @@ -2814,11 +2938,11 @@ static void TryListInitialization(Sema &S, Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar); return; } - // FIXME: C++0x defines behavior for these two cases. if (DestType->isReferenceType()) { - Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList); + TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence); return; } + // FIXME: C++11 defines behavior for this case. if (DestType->isRecordType() && !DestType->isAggregateType()) { Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); return; @@ -3041,27 +3165,31 @@ static void TryReferenceInitialization(Sema &S, QualType cv2T2 = Initializer->getType(); Qualifiers T2Quals; QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals); - SourceLocation DeclLoc = Initializer->getLocStart(); // If the initializer is the address of an overloaded function, try // to resolve the overloaded function. If all goes well, T2 is the // type of the resulting function. - if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { - DeclAccessPair Found; - bool HadMultipleCandidates = false; - if (FunctionDecl *Fn - = S.ResolveAddressOfOverloadedFunction(Initializer, T1, false, Found, - &HadMultipleCandidates)) { - Sequence.AddAddressOverloadResolutionStep(Fn, Found, - HadMultipleCandidates); - cv2T2 = Fn->getType(); - T2 = cv2T2.getUnqualifiedType(); - } else if (!T1->isRecordType()) { - Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); - return; - } - } + if (ResolveOverloadedFunctionForReferenceBinding(S, Initializer, cv2T2, T2, + T1, Sequence)) + return; + + // Delegate everything else to a subfunction. + TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1, + T1Quals, cv2T2, T2, T2Quals, Sequence); +} +/// \brief Reference initialization without resolving overloaded functions. +static void TryReferenceInitializationCore(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + QualType cv1T1, QualType T1, + Qualifiers T1Quals, + QualType cv2T2, QualType T2, + Qualifiers T2Quals, + InitializationSequence &Sequence) { + QualType DestType = Entity.getType(); + SourceLocation DeclLoc = Initializer->getLocStart(); // Compute some basic properties of the types and the initializer. bool isLValueRef = DestType->isLValueReferenceType(); bool isRValueRef = !isLValueRef; @@ -4486,6 +4614,8 @@ InitializationSequence::Perform(Sema &S, case SK_ConversionSequence: case SK_ListConstructorCall: case SK_ListInitialization: + case SK_UnwrapInitList: + case SK_RewrapInitList: case SK_CAssignment: case SK_StringInit: case SK_ObjCObjectConversion: @@ -4746,22 +4876,59 @@ InitializationSequence::Perform(Sema &S, case SK_ListInitialization: { InitListExpr *InitList = cast<InitListExpr>(CurInit.get()); - QualType Ty = Step->Type; - InitListChecker PerformInitList(S, Entity, InitList, - ResultType ? *ResultType : Ty, /*VerifyOnly=*/false, + // Hack: We must pass *ResultType if available in order to set the type + // of arrays, e.g. in 'int ar[] = {1, 2, 3};'. + // But in 'const X &x = {1, 2, 3};' we're supposed to initialize a + // temporary, not a reference, so we should pass Ty. + // Worst case: 'const int (&arref)[] = {1, 2, 3};'. + // Since this step is never used for a reference directly, we explicitly + // unwrap references here and rewrap them afterwards. + // We also need to create a InitializeTemporary entity for this. + QualType Ty = ResultType ? ResultType->getNonReferenceType() : Step->Type; + bool IsTemporary = ResultType && (*ResultType)->isReferenceType(); + InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty); + InitListChecker PerformInitList(S, IsTemporary ? TempEntity : Entity, + InitList, Ty, /*VerifyOnly=*/false, Kind.getKind() != InitializationKind::IK_Direct || !S.getLangOptions().CPlusPlus0x); if (PerformInitList.HadError()) return ExprError(); + if (ResultType) { + if ((*ResultType)->isRValueReferenceType()) + Ty = S.Context.getRValueReferenceType(Ty); + else if ((*ResultType)->isLValueReferenceType()) + Ty = S.Context.getLValueReferenceType(Ty, + (*ResultType)->getAs<LValueReferenceType>()->isSpelledAsLValue()); + *ResultType = Ty; + } + + InitListExpr *StructuredInitList = + PerformInitList.getFullyStructuredList(); CurInit.release(); - CurInit = S.Owned(PerformInitList.getFullyStructuredList()); + CurInit = S.Owned(StructuredInitList); break; } case SK_ListConstructorCall: assert(false && "List constructor calls not yet supported."); + case SK_UnwrapInitList: + CurInit = S.Owned(cast<InitListExpr>(CurInit.take())->getInit(0)); + break; + + case SK_RewrapInitList: { + Expr *E = CurInit.take(); + InitListExpr *Syntactic = Step->WrappingSyntacticList; + InitListExpr *ILE = new (S.Context) InitListExpr(S.Context, + Syntactic->getLBraceLoc(), &E, 1, Syntactic->getRBraceLoc()); + ILE->setSyntacticForm(Syntactic); + ILE->setType(E->getType()); + ILE->setValueKind(E->getValueKind()); + CurInit = S.Owned(ILE); + break; + } + case SK_ConstructorInitialization: { unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor @@ -5081,6 +5248,16 @@ bool InitializationSequence::Diagnose(Sema &S, break; case FK_NonConstLValueReferenceBindingToTemporary: + if (isa<InitListExpr>(Args[0])) { + S.Diag(Kind.getLocation(), + diag::err_lvalue_reference_bind_to_initlist) + << DestType.getNonReferenceType().isVolatileQualified() + << DestType.getNonReferenceType() + << Args[0]->getSourceRange(); + break; + } + // Intentional fallthrough + case FK_NonConstLValueReferenceBindingToUnrelated: S.Diag(Kind.getLocation(), Failure == FK_NonConstLValueReferenceBindingToTemporary @@ -5446,9 +5623,11 @@ void InitializationSequence::dump(raw_ostream &OS) const { case SK_QualificationConversionRValue: OS << "qualification conversion (rvalue)"; + break; case SK_QualificationConversionXValue: OS << "qualification conversion (xvalue)"; + break; case SK_QualificationConversionLValue: OS << "qualification conversion (lvalue)"; @@ -5468,6 +5647,14 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "list initialization via constructor"; break; + case SK_UnwrapInitList: + OS << "unwrap reference initializer list"; + break; + + case SK_RewrapInitList: + OS << "rewrap reference initializer list"; + break; + case SK_ConstructorInitialization: OS << "constructor initialization"; break; |