forked from OSchip/llvm-project
Save a copy expression for non-trivial copy constructions of catch variables.
llvm-svn: 125661
This commit is contained in:
parent
c8fb2557b9
commit
1bf5846abf
|
@ -3636,6 +3636,11 @@ public:
|
||||||
Loc(Loc) {
|
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)
|
explicit OpaqueValueExpr(EmptyShell Empty)
|
||||||
: Expr(OpaqueValueExprClass, Empty) { }
|
: Expr(OpaqueValueExprClass, Empty) { }
|
||||||
|
|
||||||
|
|
|
@ -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.
|
// ExprIterator.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -1034,7 +1034,8 @@ static void InitCatchParam(CodeGenFunction &CGF,
|
||||||
|
|
||||||
const llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
|
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 *AdjustedExn = CallBeginCatch(CGF, Exn, true);
|
||||||
llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
|
llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
|
||||||
CGF.EmitAggregateCopy(ParamAddr, Cast, CatchType);
|
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
|
// We have to call __cxa_get_exception_ptr to get the adjusted
|
||||||
// pointer before copying.
|
// pointer before copying.
|
||||||
llvm::CallInst *AdjustedExn =
|
llvm::CallInst *rawAdjustedExn =
|
||||||
CGF.Builder.CreateCall(getGetExceptionPtrFn(CGF), Exn);
|
CGF.Builder.CreateCall(getGetExceptionPtrFn(CGF), Exn);
|
||||||
AdjustedExn->setDoesNotThrow();
|
rawAdjustedExn->setDoesNotThrow();
|
||||||
llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
|
|
||||||
|
|
||||||
CXXConstructorDecl *CD = RD->getCopyConstructor(CGF.getContext(), 0);
|
// Cast that to the appropriate type.
|
||||||
assert(CD && "record has no copy constructor!");
|
llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);
|
||||||
llvm::Value *CopyCtor = CGF.CGM.GetAddrOfCXXConstructor(CD, Ctor_Complete);
|
|
||||||
|
|
||||||
CallArgList CallArgs;
|
// The copy expression is defined in terms of an OpaqueValueExpr.
|
||||||
CallArgs.push_back(std::make_pair(RValue::get(ParamAddr),
|
// Find it and map it to the adjusted expression.
|
||||||
CD->getThisType(CGF.getContext())));
|
CodeGenFunction::OpaqueValueMapping
|
||||||
CallArgs.push_back(std::make_pair(RValue::get(Cast),
|
opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr), adjustedExn);
|
||||||
CD->getParamDecl(0)->getType()));
|
|
||||||
|
|
||||||
const FunctionProtoType *FPT
|
|
||||||
= CD->getType()->getAs<FunctionProtoType>();
|
|
||||||
|
|
||||||
// Call the copy ctor in a terminate scope.
|
// Call the copy ctor in a terminate scope.
|
||||||
CGF.EHStack.pushTerminate();
|
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();
|
CGF.EHStack.popTerminate();
|
||||||
|
|
||||||
|
// Undo the opaque value mapping.
|
||||||
|
opaque.pop();
|
||||||
|
|
||||||
// Finally we can call __cxa_begin_catch.
|
// Finally we can call __cxa_begin_catch.
|
||||||
CallBeginCatch(CGF, Exn, true);
|
CallBeginCatch(CGF, Exn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Begins a catch statement by initializing the catch variable and
|
/// Begins a catch statement by initializing the catch variable and
|
||||||
/// calling __cxa_begin_catch.
|
/// calling __cxa_begin_catch.
|
||||||
static void BeginCatch(CodeGenFunction &CGF,
|
static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) {
|
||||||
const CXXCatchStmt *S) {
|
|
||||||
// We have to be very careful with the ordering of cleanups here:
|
// We have to be very careful with the ordering of cleanups here:
|
||||||
// C++ [except.throw]p4:
|
// C++ [except.throw]p4:
|
||||||
// The destruction [of the exception temporary] occurs
|
// The destruction [of the exception temporary] occurs
|
||||||
|
|
|
@ -583,6 +583,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
|
||||||
return EmitConditionalOperatorLValue(cast<ConditionalOperator>(E));
|
return EmitConditionalOperatorLValue(cast<ConditionalOperator>(E));
|
||||||
case Expr::ChooseExprClass:
|
case Expr::ChooseExprClass:
|
||||||
return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext()));
|
return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext()));
|
||||||
|
case Expr::OpaqueValueExprClass:
|
||||||
|
return EmitOpaqueValueLValue(cast<OpaqueValueExpr>(E));
|
||||||
case Expr::ImplicitCastExprClass:
|
case Expr::ImplicitCastExprClass:
|
||||||
case Expr::CStyleCastExprClass:
|
case Expr::CStyleCastExprClass:
|
||||||
case Expr::CXXFunctionalCastExprClass:
|
case Expr::CXXFunctionalCastExprClass:
|
||||||
|
@ -1888,6 +1890,12 @@ LValue CodeGenFunction::EmitNullInitializationLValue(
|
||||||
return LV;
|
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
|
// Expression Emission
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
|
|
|
@ -129,6 +129,8 @@ public:
|
||||||
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
|
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
|
||||||
void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
|
void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
|
||||||
|
|
||||||
|
void VisitOpaqueValueExpr(OpaqueValueExpr *E);
|
||||||
|
|
||||||
void VisitVAArgExpr(VAArgExpr *E);
|
void VisitVAArgExpr(VAArgExpr *E);
|
||||||
|
|
||||||
void EmitInitializationToLValue(Expr *E, LValue Address, QualType T);
|
void EmitInitializationToLValue(Expr *E, LValue Address, QualType T);
|
||||||
|
@ -242,6 +244,10 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
|
||||||
// Visitor Methods
|
// Visitor Methods
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
|
||||||
|
EmitFinalDestCopy(e, CGF.EmitOpaqueValueLValue(e));
|
||||||
|
}
|
||||||
|
|
||||||
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
|
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
|
||||||
if (Dest.isIgnored() && E->getCastKind() != CK_Dynamic) {
|
if (Dest.isIgnored() && E->getCastKind() != CK_Dynamic) {
|
||||||
Visit(E->getSubExpr());
|
Visit(E->getSubExpr());
|
||||||
|
|
|
@ -129,6 +129,14 @@ public:
|
||||||
}
|
}
|
||||||
ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); }
|
ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); }
|
||||||
ComplexPairTy VisitMemberExpr(const 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
|
// FIXME: CompoundLiteralExpr
|
||||||
|
|
||||||
|
|
|
@ -200,6 +200,13 @@ public:
|
||||||
E->getPackLength());
|
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.
|
// l-values.
|
||||||
Value *VisitDeclRefExpr(DeclRefExpr *E) {
|
Value *VisitDeclRefExpr(DeclRefExpr *E) {
|
||||||
Expr::EvalResult Result;
|
Expr::EvalResult Result;
|
||||||
|
|
|
@ -839,6 +839,31 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// 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
|
/// getByrefValueFieldNumber - Given a declaration, returns the LLVM field
|
||||||
/// number that holds the value.
|
/// number that holds the value.
|
||||||
unsigned getByRefValueLLVMField(const ValueDecl *VD) const;
|
unsigned getByRefValueLLVMField(const ValueDecl *VD) const;
|
||||||
|
@ -883,6 +908,10 @@ private:
|
||||||
/// statement range in current switch instruction.
|
/// statement range in current switch instruction.
|
||||||
llvm::BasicBlock *CaseRangeBlock;
|
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.
|
// 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
|
// 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,
|
// in certain situations, like a const qualifier applied to an VLA typedef,
|
||||||
|
@ -1278,6 +1307,16 @@ public:
|
||||||
return Res;
|
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
|
/// getAccessedFieldNo - Given an encoded value and a result number, return
|
||||||
/// the input field number being accessed.
|
/// the input field number being accessed.
|
||||||
static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);
|
static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);
|
||||||
|
@ -1609,6 +1648,7 @@ public:
|
||||||
LValue EmitConditionalOperatorLValue(const ConditionalOperator *E);
|
LValue EmitConditionalOperatorLValue(const ConditionalOperator *E);
|
||||||
LValue EmitCastLValue(const CastExpr *E);
|
LValue EmitCastLValue(const CastExpr *E);
|
||||||
LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E);
|
LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E);
|
||||||
|
LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
|
||||||
|
|
||||||
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
|
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
|
||||||
const ObjCIvarDecl *Ivar);
|
const ObjCIvarDecl *Ivar);
|
||||||
|
|
|
@ -6593,7 +6593,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
|
||||||
ExDecl->setExceptionVariable(true);
|
ExDecl->setExceptionVariable(true);
|
||||||
|
|
||||||
if (!Invalid) {
|
if (!Invalid) {
|
||||||
if (const RecordType *RecordTy = ExDeclType->getAs<RecordType>()) {
|
if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) {
|
||||||
// C++ [except.handle]p16:
|
// C++ [except.handle]p16:
|
||||||
// The object declared in an exception-declaration or, if the
|
// The object declared in an exception-declaration or, if the
|
||||||
// exception-declaration does not specify a name, a temporary (12.2) is
|
// 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
|
// We just pretend to initialize the object with itself, then make sure
|
||||||
// it can be destroyed later.
|
// it can be destroyed later.
|
||||||
InitializedEntity Entity = InitializedEntity::InitializeVariable(ExDecl);
|
QualType initType = ExDeclType;
|
||||||
Expr *ExDeclRef = DeclRefExpr::Create(Context, 0, SourceRange(), ExDecl,
|
|
||||||
Loc, ExDeclType, VK_LValue, 0);
|
InitializedEntity entity =
|
||||||
InitializationKind Kind = InitializationKind::CreateCopy(Loc,
|
InitializedEntity::InitializeVariable(ExDecl);
|
||||||
SourceLocation());
|
InitializationKind initKind =
|
||||||
InitializationSequence InitSeq(*this, Entity, Kind, &ExDeclRef, 1);
|
InitializationKind::CreateCopy(Loc, SourceLocation());
|
||||||
ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
|
|
||||||
MultiExprArg(*this, &ExDeclRef, 1));
|
Expr *opaqueValue =
|
||||||
if (Result.isInvalid())
|
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;
|
Invalid = true;
|
||||||
else
|
else {
|
||||||
FinalizeVarWithDestructor(ExDecl, RecordTy);
|
// 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -259,3 +259,37 @@ namespace test4 {
|
||||||
return new(foo(),bar()) A(5);
|
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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue