]> granicus.if.org Git - clang/commitdiff
Save a copy expression for non-trivial copy constructions of catch variables.
authorJohn McCall <rjmccall@apple.com>
Wed, 16 Feb 2011 08:02:54 +0000 (08:02 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 16 Feb 2011 08:02:54 +0000 (08:02 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125661 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
lib/AST/Expr.cpp
lib/CodeGen/CGException.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprComplex.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/CodeGenFunction.h
lib/Sema/SemaDeclCXX.cpp
test/CodeGenCXX/exceptions.cpp

index 2977d75f30b9914dfcbf2467c7bd12e1c41ed0f0..c09394d9c0432336225fefbe4e4b9095612769cf 100644 (file)
@@ -3636,6 +3636,11 @@ public:
       Loc(Loc) {
   }
 
+  /// Given an expression which invokes a copy constructor --- i.e.  a
+  /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups ---
+  /// find the OpaqueValueExpr that's the source of the construction.
+  static const OpaqueValueExpr *findInCopyConstruct(const Expr *expr);
+
   explicit OpaqueValueExpr(EmptyShell Empty)
     : Expr(OpaqueValueExprClass, Empty) { }
 
index 884a184b5267e3558f5eadf42469a31b8126b1e0..209e5d3260fd1d9bcc9c5bb12536b67b7b212750 100644 (file)
@@ -2751,6 +2751,15 @@ ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
   }
 }
 
+const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
+  if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
+    e = ewc->getSubExpr();
+  e = cast<CXXConstructExpr>(e)->getArg(0);
+  while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
+    e = ice->getSubExpr();
+  return cast<OpaqueValueExpr>(e);
+}
+
 //===----------------------------------------------------------------------===//
 //  ExprIterator.
 //===----------------------------------------------------------------------===//
index f110f797b0de2c459b992c2e700a15fa3b0daec5..cde27288c3f410df28a121e4005479ca0bb7e7b1 100644 (file)
@@ -1034,7 +1034,8 @@ static void InitCatchParam(CodeGenFunction &CGF,
 
   const llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
 
-  if (RD->hasTrivialCopyConstructor()) {
+  const Expr *copyExpr = CatchParam.getInit();
+  if (!copyExpr) {
     llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, true);
     llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
     CGF.EmitAggregateCopy(ParamAddr, Cast, CatchType);
@@ -1043,38 +1044,37 @@ static void InitCatchParam(CodeGenFunction &CGF,
 
   // We have to call __cxa_get_exception_ptr to get the adjusted
   // pointer before copying.
-  llvm::CallInst *AdjustedExn =
+  llvm::CallInst *rawAdjustedExn =
     CGF.Builder.CreateCall(getGetExceptionPtrFn(CGF), Exn);
-  AdjustedExn->setDoesNotThrow();
-  llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
+  rawAdjustedExn->setDoesNotThrow();
 
-  CXXConstructorDecl *CD = RD->getCopyConstructor(CGF.getContext(), 0);
-  assert(CD && "record has no copy constructor!");
-  llvm::Value *CopyCtor = CGF.CGM.GetAddrOfCXXConstructor(CD, Ctor_Complete);
+  // Cast that to the appropriate type.
+  llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);
 
-  CallArgList CallArgs;
-  CallArgs.push_back(std::make_pair(RValue::get(ParamAddr),
-                                    CD->getThisType(CGF.getContext())));
-  CallArgs.push_back(std::make_pair(RValue::get(Cast),
-                                    CD->getParamDecl(0)->getType()));
-
-  const FunctionProtoType *FPT
-    = CD->getType()->getAs<FunctionProtoType>();
+  // The copy expression is defined in terms of an OpaqueValueExpr.
+  // Find it and map it to the adjusted expression.
+  CodeGenFunction::OpaqueValueMapping
+    opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr), adjustedExn);
 
   // Call the copy ctor in a terminate scope.
   CGF.EHStack.pushTerminate();
-  CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
-               CopyCtor, ReturnValueSlot(), CallArgs, CD);
+
+  // Perform the copy construction.
+  CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, false, false));
+
+  // Leave the terminate scope.
   CGF.EHStack.popTerminate();
 
+  // Undo the opaque value mapping.
+  opaque.pop();
+
   // Finally we can call __cxa_begin_catch.
   CallBeginCatch(CGF, Exn, true);
 }
 
 /// Begins a catch statement by initializing the catch variable and
 /// calling __cxa_begin_catch.
-static void BeginCatch(CodeGenFunction &CGF,
-                       const CXXCatchStmt *S) {
+static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) {
   // We have to be very careful with the ordering of cleanups here:
   //   C++ [except.throw]p4:
   //     The destruction [of the exception temporary] occurs
index 049aeeeebb8e8061e644d694f1365a3268157088..56a9107a82c49f219547cab2856c6547e9c09b7c 100644 (file)
@@ -583,6 +583,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
     return EmitConditionalOperatorLValue(cast<ConditionalOperator>(E));
   case Expr::ChooseExprClass:
     return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext()));
