[cfe-commits] r144646 - in /cfe/trunk: lib/Analysis/CFG.cpp test/SemaCXX/uninitialized.cpp

Douglas Gregor dgregor at apple.com
Tue Nov 15 07:29:30 PST 2011


Author: dgregor
Date: Tue Nov 15 09:29:30 2011
New Revision: 144646

URL: http://llvm.org/viewvc/llvm-project?rev=144646&view=rev
Log:
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>.

Modified:
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/test/SemaCXX/uninitialized.cpp

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=144646&r1=144645&r2=144646&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Tue Nov 15 09:29:30 2011
@@ -639,6 +639,52 @@
   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 @@
     // 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 @@
 
   // 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();

Modified: cfe/trunk/test/SemaCXX/uninitialized.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/uninitialized.cpp?rev=144646&r1=144645&r2=144646&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/uninitialized.cpp (original)
+++ cfe/trunk/test/SemaCXX/uninitialized.cpp Tue Nov 15 09:29:30 2011
@@ -117,3 +117,30 @@
 };
 
 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;
+  };
+}





More information about the cfe-commits mailing list