diff options
-rw-r--r-- | lib/Analysis/CFG.cpp | 65 | ||||
-rw-r--r-- | test/SemaCXX/uninitialized.cpp | 27 |
2 files changed, 84 insertions, 8 deletions
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 73879214f3..4c1652122f 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -639,6 +639,52 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) { return Block; } +/// \brief Retrieve the type of the temporary object whose lifetime was +/// extended by a local reference with the given initializer. +static QualType getReferenceInitTemporaryType(ASTContext &Context, + const Expr *Init) { + while (true) { + // Skip parentheses. + Init = Init->IgnoreParens(); + + // Skip through cleanups. + if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init)) { + Init = EWC->getSubExpr(); + continue; + } + + // Skip through the temporary-materialization expression. + if (const MaterializeTemporaryExpr *MTE + = dyn_cast<MaterializeTemporaryExpr>(Init)) { + Init = MTE->GetTemporaryExpr(); + continue; + } + + // Skip derived-to-base and no-op casts. + if (const CastExpr *CE = dyn_cast<CastExpr>(Init)) { + if ((CE->getCastKind() == CK_DerivedToBase || + CE->getCastKind() == CK_UncheckedDerivedToBase || + CE->getCastKind() == CK_NoOp) && + Init->getType()->isRecordType()) { + Init = CE->getSubExpr(); + continue; + } + } + + // Skip member accesses into rvalues. + if (const MemberExpr *ME = dyn_cast<MemberExpr>(Init)) { + if (!ME->isArrow() && ME->getBase()->isRValue()) { + Init = ME->getBase(); + continue; + } + } + + break; + } + + return Init->getType(); +} + /// addAutomaticObjDtors - Add to current block automatic objects destructors /// for objects in range of local scope positions. Use S as trigger statement /// for destructors. @@ -667,9 +713,13 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, // If this destructor is marked as a no-return destructor, we need to // create a new block for the destructor which does not have as a successor // anything built thus far: control won't flow out of this block. - QualType Ty = (*I)->getType().getNonReferenceType(); - if (const ArrayType *AT = Context->getAsArrayType(Ty)) - Ty = AT->getElementType(); + QualType Ty; + if ((*I)->getType()->isReferenceType()) { + Ty = getReferenceInitTemporaryType(*Context, (*I)->getInit()); + } else { + Ty = Context->getBaseElementType((*I)->getType()); + } + const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor(); if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr()) Block = createNoReturnBlock(); @@ -799,16 +849,15 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, // Check for const references bound to temporary. Set type to pointee. QualType QT = VD->getType(); - if (const ReferenceType* RT = QT.getTypePtr()->getAs<ReferenceType>()) { - QT = RT->getPointeeType(); - if (!QT.isConstQualified()) - return Scope; + if (QT.getTypePtr()->isReferenceType()) { if (!VD->extendsLifetimeOfTemporary()) return Scope; + + QT = getReferenceInitTemporaryType(*Context, VD->getInit()); } // Check for constant size array. Set type to array element type. - if (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) { + while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) { if (AT->getSize() == 0) return Scope; QT = AT->getElementType(); diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp index c25bd201d6..c3a5994af4 100644 --- a/test/SemaCXX/uninitialized.cpp +++ b/test/SemaCXX/uninitialized.cpp @@ -117,3 +117,30 @@ struct S { }; struct C { char a[100], *e; } car = { .e = car.a }; + +// <rdar://problem/10398199> +namespace rdar10398199 { + class FooBase { protected: ~FooBase() {} }; + class Foo : public FooBase { + public: + operator int&() const; + }; + void stuff(); + template <typename T> class FooImpl : public Foo { + T val; + public: + FooImpl(const T &x) : val(x) {} + ~FooImpl() { stuff(); } + }; + + template <typename T> FooImpl<T> makeFoo(const T& x) { + return FooImpl<T>(x); + } + + void test() { + const Foo &x = makeFoo(42); + const int&y = makeFoo(42u); + (void)x; + (void)y; + }; +} |