/// the expression is a default argument.
bool isDefaultArgument() const;
- /// \brief Determine whether this expression directly creates a
- /// temporary object (of class type).
- bool isTemporaryObject() const { return getTemporaryObject() != 0; }
-
- /// \brief If this expression directly creates a temporary object of
- /// class type, return the expression that actually constructs that
- /// temporary object.
- const Expr *getTemporaryObject() const;
+ /// \brief Determine whether the result of this expression is a
+ /// temporary object of the given class type.
+ bool isTemporaryObject(ASTContext &Ctx, const CXXRecordDecl *TempTy) const;
const Expr *IgnoreParens() const {
return const_cast<Expr*>(this)->IgnoreParens();
return E;
}
-const Expr *Expr::getTemporaryObject() const {
- const Expr *E = skipTemporaryBindingsAndNoOpCasts(this);
-
- // A cast can produce a temporary object. The object's construction
- // is represented as a CXXConstructExpr.
- if (const CastExpr *Cast = dyn_cast<CastExpr>(E)) {
- // Only user-defined and constructor conversions can produce
- // temporary objects.
- if (Cast->getCastKind() != CK_ConstructorConversion &&
- Cast->getCastKind() != CK_UserDefinedConversion)
- return 0;
-
- // Strip off temporary bindings and no-op casts.
- const Expr *Sub = skipTemporaryBindingsAndNoOpCasts(Cast->getSubExpr());
-
- // If this is a constructor conversion, see if we have an object
- // construction.
- if (Cast->getCastKind() == CK_ConstructorConversion)
- return dyn_cast<CXXConstructExpr>(Sub);
-
- // If this is a user-defined conversion, see if we have a call to
- // a function that itself returns a temporary object.
- if (Cast->getCastKind() == CK_UserDefinedConversion)
- if (const CallExpr *CE = dyn_cast<CallExpr>(Sub))
- if (CE->getCallReturnType()->isRecordType())
- return CE;
+/// isTemporaryObject - Determines if this expression produces a
+/// temporary of the given class type.
+bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const {
+ if (!C.hasSameUnqualifiedType(getType(), C.getTypeDeclType(TempTy)))
+ return false;
- return 0;
- }
+ const Expr *E = skipTemporaryBindingsAndNoOpCasts(this);
- // A call returning a class type returns a temporary.
- if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
- if (CE->getCallReturnType()->isRecordType())
- return CE;
+ // pr-values of class type are always temporaries.
+ if (!E->Classify(C).isPRValue()) return false;
- return 0;
+ // Black-list implicit derived-to-base conversions, which are the
+ // only way we can get a pr-value of class type that doesn't refer
+ // to a temporary of that type.
+ if (isa<ImplicitCastExpr>(E)) {
+ switch (cast<ImplicitCastExpr>(E)->getCastKind()) {
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ return false;
+ default:
+ break;
+ }
}
- // Explicit temporary object constructors create temporaries.
- return dyn_cast<CXXTemporaryObjectExpr>(E);
+ return true;
}
/// hasAnyTypeDependentArguments - Determines if any of the expressions
SourceLocation());
}
- RValue r = EmitAnyExpr(E, Addr, false);
+ RValue r = EmitAnyExpr(E, AggValueSlot::forAddr(Addr, false, true));
if (r.isScalar()) {
llvm::Value *Loc = r.getScalarVal();
const llvm::Type *Ty = Types[i+BlockFields];
BaseClassDecl,
isBaseVirtual);
- CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true);
+ AggValueSlot AggSlot = AggValueSlot::forAddr(V, false, /*Lifetime*/ true);
+
+ CGF.EmitAggExpr(BaseInit->getInit(), AggSlot);
if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor())
CGF.EHStack.pushCleanup<CallBaseDtor>(EHCleanup, BaseClassDecl,
Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc");
CGF.Builder.CreateStore(Next, ArrayIndexVar);
}
+
+ AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.isVolatileQualified(),
+ /*Lifetime*/ true);
- CGF.EmitAggExpr(MemberInit->getInit(), Dest,
- LHS.isVolatileQualified(),
- /*IgnoreResult*/ false,
- /*IsInitializer*/ true);
+ CGF.EmitAggExpr(MemberInit->getInit(), Slot);
return;
}
} else if (Init->getType()->isAnyComplexType()) {
EmitComplexExprIntoAddr(Init, Loc, isVolatile);
} else {
- EmitAggExpr(Init, Loc, isVolatile);
+ EmitAggExpr(Init, AggValueSlot::forAddr(Loc, isVolatile, true));
}
}
} else if (T->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
} else {
- CGF.EmitAggExpr(Init, DeclPtr, isVolatile);
+ CGF.EmitAggExpr(Init, AggValueSlot::forAddr(DeclPtr, isVolatile, true));
}
}
// evaluated but before the exception is caught. But the best way
// to handle that is to teach EmitAggExpr to do the final copy
// differently if it can't be elided.
- CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false);
+ CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false, /*IsInit*/ true);
CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
ShouldFreeVar);
return EmitComplexToScalarConversion(EmitComplexExpr(E), E->getType(),BoolTy);
}
-/// EmitAnyExpr - Emit code to compute the specified expression which can have
-/// any type. The result is returned as an RValue struct. If this is an
-/// aggregate expression, the aggloc/agglocvolatile arguments indicate where the
+/// EmitAnyExpr - Emit code to compute the specified expression which
+/// can have any type. The result is returned as an RValue struct.
+/// If this is an aggregate expression, AggSlot indicates where the
/// result should be returned.
-RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc,
- bool IsAggLocVolatile, bool IgnoreResult,
- bool IsInitializer) {
+RValue CodeGenFunction::EmitAnyExpr(const Expr *E, AggValueSlot AggSlot,
+ bool IgnoreResult) {
if (!hasAggregateLLVMType(E->getType()))
return RValue::get(EmitScalarExpr(E, IgnoreResult));
else if (E->getType()->isAnyComplexType())
return RValue::getComplex(EmitComplexExpr(E, false, false,
IgnoreResult, IgnoreResult));
- EmitAggExpr(E, AggLoc, IsAggLocVolatile, IgnoreResult, IsInitializer);
- return RValue::getAggregate(AggLoc, IsAggLocVolatile);
+ EmitAggExpr(E, AggSlot, IgnoreResult);
+ return AggSlot.asRValue();
}
/// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will
/// always be accessible even if no aggregate location is provided.
-RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E,
- bool IsAggLocVolatile,
- bool IsInitializer) {
- llvm::Value *AggLoc = 0;
+RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E) {
+ AggValueSlot AggSlot = AggValueSlot::ignored();
if (hasAggregateLLVMType(E->getType()) &&
!E->getType()->isAnyComplexType())
- AggLoc = CreateMemTemp(E->getType(), "agg.tmp");
- return EmitAnyExpr(E, AggLoc, IsAggLocVolatile, /*IgnoreResult=*/false,
- IsInitializer);
+ AggSlot = CreateAggTemp(E->getType(), "agg.tmp");
+ return EmitAnyExpr(E, AggSlot);
}
/// EmitAnyExprToMem - Evaluate an expression into a given memory
if (E->getType()->isComplexType())
EmitComplexExprIntoAddr(E, Location, IsLocationVolatile);
else if (hasAggregateLLVMType(E->getType()))
- EmitAggExpr(E, Location, IsLocationVolatile, /*Ignore*/ false, IsInit);
+ EmitAggExpr(E, AggValueSlot::forAddr(Location, IsLocationVolatile, IsInit));
else {
RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
LValue LV = MakeAddrLValue(Location, E->getType());
}
// Create a reference temporary if necessary.
+ AggValueSlot AggSlot = AggValueSlot::ignored();
if (CGF.hasAggregateLLVMType(E->getType()) &&
- !E->getType()->isAnyComplexType())
+ !E->getType()->isAnyComplexType()) {
ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
InitializedDecl);
+ AggSlot = AggValueSlot::forAddr(ReferenceTemporary, false,
+ InitializedDecl != 0);
+ }
- RV = CGF.EmitAnyExpr(E, ReferenceTemporary, /*IsAggLocVolatile=*/false,
- /*IgnoreResult=*/false, InitializedDecl);
+ RV = CGF.EmitAnyExpr(E, AggSlot);
if (InitializedDecl) {
// Get the destructor for the reference temporary.
const Expr *InitExpr = E->getInitializer();
LValue Result = MakeAddrLValue(DeclPtr, E->getType());
- EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false);
+ EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false, /*Init*/ true);
return Result;
}
}
LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
- llvm::Value *Temp = CreateMemTemp(E->getType(), "tmp");
- EmitCXXConstructExpr(Temp, E);
- return MakeAddrLValue(Temp, E->getType());
+ AggValueSlot Slot = CreateAggTemp(E->getType(), "tmp");
+ EmitCXXConstructExpr(E, Slot);
+ return MakeAddrLValue(Slot.getAddr(), E->getType());
}
LValue
class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
- llvm::Value *DestPtr;
- bool VolatileDest;
+ AggValueSlot Dest;
bool IgnoreResult;
- bool IsInitializer;
bool RequiresGCollection;
ReturnValueSlot getReturnValueSlot() const {
// API.
if (RequiresGCollection) return ReturnValueSlot();
- return ReturnValueSlot(DestPtr, VolatileDest);
+ return ReturnValueSlot(Dest.getAddr(), Dest.isVolatile());
+ }
+
+ AggValueSlot EnsureSlot(QualType T) {
+ if (!Dest.isIgnored()) return Dest;
+ return CGF.CreateAggTemp(T, "agg.tmp.ensured");
}
public:
- AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool v,
- bool ignore, bool isinit, bool requiresGCollection)
- : CGF(cgf), Builder(CGF.Builder),
- DestPtr(destPtr), VolatileDest(v), IgnoreResult(ignore),
- IsInitializer(isinit), RequiresGCollection(requiresGCollection) {
+ AggExprEmitter(CodeGenFunction &cgf, AggValueSlot Dest,
+ bool ignore, bool requiresGCollection)
+ : CGF(cgf), Builder(CGF.Builder), Dest(Dest),
+ IgnoreResult(ignore), RequiresGCollection(requiresGCollection) {
}
//===--------------------------------------------------------------------===//
unsigned long size = TypeInfo.first/8;
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size);
- CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, DestPtr,
+ CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, Dest.getAddr(),
Src.getAggregateAddr(),
SizeVal);
}
void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
assert(Src.isAggregate() && "value must be aggregate value!");
- // If DestPtr is null, then we're evaluating an aggregate expression
+ // If Dest is ignored, then we're evaluating an aggregate expression
// in a context (like an expression statement) that doesn't care
// about the result. C says that an lvalue-to-rvalue conversion is
// performed in these cases; C++ says that it is not. In either
// case, we don't actually need to do anything unless the value is
// volatile.
- if (DestPtr == 0) {
+ if (Dest.isIgnored()) {
if (!Src.isVolatileQualified() ||
CGF.CGM.getLangOptions().CPlusPlus ||
(IgnoreResult && Ignore))
// If the source is volatile, we must read from it; to do that, we need
// some place to put it.
- DestPtr = CGF.CreateMemTemp(E->getType(), "agg.tmp");
+ Dest = CGF.CreateAggTemp(E->getType(), "agg.tmp");
}
if (RequiresGCollection) {
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size);
CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF,
- DestPtr, Src.getAggregateAddr(),
- SizeVal);
+ Dest.getAddr(),
+ Src.getAggregateAddr(),
+ SizeVal);
return;
}
// If the result of the assignment is used, copy the LHS there also.
// FIXME: Pass VolatileDest as well. I think we also need to merge volatile
// from the source as well, as we can't eliminate it if either operand
// is volatile, unless copy has volatile for both source and destination..
- CGF.EmitAggregateCopy(DestPtr, Src.getAggregateAddr(), E->getType(),
- VolatileDest|Src.isVolatileQualified());
+ CGF.EmitAggregateCopy(Dest.getAddr(), Src.getAggregateAddr(), E->getType(),
+ Dest.isVolatile()|Src.isVolatileQualified());
}
/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
//===----------------------------------------------------------------------===//
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
- if (!DestPtr && E->getCastKind() != CK_Dynamic) {
+ if (Dest.isIgnored() && E->getCastKind() != CK_Dynamic) {
Visit(E->getSubExpr());
return;
}
else
CGF.CGM.ErrorUnsupported(E, "non-simple lvalue dynamic_cast");
- if (DestPtr)
- CGF.CGM.ErrorUnsupported(E, "lvalue dynamic_cast with a destination");
+ if (!Dest.isIgnored())
+ CGF.CGM.ErrorUnsupported(E, "lvalue dynamic_cast with a destination");
break;
}
// GCC union extension
QualType Ty = E->getSubExpr()->getType();
QualType PtrTy = CGF.getContext().getPointerType(Ty);
- llvm::Value *CastPtr = Builder.CreateBitCast(DestPtr,
+ llvm::Value *CastPtr = Builder.CreateBitCast(Dest.getAddr(),
CGF.ConvertType(PtrTy));
EmitInitializationToLValue(E->getSubExpr(), CGF.MakeAddrLValue(CastPtr, Ty),
Ty);
}
void AggExprEmitter::VisitBinComma(const BinaryOperator *E) {
- CGF.EmitAnyExpr(E->getLHS(), 0, false, true);
- CGF.EmitAggExpr(E->getRHS(), DestPtr, VolatileDest,
- /*IgnoreResult=*/false, IsInitializer);
+ CGF.EmitAnyExpr(E->getLHS(), AggValueSlot::ignored(), true);
+ Visit(E->getRHS());
}
void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
- CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest);
+ CGF.EmitCompoundStmt(*E->getSubStmt(), true, Dest);
}
void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
// We have to special case property setters, otherwise we must have
// a simple lvalue (no aggregates inside vectors, bitfields).
if (LHS.isPropertyRef()) {
- llvm::Value *AggLoc = DestPtr;
- if (!AggLoc)
- AggLoc = CGF.CreateMemTemp(E->getRHS()->getType());
- CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest);
- CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(),
- RValue::getAggregate(AggLoc, VolatileDest));
+ AggValueSlot Slot = EnsureSlot(E->getRHS()->getType());
+ CGF.EmitAggExpr(E->getRHS(), Slot);
+ CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), Slot.asRValue());
} else if (LHS.isKVCRef()) {
- llvm::Value *AggLoc = DestPtr;
- if (!AggLoc)
- AggLoc = CGF.CreateMemTemp(E->getRHS()->getType());
- CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest);
- CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(),
- RValue::getAggregate(AggLoc, VolatileDest));
+ AggValueSlot Slot = EnsureSlot(E->getRHS()->getType());
+ CGF.EmitAggExpr(E->getRHS(), Slot);
+ CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(), Slot.asRValue());
} else {
bool RequiresGCollection = false;
if (CGF.getContext().getLangOptions().getGCMode())
RequiresGCollection = TypeRequiresGCollection(E->getLHS()->getType());
// Codegen the RHS so that it stores directly into the LHS.
- CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), LHS.isVolatileQualified(),
- false, false, RequiresGCollection);
+ AggValueSlot LHSSlot = AggValueSlot::forLValue(LHS, true);
+ CGF.EmitAggExpr(E->getRHS(), LHSSlot, false, RequiresGCollection);
EmitFinalDestCopy(E, LHS, true);
}
}
}
void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
- llvm::Value *Val = DestPtr;
-
- if (!Val) {
- // Create a temporary variable.
- Val = CGF.CreateMemTemp(E->getType(), "tmp");
-
- // FIXME: volatile
- CGF.EmitAggExpr(E->getSubExpr(), Val, false);
- } else
- Visit(E->getSubExpr());
-
- // Don't make this a live temporary if we're emitting an initializer expr.
- if (!IsInitializer)
- CGF.EmitCXXTemporary(E->getTemporary(), Val);
+ // Ensure that we have a slot, but if we already do, remember
+ // whether its lifetime was externally managed.
+ bool WasManaged = Dest.isLifetimeExternallyManaged();
+ Dest = EnsureSlot(E->getType());
+ Dest.setLifetimeExternallyManaged();
+
+ Visit(E->getSubExpr());
+
+ // Set up the temporary's destructor if its lifetime wasn't already
+ // being managed.
+ if (!WasManaged)
+ CGF.EmitCXXTemporary(E->getTemporary(), Dest.getAddr());
}
void
AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
- llvm::Value *Val = DestPtr;
-
- if (!Val) // Create a temporary variable.
- Val = CGF.CreateMemTemp(E->getType(), "tmp");
-
- CGF.EmitCXXConstructExpr(Val, E);
+ AggValueSlot Slot = EnsureSlot(E->getType());
+ CGF.EmitCXXConstructExpr(E, Slot);
}
void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
- llvm::Value *Val = DestPtr;
-
- CGF.EmitCXXExprWithTemporaries(E, Val, VolatileDest, IsInitializer);
+ CGF.EmitCXXExprWithTemporaries(E, Dest);
}
void AggExprEmitter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
- llvm::Value *Val = DestPtr;
-
- if (!Val) {
- // Create a temporary variable.
- Val = CGF.CreateMemTemp(E->getType(), "tmp");
- }
- EmitNullInitializationToLValue(CGF.MakeAddrLValue(Val, E->getType()),
- E->getType());
+ QualType T = E->getType();
+ AggValueSlot Slot = EnsureSlot(T);
+ EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddr(), T), T);
}
void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
- llvm::Value *Val = DestPtr;
-
- if (!Val) {
- // Create a temporary variable.
- Val = CGF.CreateMemTemp(E->getType(), "tmp");
- }
- EmitNullInitializationToLValue(CGF.MakeAddrLValue(Val, E->getType()),
- E->getType());
+ QualType T = E->getType();
+ AggValueSlot Slot = EnsureSlot(T);
+ EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddr(), T), T);
}
void
} else if (T->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
} else if (CGF.hasAggregateLLVMType(T)) {
- CGF.EmitAnyExpr(E, LV.getAddress(), false);
+ CGF.EmitAggExpr(E, AggValueSlot::forAddr(LV.getAddress(), false, true));
} else {
CGF.EmitStoreThroughLValue(CGF.EmitAnyExpr(E), LV, T);
}
if (E->hadArrayRangeDesignator())
CGF.ErrorUnsupported(E, "GNU array range designator extension");
+ llvm::Value *DestPtr = Dest.getAddr();
+
// Handle initialization of an array.
if (E->getType()->isArrayType()) {
const llvm::PointerType *APType =
/// type. The result is computed into DestPtr. Note that if DestPtr is null,
/// the value of the aggregate expression is not needed. If VolatileDest is
/// true, DestPtr cannot be 0.
+///
+/// \param IsInitializer - true if this evaluation is initializing an
+/// object whose lifetime is already being managed.
//
// FIXME: Take Qualifiers object.
-void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr,
- bool VolatileDest, bool IgnoreResult,
- bool IsInitializer,
+void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot,
+ bool IgnoreResult,
bool RequiresGCollection) {
assert(E && hasAggregateLLVMType(E->getType()) &&
"Invalid aggregate expression to emit");
- assert ((DestPtr != 0 || VolatileDest == false)
- && "volatile aggregate can't be 0");
+ assert((Slot.getAddr() != 0 || Slot.isIgnored())
+ && "slot has bits but no address");
- AggExprEmitter(*this, DestPtr, VolatileDest, IgnoreResult, IsInitializer,
- RequiresGCollection)
+ AggExprEmitter(*this, Slot, IgnoreResult, RequiresGCollection)
.Visit(const_cast<Expr*>(E));
}
assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!");
llvm::Value *Temp = CreateMemTemp(E->getType());
LValue LV = MakeAddrLValue(Temp, E->getType());
- EmitAggExpr(E, Temp, LV.isVolatileQualified());
+ AggValueSlot Slot
+ = AggValueSlot::forAddr(Temp, LV.isVolatileQualified(), false);
+ EmitAggExpr(E, Slot);
return LV;
}
LValue LV = EmitLValue(E->getArg(0));
llvm::Value *This;
if (LV.isPropertyRef() || LV.isKVCRef()) {
- llvm::Value *AggLoc = CreateMemTemp(E->getArg(1)->getType());
- EmitAggExpr(E->getArg(1), AggLoc, false /*VolatileDest*/);
+ AggValueSlot Slot = CreateAggTemp(E->getArg(1)->getType());
+ EmitAggExpr(E->getArg(1), Slot);
if (LV.isPropertyRef())
- EmitObjCPropertySet(LV.getPropertyRefExpr(),
- RValue::getAggregate(AggLoc,
- false /*VolatileDest*/));
+ EmitObjCPropertySet(LV.getPropertyRefExpr(), Slot.asRValue());
else
- EmitObjCPropertySet(LV.getKVCRefExpr(),
- RValue::getAggregate(AggLoc,
- false /*VolatileDest*/));
+ EmitObjCPropertySet(LV.getKVCRefExpr(), Slot.asRValue());
return RValue::getAggregate(0, false);
}
else
}
void
-CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
- const CXXConstructExpr *E) {
- assert(Dest && "Must have a destination!");
+CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
+ AggValueSlot Dest) {
+ assert(!Dest.isIgnored() && "Must have a destination!");
const CXXConstructorDecl *CD = E->getConstructor();
// If we require zero initialization before (or instead of) calling the
// constructor, as can be the case with a non-user-provided default
// constructor, emit the zero initialization now.
if (E->requiresZeroInitialization())
- EmitNullInitialization(Dest, E->getType());
-
+ EmitNullInitialization(Dest.getAddr(), E->getType());
// If this is a call to a trivial default constructor, do nothing.
if (CD->isTrivial() && CD->isDefaultConstructor())
// its first argument instead, if in fact that argument is a temporary
// object.
if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
- if (const Expr *Arg = E->getArg(0)->getTemporaryObject()) {
- EmitAggExpr(Arg, Dest, false);
+ if (E->getArg(0)->isTemporaryObject(getContext(), CD->getParent())) {
+ EmitAggExpr(E->getArg(0), Dest);
return;
}
}
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(Dest, BasePtr);
+ Builder.CreateBitCast(Dest.getAddr(), BasePtr);
EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
E->arg_begin(), E->arg_end());
E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase;
// Call the constructor.
- EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest,
+ EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest.getAddr(),
E->arg_begin(), E->arg_end());
}
}
else if (AllocType->isAnyComplexType())
CGF.EmitComplexExprIntoAddr(Init, NewPtr,
AllocType.isVolatileQualified());
- else
- CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified());
+ else {
+ AggValueSlot Slot
+ = AggValueSlot::forAddr(NewPtr, AllocType.isVolatileQualified(), true);
+ CGF.EmitAggExpr(Init, Slot);
+ }
}
void
CGF.EmitLoadOfKVCRefLValue(LV, E->getType());
}
else
- CGF.EmitAnyExpr(E, 0, false, true);
+ CGF.EmitAnyExpr(E, AggValueSlot::ignored(), true);
return 0;
}
case CK_VectorSplat: {
// Okay, this is a cast from an aggregate. It must be a cast to void. Just
// evaluate the result and return.
- CGF.EmitAggExpr(E, 0, false, true);
+ CGF.EmitAggExpr(E, AggValueSlot::ignored(), true);
return 0;
}
FunctionType::ExtInfo()),
GetCopyStructFn, ReturnValueSlot(), Args);
} else if (PID->getSetterCXXAssignment()) {
- EmitAnyExpr(PID->getSetterCXXAssignment(), (llvm::Value *)0, false, true,
- false);
+ EmitAnyExpr(PID->getSetterCXXAssignment(), AggValueSlot::ignored(), true);
} else {
// FIXME: Find a clean way to avoid AST node creation.
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
LoadObjCSelf(), Ivar, 0);
- EmitAggExpr(IvarInit->getInit(), LV.getAddress(),
- LV.isVolatileQualified(), false, true);
+ EmitAggExpr(IvarInit->getInit(), AggValueSlot::forLValue(LV, true));
}
// constructor returns 'self'.
CodeGenTypes &Types = CGM.getTypes();
if (!isa<Expr>(S))
ErrorUnsupported(S, "statement");
- EmitAnyExpr(cast<Expr>(S), 0, false, true);
+ EmitAnyExpr(cast<Expr>(S), AggValueSlot::ignored(), true);
// Expression emitters don't handle unreachable blocks yet, so look for one
// explicitly here. This handles the common case of a call to a noreturn
/// this captures the expression result of the last sub-statement and returns it
/// (for use by the statement expression extension).
RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
- llvm::Value *AggLoc, bool isAggVol) {
+ AggValueSlot AggSlot) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),S.getLBracLoc(),
"LLVM IR generation of compound statement ('{}')");
EnsureInsertPoint();
- RV = EmitAnyExpr(cast<Expr>(LastStmt), AggLoc);
+ RV = EmitAnyExpr(cast<Expr>(LastStmt), AggSlot);
}
return RV;
} else if (RV->getType()->isAnyComplexType()) {
EmitComplexExprIntoAddr(RV, ReturnValue, false);
} else {
- EmitAggExpr(RV, ReturnValue, false);
+ EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, false, true));
}
EmitBranchThroughCleanup(ReturnBlock);
RValue
CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
- llvm::Value *AggLoc,
- bool IsAggLocVolatile,
- bool IsInitializer) {
+ AggValueSlot Slot) {
RunCleanupsScope Scope(*this);
- return EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile,
- /*IgnoreResult=*/false, IsInitializer);
+ return EmitAnyExpr(E->getSubExpr(), Slot);
}
LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue(
}
};
+/// An aggregate value slot.
+class AggValueSlot {
+ /// The address and associated flags.
+ uintptr_t AddrAndFlags;
+
+ static const uintptr_t VolatileFlag = 0x1;
+ static const uintptr_t LifetimeFlag = 0x2;
+ static const uintptr_t AddrMask = ~(VolatileFlag | LifetimeFlag);
+
+public:
+ /// ignored - Returns an aggregate value slot indicating that the
+ /// aggregate value is being ignored.
+ static AggValueSlot ignored() {
+ AggValueSlot AV;
+ AV.AddrAndFlags = 0;
+ return AV;
+ }
+
+ /// forAddr - Make a slot for an aggregate value.
+ ///
+ /// \param Volatile - true if the slot should be volatile-initialized
+ /// \param LifetimeExternallyManaged - true if the slot's lifetime
+ /// is being externally managed; false if a destructor should be
+ /// registered for any temporaries evaluated into the slot
+ static AggValueSlot forAddr(llvm::Value *Addr, bool Volatile,
+ bool LifetimeExternallyManaged) {
+ AggValueSlot AV;
+ AV.AddrAndFlags = reinterpret_cast<uintptr_t>(Addr);
+ if (Volatile) AV.AddrAndFlags |= VolatileFlag;
+ if (LifetimeExternallyManaged) AV.AddrAndFlags |= LifetimeFlag;
+ return AV;
+ }
+
+ static AggValueSlot forLValue(LValue LV, bool LifetimeExternallyManaged) {
+ return forAddr(LV.getAddress(), LV.isVolatileQualified(),
+ LifetimeExternallyManaged);
+ }
+
+ bool isLifetimeExternallyManaged() const {
+ return AddrAndFlags & LifetimeFlag;
+ }
+ void setLifetimeExternallyManaged() {
+ AddrAndFlags |= LifetimeFlag;
+ }
+
+ bool isVolatile() const {
+ return AddrAndFlags & VolatileFlag;
+ }
+
+ llvm::Value *getAddr() const {
+ return reinterpret_cast<llvm::Value*>(AddrAndFlags & AddrMask);
+ }
+
+ bool isIgnored() const {
+ return AddrAndFlags == 0;
+ }
+
+ RValue asRValue() const {
+ return RValue::getAggregate(getAddr(), isVolatile());
+ }
+
+};
+
} // end namespace CodeGen
} // end namespace clang
/// appropriate alignment.
llvm::AllocaInst *CreateMemTemp(QualType T, const llvm::Twine &Name = "tmp");
+ /// CreateAggTemp - Create a temporary memory object for the given
+ /// aggregate type.
+ AggValueSlot CreateAggTemp(QualType T, const llvm::Twine &Name = "tmp") {
+ return AggValueSlot::forAddr(CreateMemTemp(T, Name), false, false);
+ }
+
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
/// expression and compare the result against zero, returning an Int1Ty value.
llvm::Value *EvaluateExprAsBool(const Expr *E);
/// the result should be returned.
///
/// \param IgnoreResult - True if the resulting value isn't used.
- RValue EmitAnyExpr(const Expr *E, llvm::Value *AggLoc = 0,
- bool IsAggLocVolatile = false, bool IgnoreResult = false,
- bool IsInitializer = false);
+ RValue EmitAnyExpr(const Expr *E,
+ AggValueSlot AggSlot = AggValueSlot::ignored(),
+ bool IgnoreResult = false);
// EmitVAListRef - Emit a "reference" to a va_list; this is either the address
// or the value of the expression, depending on how va_list is defined.
/// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will
/// always be accessible even if no aggregate location is provided.
- RValue EmitAnyExprToTemp(const Expr *E, bool IsAggLocVolatile = false,
- bool IsInitializer = false);
+ RValue EmitAnyExprToTemp(const Expr *E);
/// EmitsAnyExprToMem - Emits the code necessary to evaluate an
/// arbitrary expression into the given memory location.
void EmitAnyExprToMem(const Expr *E, llvm::Value *Location,
- bool IsLocationVolatile = false,
- bool IsInitializer = false);
+ bool IsLocationVolatile,
+ bool IsInitializer);
/// EmitAggregateCopy - Emit an aggrate copy.
///
bool EmitSimpleStmt(const Stmt *S);
RValue EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
- llvm::Value *AggLoc = 0, bool isAggVol = false);
+ AggValueSlot AVS = AggValueSlot::ignored());
/// EmitLabel - Emit the block for the given label. It is legal to call this
/// function even if there is no current insertion point.
QualType DstTy);
- /// EmitAggExpr - Emit the computation of the specified expression of
- /// aggregate type. The result is computed into DestPtr. Note that if
- /// DestPtr is null, the value of the aggregate expression is not needed.
- void EmitAggExpr(const Expr *E, llvm::Value *DestPtr, bool VolatileDest,
- bool IgnoreResult = false, bool IsInitializer = false,
+ /// EmitAggExpr - Emit the computation of the specified expression
+ /// of aggregate type. The result is computed into the given slot,
+ /// which may be null to indicate that the value is not needed.
+ void EmitAggExpr(const Expr *E, AggValueSlot AS, bool IgnoreResult = false,
bool RequiresGCollection = false);
/// EmitAggExprToLValue - Emit the computation of the specified expression of
void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D);
- void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);
+ void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest);
RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
- llvm::Value *AggLoc = 0,
- bool IsAggLocVolatile = false,
- bool IsInitializer = false);
+ AggValueSlot Slot
+ = AggValueSlot::ignored());
void EmitCXXThrowExpr(const CXXThrowExpr *E);
// with the same cv-unqualified type, the copy/move operation
// can be omitted by constructing the temporary object
// directly into the target of the omitted copy/move
- if (Constructor->isCopyConstructor() && ExprArgs.size() >= 1) {
+ if (ConstructKind == CXXConstructExpr::CK_Complete &&
+ Constructor->isCopyConstructor() && ExprArgs.size() >= 1) {
Expr *SubExpr = ((Expr **)ExprArgs.get())[0];
- Elidable = SubExpr->isTemporaryObject() &&
- ConstructKind == CXXConstructExpr::CK_Complete &&
- Context.hasSameUnqualifiedType(SubExpr->getType(),
- Context.getTypeDeclType(Constructor->getParent()));
+ Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent());
}
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
// elision for return statements and throw expressions are handled as part
// of constructor initialization, while copy elision for exception handlers
// is handled by the run-time.
- bool Elidable = CurInitExpr->isTemporaryObject() &&
- S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType());
+ bool Elidable = CurInitExpr->isTemporaryObject(S.Context, Class);
SourceLocation Loc;
switch (Entity.getKind()) {
case InitializedEntity::EK_Result:
// CHECK-NEXT: ret void
}
}
+
+namespace Elision {
+ struct A { A(); A(const A &); ~A(); void *p; };
+
+ void foo();
+ A fooA();
+
+ // CHECK: define void @_ZN7Elision5test0Ev()
+ void test0() {
+ // CHECK: [[I:%.*]] = alloca [[A:%.*]], align 8
+ // CHECK-NEXT: [[J:%.*]] = alloca [[A:%.*]], align 8
+ // CHECK-NEXT: [[T0:%.*]] = alloca [[A:%.*]], align 8
+ // CHECK-NEXT: [[K:%.*]] = alloca [[A:%.*]], align 8
+ // CHECK-NEXT: [[T1:%.*]] = alloca [[A:%.*]], align 8
+
+ // CHECK-NEXT: call void @_ZN7Elision3fooEv()
+ // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[I]])
+ A i = (foo(), A());
+
+ // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret [[T0]])
+ // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[J]])
+ // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T0]])
+ A j = (fooA(), A());
+
+ // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[T1]])
+ // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret [[K]])
+ // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T1]])
+ A k = (A(), fooA());
+
+ // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[K]])
+ // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[J]])
+ // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[I]])
+ }
+
+
+ // CHECK: define void @_ZN7Elision5test1EbNS_1AE(
+ void test1(bool c, A x) {
+ // CHECK: [[I:%.*]] = alloca [[A:%.*]], align 8
+ // CHECK-NEXT: [[J:%.*]] = alloca [[A:%.*]], align 8
+
+ // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[I]])
+ // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[I]], [[A]]* [[X:%.*]])
+ A i = (c ? A() : x);
+
+ // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[J]], [[A]]* [[X]])
+ // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[J]])
+ A j = (c ? x : A());
+
+ // CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[J]])
+ // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[I]])
+ }
+
+ // CHECK: define void @_ZN7Elision5test2Ev([[A]]* sret
+ A test2() {
+ // CHECK: call void @_ZN7Elision3fooEv()
+ // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]])
+ // CHECK-NEXT: ret void
+ return (foo(), A());
+ }
+
+ // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* sret
+ A test3(int v, A x) {
+ if (v < 5)
+ // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]])
+ // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[RET]], [[A]]* [[X:%.*]])
+ return (v < 0 ? A() : x);
+ else
+ // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[RET]], [[A]]* [[X]])
+ // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[RET]])
+ return (v > 10 ? x : A());
+
+ // CHECK: ret void
+ }
+
+ // CHECK: define void @_ZN7Elision5test4Ev()
+ void test4() {
+ // CHECK: [[X:%.*]] = alloca [[A]], align 8
+ // CHECK-NEXT: [[XS:%.*]] = alloca [2 x [[A]]], align 16
+ // CHECK-NEXT: [[I:%.*]] = alloca i64
+
+ // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[X]])
+ A x;
+
+ // CHECK-NEXT: [[XS0:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 0
+ // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[XS0]])
+ // CHECK-NEXT: [[XS1:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 1
+ // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[XS1]], [[A]]* [[X]])
+ // CHECK-NEXT: [[XSB:%.*]] = bitcast [2 x [[A]]]* [[XS]] to [[A]]*
+ A xs[] = { A(), x };
+
+ // CHECK-NEXT: store i64 2, i64* [[I]]
+ // CHECK-NEXT: br label
+ // CHECK: [[I0:%.*]] = load i64* [[I]]
+ // CHECK-NEXT: icmp ne i64 [[I0]], 0
+ // CHECK-NEXT: br i1
+ // CHECK: [[I1:%.*]] = load i64* [[I]]
+ // CHECK-NEXT: [[I2:%.*]] = sub i64 [[I1]], 1
+ // CHECK-NEXT: [[XSI:%.*]] = getelementptr inbounds [[A]]* [[XSB]], i64 [[I2]]
+ // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[XSI]])
+ // CHECK-NEXT: br label
+
+ // CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[X]])
+ }
+}
A e = A(A());
A f = A(a); // expected-warning {{global constructor}}
A g(a); // expected-warning {{global constructor}}
- A h((A())); // expected-warning {{global constructor}}
- A i((A(A()))); // expected-warning {{global constructor}}
+ A h((A())); // elided
+ A i((A(A()))); // elided
}
namespace test2 {