diff options
Diffstat (limited to 'clang/lib/Sema/SemaInit.cpp')
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 209 |
1 files changed, 97 insertions, 112 deletions
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index a4bccacb2da..18b3d8225e0 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2937,6 +2937,12 @@ static void MaybeProduceObjCObject(Sema &S, } } +static void TryListInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitListExpr *InitList, + InitializationSequence &Sequence); + /// \brief When initializing from init list via constructor, handle /// initialization of an object of type std::initializer_list<T>. /// @@ -2950,25 +2956,23 @@ static bool TryInitializerListConstruction(Sema &S, if (!S.isStdInitializerList(DestType, &E)) return 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; - } + if (S.RequireCompleteType(List->getExprLoc(), E, 0)) { + Sequence.setIncompleteTypeFailure(E); + return true; } - Sequence.AddStdInitializerListConstructionStep(DestType); + + // Try initializing a temporary array from the init list. + QualType ArrayType = S.Context.getConstantArrayType( + E.withConst(), llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), + List->getNumInits()), + clang::ArrayType::Normal, 0); + InitializedEntity HiddenArray = + InitializedEntity::InitializeTemporary(ArrayType); + InitializationKind Kind = + InitializationKind::CreateDirectList(List->getExprLoc()); + TryListInitialization(S, HiddenArray, Kind, List, Sequence); + if (Sequence) + Sequence.AddStdInitializerListConstructionStep(DestType); return true; } @@ -3198,12 +3202,6 @@ static void TryValueInitialization(Sema &S, InitializationSequence &Sequence, InitListExpr *InitList = 0); -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, @@ -5135,7 +5133,7 @@ PerformConstructorInitialization(Sema &S, return ExprError(); if (shouldBindAsTemporary(Entity)) - CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + CurInit = S.MaybeBindToTemporary(CurInit.take()); return CurInit; } @@ -5277,19 +5275,18 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) { if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init)) Init = BTE->getSubExpr(); + if (CXXStdInitializerListExpr *ILE = + dyn_cast<CXXStdInitializerListExpr>(Init)) + return performReferenceExtension(ILE->getSubExpr(), ExtendingD); + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { - if (ILE->initializesStdInitializerList() || ILE->getType()->isArrayType()) { - // FIXME: If this is an InitListExpr which creates a std::initializer_list - // object, we also need to lifetime-extend the underlying array - // itself. Fix the representation to explicitly materialize an - // array temporary so we can model this properly. + if (ILE->getType()->isArrayType()) { for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I) performLifetimeExtension(ILE->getInit(I), ExtendingD); return; } - CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl(); - if (RD) { + if (CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl()) { assert(RD->isAggregate() && "aggregate init on non-aggregate"); // If we lifetime-extend a braced initializer which is initializing an @@ -5319,6 +5316,39 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) { } } +static void warnOnLifetimeExtension(Sema &S, const InitializedEntity &Entity, + const Expr *Init, bool IsInitializerList, + const ValueDecl *ExtendingDecl) { + // Warn if a field lifetime-extends a temporary. + if (isa<FieldDecl>(ExtendingDecl)) { + if (IsInitializerList) { + S.Diag(Init->getExprLoc(), diag::warn_dangling_std_initializer_list) + << /*at end of constructor*/true; + return; + } + + bool IsSubobjectMember = false; + for (const InitializedEntity *Ent = Entity.getParent(); Ent; + Ent = Ent->getParent()) { + if (Ent->getKind() != InitializedEntity::EK_Base) { + IsSubobjectMember = true; + break; + } + } + S.Diag(Init->getExprLoc(), + diag::warn_bind_ref_member_to_temporary) + << ExtendingDecl << Init->getSourceRange() + << IsSubobjectMember << IsInitializerList; + if (IsSubobjectMember) + S.Diag(ExtendingDecl->getLocation(), + diag::note_ref_subobject_of_member_declared_here); + else + S.Diag(ExtendingDecl->getLocation(), + diag::note_ref_or_ptr_member_declared_here) + << /*is pointer*/false; + } +} + ExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, @@ -5570,29 +5600,7 @@ InitializationSequence::Perform(Sema &S, getDeclForTemporaryLifetimeExtension(Entity); if (ExtendingDecl) { performLifetimeExtension(CurInit.get(), ExtendingDecl); - - // Warn if a field lifetime-extends a temporary. - if (isa<FieldDecl>(ExtendingDecl)) { - bool IsSubobjectMember = false; - for (const InitializedEntity *Ent = Entity.getParent(); Ent; - Ent = Ent->getParent()) { - if (Ent->getKind() != InitializedEntity::EK_Base) { - IsSubobjectMember = true; - break; - } - } - S.Diag(CurInit.get()->getExprLoc(), - diag::warn_bind_ref_member_to_temporary) - << ExtendingDecl << CurInit.get()->getSourceRange() - << IsSubobjectMember; - if (IsSubobjectMember) - S.Diag(ExtendingDecl->getLocation(), - diag::note_ref_subobject_of_member_declared_here); - else - S.Diag(ExtendingDecl->getLocation(), - diag::note_ref_or_ptr_member_declared_here) - << /*IsPointer*/false; - } + warnOnLifetimeExtension(S, Entity, CurInit.get(), false, ExtendingDecl); } // Materialize the temporary into memory. @@ -5763,16 +5771,10 @@ InitializationSequence::Perform(Sema &S, case SK_ListInitialization: { InitListExpr *InitList = cast<InitListExpr>(CurInit.get()); - // 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 = Entity.getType()->isReferenceType(); + // If we're not initializing the top-level entity, we need to create an + // InitializeTemporary entity for our target type. + QualType Ty = Step->Type; + bool IsTemporary = !S.Context.hasSameType(Entity.getType(), Ty); InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty); InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity; InitListChecker PerformInitList(S, InitEntity, @@ -5780,7 +5782,11 @@ InitializationSequence::Perform(Sema &S, if (PerformInitList.HadError()) return ExprError(); - if (ResultType) { + // Hack: We must update *ResultType if available in order to set the + // bounds of arrays, e.g. in 'int ar[] = {1, 2, 3};'. + // Worst case: 'const int (&arref)[] = {1, 2, 3};'. + if (ResultType && + ResultType->getNonReferenceType()->isIncompleteArrayType()) { if ((*ResultType)->isRValueReferenceType()) Ty = S.Context.getRValueReferenceType(Ty); else if ((*ResultType)->isLValueReferenceType()) @@ -5973,56 +5979,35 @@ InitializationSequence::Perform(Sema &S, break; case SK_StdInitializerList: { - QualType Dest = Step->Type; - QualType E; - bool Success = S.isStdInitializerList(Dest.getNonReferenceType(), &E); - (void)Success; - assert(Success && "Destination type changed?"); - - // If the element type has a destructor, check it. - if (CXXRecordDecl *RD = E->getAsCXXRecordDecl()) { - if (!RD->hasIrrelevantDestructor()) { - if (CXXDestructorDecl *Destructor = S.LookupDestructor(RD)) { - S.MarkFunctionReferenced(Kind.getLocation(), Destructor); - S.CheckDestructorAccess(Kind.getLocation(), Destructor, - S.PDiag(diag::err_access_dtor_temp) << E); - if (S.DiagnoseUseOfDecl(Destructor, Kind.getLocation())) - return ExprError(); - } - } - } + S.Diag(CurInit.get()->getExprLoc(), + diag::warn_cxx98_compat_initializer_list_init) + << CurInit.get()->getSourceRange(); - InitListExpr *ILE = cast<InitListExpr>(CurInit.take()); - S.Diag(ILE->getExprLoc(), diag::warn_cxx98_compat_initializer_list_init) - << ILE->getSourceRange(); - unsigned NumInits = ILE->getNumInits(); - SmallVector<Expr*, 16> Converted(NumInits); - InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary( - S.Context.getConstantArrayType(E, - llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), - NumInits), - ArrayType::Normal, 0)); - InitializedEntity Element =InitializedEntity::InitializeElement(S.Context, - 0, HiddenArray); - for (unsigned i = 0; i < NumInits; ++i) { - Element.setElementIndex(i); - ExprResult Init = S.Owned(ILE->getInit(i)); - ExprResult Res = S.PerformCopyInitialization( - Element, Init.get()->getExprLoc(), Init, - /*TopLevelOfInitList=*/ true); - if (Res.isInvalid()) - return ExprError(); - Converted[i] = Res.take(); + // Maybe lifetime-extend the array temporary's subobjects to match the + // entity's lifetime. + const ValueDecl *ExtendingDecl = + getDeclForTemporaryLifetimeExtension(Entity); + if (ExtendingDecl) { + performLifetimeExtension(CurInit.get(), ExtendingDecl); + warnOnLifetimeExtension(S, Entity, CurInit.get(), true, ExtendingDecl); } - InitListExpr *Semantic = new (S.Context) - InitListExpr(S.Context, ILE->getLBraceLoc(), - Converted, ILE->getRBraceLoc()); - Semantic->setSyntacticForm(ILE); - Semantic->setType(Dest); - Semantic->setInitializesStdInitializerList(); - CurInit = S.Owned(Semantic); + + // Materialize the temporary into memory. + MaterializeTemporaryExpr *MTE = new (S.Context) + MaterializeTemporaryExpr(CurInit.get()->getType(), CurInit.get(), + /*lvalue reference*/ false, ExtendingDecl); + + // Wrap it in a construction of a std::initializer_list<T>. + CurInit = S.Owned( + new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE)); + + // Bind the result, in case the library has given initializer_list a + // non-trivial destructor. + if (shouldBindAsTemporary(Entity)) + CurInit = S.MaybeBindToTemporary(CurInit.take()); break; } + case SK_OCLSamplerInit: { assert(Step->Type->isSamplerT() && "Sampler initialization on non sampler type."); |