summaryrefslogtreecommitdiffstats
path: root/clang/lib/Analysis/CFG.cpp
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 /clang/lib/Analysis/CFG.cpp
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
Diffstat (limited to 'clang/lib/Analysis/CFG.cpp')
-rw-r--r--clang/lib/Analysis/CFG.cpp65
1 files changed, 57 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();
OpenPOWER on IntegriCloud