diff options
-rw-r--r-- | include/clang/AST/Expr.h | 11 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 55 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 12 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGDeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGException.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 45 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 157 | ||||
-rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 36 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 8 | ||||
-rw-r--r-- | lib/CodeGen/CGTemporaries.cpp | 7 | ||||
-rw-r--r-- | lib/CodeGen/CGValue.h | 63 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 37 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 3 | ||||
-rw-r--r-- | test/CodeGenCXX/temporaries.cpp | 104 | ||||
-rw-r--r-- | test/SemaCXX/warn-global-constructors.cpp | 4 |
20 files changed, 346 insertions, 222 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 4cf2d17076..7a9dd2cde0 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -450,14 +450,9 @@ public: /// 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(); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index c9dae17f80..4e65b9c339 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1648,46 +1648,31 @@ static const Expr *skipTemporaryBindingsAndNoOpCasts(const Expr *E) { 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 diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index d4e703ce03..35a2ada974 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -352,7 +352,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { 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]; diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index bf26799b83..a6ac0acfb9 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -362,7 +362,9 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, 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, @@ -388,11 +390,11 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF, 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; } diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 965400135e..b743c0c6b4 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -761,7 +761,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D, } else if (Init->getType()->isAnyComplexType()) { EmitComplexExprIntoAddr(Init, Loc, isVolatile); } else { - EmitAggExpr(Init, Loc, isVolatile); + EmitAggExpr(Init, AggValueSlot::forAddr(Loc, isVolatile, true)); } } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 565c865c34..1b42f6189e 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -38,7 +38,7 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, } else if (T->isAnyComplexType()) { CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); } else { - CGF.EmitAggExpr(Init, DeclPtr, isVolatile); + CGF.EmitAggExpr(Init, AggValueSlot::forAddr(DeclPtr, isVolatile, true)); } } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 7fb616e5a1..1063e28b84 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -457,7 +457,7 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E, // 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); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index bb0462f963..9c1a3cf249 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -78,35 +78,31 @@ llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { 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 @@ -118,7 +114,7 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E, 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()); @@ -247,13 +243,16 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, } // 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. @@ -1673,7 +1672,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){ 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; } @@ -1965,9 +1964,9 @@ LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { } 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 diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index f1bc692cf4..9ed20f382e 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -32,10 +32,8 @@ namespace { 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 { @@ -44,15 +42,19 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { // 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) { } //===--------------------------------------------------------------------===// @@ -182,7 +184,7 @@ void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) { 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); } @@ -192,13 +194,13 @@ void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) { 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)) @@ -206,7 +208,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool 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) { @@ -216,16 +218,17 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { 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. @@ -242,7 +245,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) { //===----------------------------------------------------------------------===// void AggExprEmitter::VisitCastExpr(CastExpr *E) { - if (!DestPtr && E->getCastKind() != CK_Dynamic) { + if (Dest.isIgnored() && E->getCastKind() != CK_Dynamic) { Visit(E->getSubExpr()); return; } @@ -259,8 +262,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { 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; } @@ -268,7 +271,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { // 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); @@ -327,13 +330,12 @@ void AggExprEmitter::VisitObjCImplicitSetterGetterRefExpr( } 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) { @@ -360,27 +362,21 @@ void AggExprEmitter::VisitBinAssign(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); } } @@ -434,58 +430,40 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { } 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 @@ -500,7 +478,7 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV, QualType T) { } 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); } @@ -537,6 +515,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { 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 = @@ -660,19 +640,20 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { /// 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)); } @@ -680,7 +661,9 @@ LValue CodeGenFunction::EmitAggExprToLValue(const 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; } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 10e29d199c..584f6c099b 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -219,16 +219,12 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, 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 @@ -269,17 +265,16 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, } 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()) @@ -289,8 +284,8 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, // 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; } } @@ -302,7 +297,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, 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()); @@ -315,7 +310,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, 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()); } } @@ -539,8 +534,11 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E, 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 diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 45c5fb9f0b..d4b1bd940c 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1063,7 +1063,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { CGF.EmitLoadOfKVCRefLValue(LV, E->getType()); } else - CGF.EmitAnyExpr(E, 0, false, true); + CGF.EmitAnyExpr(E, AggValueSlot::ignored(), true); return 0; } case CK_VectorSplat: { @@ -1127,7 +1127,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { // 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; } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 5b0c2630a0..8abcbea5d0 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -386,8 +386,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, 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. @@ -438,8 +437,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, 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(); diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 16145f766a..a70534d2ca 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -75,7 +75,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { 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 @@ -146,7 +146,7 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) { /// 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 ('{}')"); @@ -184,7 +184,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, EnsureInsertPoint(); - RV = EmitAnyExpr(cast<Expr>(LastStmt), AggLoc); + RV = EmitAnyExpr(cast<Expr>(LastStmt), AggSlot); } return RV; @@ -643,7 +643,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { } else if (RV->getType()->isAnyComplexType()) { EmitComplexExprIntoAddr(RV, ReturnValue, false); } else { - EmitAggExpr(RV, ReturnValue, false); + EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, false, true)); } EmitBranchThroughCleanup(ReturnBlock); diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp index dfb8dc63c5..ba01b72e54 100644 --- a/lib/CodeGen/CGTemporaries.cpp +++ b/lib/CodeGen/CGTemporaries.cpp @@ -77,12 +77,9 @@ void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary, 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( diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index f57ecd245f..42b8335ecd 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -321,6 +321,69 @@ public: } }; +/// 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 diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 715be3ce17..d19827bf4f 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1024,6 +1024,12 @@ public: /// 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); @@ -1034,9 +1040,9 @@ public: /// 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. @@ -1044,14 +1050,13 @@ public: /// 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. /// @@ -1254,7 +1259,7 @@ public: 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. @@ -1543,11 +1548,10 @@ public: 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 @@ -1617,12 +1621,11 @@ public: 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); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index d16d9e9763..0580392689 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5462,12 +5462,10 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, // 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, diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 60d2acec07..1ffa70207a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -3303,8 +3303,7 @@ static ExprResult CopyObject(Sema &S, // 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: diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp index 9a397abfc0..b6b8b26ed3 100644 --- a/test/CodeGenCXX/temporaries.cpp +++ b/test/CodeGenCXX/temporaries.cpp @@ -338,3 +338,107 @@ namespace PR7556 { // 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]]) + } +} diff --git a/test/SemaCXX/warn-global-constructors.cpp b/test/SemaCXX/warn-global-constructors.cpp index e14117eaf3..0391f5ba3d 100644 --- a/test/SemaCXX/warn-global-constructors.cpp +++ b/test/SemaCXX/warn-global-constructors.cpp @@ -25,8 +25,8 @@ namespace test1 { 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 { |