diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 2977d75f30b9..c09394d9c043 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -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) { } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 884a184b5267..209e5d3260fd 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2751,6 +2751,15 @@ ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, } } +const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { + if (const ExprWithCleanups *ewc = dyn_cast(e)) + e = ewc->getSubExpr(); + e = cast(e)->getArg(0); + while (const ImplicitCastExpr *ice = dyn_cast(e)) + e = ice->getSubExpr(); + return cast(e); +} + //===----------------------------------------------------------------------===// // ExprIterator. //===----------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index f110f797b0de..cde27288c3f4 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -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(); + // 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 diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 049aeeeebb8e..56a9107a82c4 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -583,6 +583,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitConditionalOperatorLValue(cast(E)); case Expr::ChooseExprClass: return EmitLValue(cast(E)->getChosenSubExpr(getContext())); + case Expr::OpaqueValueExprClass: + return EmitOpaqueValueLValue(cast(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 //===--------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index ad62a3ba5379..0b3a617be159 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -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()); diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index 21c298a96aea..15901eb99a85 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -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 diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index e2e404f70fb5..99f3f0d32310 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -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) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 5ea1565fc315..c4971506c50b 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -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 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::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); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f929aa039ed4..58f656c1454a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6593,7 +6593,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, ExDecl->setExceptionVariable(true); if (!Invalid) { - if (const RecordType *RecordTy = ExDeclType->getAs()) { + if (const RecordType *recordType = ExDeclType->getAs()) { // 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(result.take()); + if (!construct->getConstructor()->isTrivial()) { + Expr *init = MaybeCreateExprWithCleanups(construct); + ExDecl->setInit(init); + } + + // And make sure it's destructable. + FinalizeVarWithDestructor(ExDecl, recordType); + } } } diff --git a/clang/test/CodeGenCXX/exceptions.cpp b/clang/test/CodeGenCXX/exceptions.cpp index 2413eb0f6d51..84d55c8f1907 100644 --- a/clang/test/CodeGenCXX/exceptions.cpp +++ b/clang/test/CodeGenCXX/exceptions.cpp @@ -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) { + } + } +}