+  case Expr::OpaqueValueExprClass:
+    return EmitOpaqueValueLValue(cast<OpaqueValueExpr>(E));
   case Expr::ImplicitCastExprClass:
   case Expr::CStyleCastExprClass:
   case Expr::CXXFunctionalCastExprClass:
@@ -1888,6 +1890,12 @@ LValue CodeGenFunction::EmitNullInitializationLValue(
   return LV;
 }
 
+LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) {
+  assert(e->isGLValue() || e->getType()->isRecordType());
+  llvm::Value *value = getOpaqueValueMapping(e);
+  return MakeAddrLValue(value, e->getType());
+}
+
 //===--------------------------------------------------------------------===//
 //                             Expression Emission
 //===--------------------------------------------------------------------===//
index ad62a3ba5379f4bee006d29d75d9150f562b8a28..0b3a617be159e6b79113ba2669041bab00cd057d 100644 (file)
@@ -129,6 +129,8 @@ public:
   void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
   void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
 
+  void VisitOpaqueValueExpr(OpaqueValueExpr *E);
+
   void VisitVAArgExpr(VAArgExpr *E);
 
   void EmitInitializationToLValue(Expr *E, LValue Address, QualType T);
@@ -242,6 +244,10 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
 //                            Visitor Methods
 //===----------------------------------------------------------------------===//
 
+void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
+  EmitFinalDestCopy(e, CGF.EmitOpaqueValueLValue(e));
+}
+
 void AggExprEmitter::VisitCastExpr(CastExpr *E) {
   if (Dest.isIgnored() && E->getCastKind() != CK_Dynamic) {
     Visit(E->getSubExpr());
index 21c298a96aea3854afc98fde07449b49bb379062..15901eb99a8579b28ccc46829594aaf2ee7f240b 100644 (file)
@@ -129,6 +129,14 @@ public:
   }
   ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); }
   ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); }
+  ComplexPairTy VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+    if (E->isGLValue()) return EmitLoadOfLValue(E);
+
+    // Otherwise, the mapping is... what, exactly?  Probably a
+    // first-class aggregate, but it's really just not worthwhile.
+    CGF.ErrorUnsupported(E, "complex opaque r-value");
+    return ComplexPairTy();
+  }
 
   // FIXME: CompoundLiteralExpr
 
index e2e404f70fb526d583693211fc3b238b5f18c7f3..99f3f0d32310a34c0b343122fc1f20b3e10677f4 100644 (file)
@@ -199,6 +199,13 @@ public:
     return llvm::ConstantInt::get(ConvertType(E->getType()), 
                                   E->getPackLength());
   }
+
+  Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+    if (E->isGLValue()) return EmitLoadOfLValue(E);
+
+    // Otherwise, assume the mapping is the scalar directly.
+    return CGF.getOpaqueValueMapping(E);
+  }
     
   // l-values.
   Value *VisitDeclRefExpr(DeclRefExpr *E) {
index 5ea1565fc315ecc1f33fa9e6047e811b39321042..c4971506c50b4ee639a2df8a393b3ef2f280781c 100644 (file)
@@ -838,6 +838,31 @@ public:
       CGF.EnsureInsertPoint();
     }
   };
+
+  /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
+  class OpaqueValueMapping {
+    CodeGenFunction &CGF;
+    const OpaqueValueExpr *OpaqueValue;
+
+  public:
+    OpaqueValueMapping(CodeGenFunction &CGF,
+                       const OpaqueValueExpr *opaqueValue,
+                       llvm::Value *value)
+      : CGF(CGF), OpaqueValue(opaqueValue) {
+      assert(opaqueValue && "no opaque value expression!");
+      CGF.OpaqueValues.insert(std::make_pair(opaqueValue, value));
+    }
+
+    void pop() {
+      assert(OpaqueValue && "mapping already popped!");
+      CGF.OpaqueValues.erase(OpaqueValue);
+      OpaqueValue = 0;
+    }
+
+    ~OpaqueValueMapping() {
+      if (OpaqueValue) CGF.OpaqueValues.erase(OpaqueValue);
+    }
+  };
   
   /// getByrefValueFieldNumber - Given a declaration, returns the LLVM field
   /// number that holds the value.
@@ -883,6 +908,10 @@ private:
   /// statement range in current switch instruction.
   llvm::BasicBlock *CaseRangeBlock;
 
+  /// OpaqueValues - Keeps track of the current set of opaque value
+  /// expressions.
+  llvm::DenseMap<const OpaqueValueExpr *, llvm::Value*> OpaqueValues;
+
   // VLASizeMap - This keeps track of the associated size for each VLA type.
   // We track this by the size expression rather than the type itself because
   // in certain situations, like a const qualifier applied to an VLA typedef,
@@ -1278,6 +1307,16 @@ public:
     return Res;
   }
 
