summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-11-15 15:29:30 +0000
committerDouglas Gregor <dgregor@apple.com>2011-11-15 15:29:30 +0000
commit6c8f07ff46c8cd41d120f9ab001f8b647961532b (patch)
tree45ccd35b6cd7b38b39019daccd56e3aaf770cf82
parentfee467a0d022ebd8a02c34eab2c9d623a3052e28 (diff)
downloadbcm5719-llvm-6c8f07ff46c8cd41d120f9ab001f8b647961532b.tar.gz
bcm5719-llvm-6c8f07ff46c8cd41d120f9ab001f8b647961532b.zip
Teach the CFG builder how to properly destroy temporaries who
lifetimes have been extended via reference binding. The type of the reference and the type of the temporary are not necessarily the same, which could cause a crash. Fixes <rdar://problem/10398199>. llvm-svn: 144646
-rw-r--r--clang/lib/Analysis/CFG.cpp65
-rw-r--r--clang/test/SemaCXX/uninitialized.cpp27
2 files changed, 84 insertions, 8 deletions
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 73879214f34..4c1652122f9 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/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/clang/test/SemaCXX/uninitialized.cpp b/clang/test/SemaCXX/uninitialized.cpp
index c25bd201d62..c3a5994af45 100644
--- a/clang/test/SemaCXX/uninitialized.cpp
+++ b/clang/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;
+ };
+}
OpenPOWER on IntegriCloud