+  /// getOpaqueValueMapping - Given an opaque value expression (which
+  /// must be mapped), return its mapping.  Whether this is an address
+  /// or a value depends on the expression's type and value kind.
+  llvm::Value *getOpaqueValueMapping(const OpaqueValueExpr *e) {
+    llvm::DenseMap<const OpaqueValueExpr*,llvm::Value*>::iterator
+      it = OpaqueValues.find(e);
+    assert(it != OpaqueValues.end() && "no mapping for opaque value!");
+    return it->second;
+  }
+
   /// getAccessedFieldNo - Given an encoded value and a result number, return
   /// the input field number being accessed.
   static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);
@@ -1609,6 +1648,7 @@ public:
   LValue EmitConditionalOperatorLValue(const ConditionalOperator *E);
   LValue EmitCastLValue(const CastExpr *E);
   LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E);
+  LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
 
   llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
                               const ObjCIvarDecl *Ivar);
index f929aa039ed4f717cf0bf762a176c785e71ff125..58f656c1454a58ed58877e4a172011086b8515ac 100644 (file)
@@ -6593,7 +6593,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
   ExDecl->setExceptionVariable(true);
   
   if (!Invalid) {
-    if (const RecordType *RecordTy = ExDeclType->getAs<RecordType>()) {
+    if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) {
       // C++ [except.handle]p16:
       //   The object declared in an exception-declaration or, if the 
       //   exception-declaration does not specify a name, a temporary (12.2) is 
@@ -6603,18 +6603,32 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
       //
       // We just pretend to initialize the object with itself, then make sure 
       // it can be destroyed later.
-      InitializedEntity Entity = InitializedEntity::InitializeVariable(ExDecl);
-      Expr *ExDeclRef = DeclRefExpr::Create(Context, 0, SourceRange(), ExDecl, 
-                                            Loc, ExDeclType, VK_LValue, 0);
-      InitializationKind Kind = InitializationKind::CreateCopy(Loc, 
-                                                               SourceLocation());
-      InitializationSequence InitSeq(*this, Entity, Kind, &ExDeclRef, 1);
-      ExprResult Result = InitSeq.Perform(*this, Entity, Kind, 
-                                         MultiExprArg(*this, &ExDeclRef, 1));
-      if (Result.isInvalid())
+      QualType initType = ExDeclType;
+
+      InitializedEntity entity =
+        InitializedEntity::InitializeVariable(ExDecl);
+      InitializationKind initKind =
+        InitializationKind::CreateCopy(Loc, SourceLocation());
+
+      Expr *opaqueValue =
+        new (Context) OpaqueValueExpr(Loc, initType, VK_LValue, OK_Ordinary);
+      InitializationSequence sequence(*this, entity, initKind, &opaqueValue, 1);
+      ExprResult result = sequence.Perform(*this, entity, initKind,
+                                           MultiExprArg(&opaqueValue, 1));
+      if (result.isInvalid())
         Invalid = true;
-      else 
-        FinalizeVarWithDestructor(ExDecl, RecordTy);
+      else {
+        // If the constructor used was non-trivial, set this as the
+        // "initializer".
+        CXXConstructExpr *construct = cast<CXXConstructExpr>(result.take());
+        if (!construct->getConstructor()->isTrivial()) {
+          Expr *init = MaybeCreateExprWithCleanups(construct);
+          ExDecl->setInit(init);
+        }
+        
+        // And make sure it's destructable.
+        FinalizeVarWithDestructor(ExDecl, recordType);
+      }
     }
   }
   
index 2413eb0f6d51edd46126137f6fa89e84a14fc8ff..84d55c8f19071d971c9320263329d66e932a6ef8 100644 (file)
@@ -259,3 +259,37 @@ namespace test4 {
     return new(foo(),bar()) A(5);
   }
 }
+
+// PR7908
+namespace test5 {
+  struct T { T(); ~T(); };
+
+  struct A {
+    A(const A &x, const T &t = T());
+    ~A();
+  };
+
+  void foo();
+
+  // CHECK:    define void @_ZN5test54testEv()
+  // CHECK:      [[EXNSLOT:%.*]] = alloca i8*
+  // CHECK-NEXT: [[A:%.*]] = alloca [[A_T:%.*]], align 1
+  // CHECK-NEXT: [[T:%.*]] = alloca [[T_T:%.*]], align 1
+  // CHECK-NEXT: alloca i32
+  // CHECK-NEXT: invoke void @_ZN5test53fooEv()
+  // CHECK:      [[EXN:%.*]] = load i8** [[EXNSLOT]]
+  // CHECK-NEXT: [[ADJ:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[EXN]])
+  // CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[ADJ]] to [[A_T]]*
+  // CHECK-NEXT: invoke void @_ZN5test51TC1Ev([[T_T]]* [[T]])
+  // CHECK:      invoke void @_ZN5test51AC1ERKS0_RKNS_1TE([[A_T]]* [[A]], [[A_T]]* [[SRC]], [[T_T]]* [[T]])
+  // CHECK:      invoke void @_ZN5test51TD1Ev([[T_T]]* [[T]])
+  // CHECK:      call i8* @__cxa_begin_catch(i8* [[EXN]]) nounwind
+  // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A_T]]* [[A]])
+  // CHECK:      call void @__cxa_end_catch()
+  void test() {
+    try {
+      foo();
+    } catch (A a) {
+    }
+  }
+}