diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index e44ccca0bd74..f9f5da129142 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1023,17 +1023,16 @@ class CXXExprWithTemporaries : public Expr { CXXTemporary **Temps; unsigned NumTemps; - bool DestroyTemps; + bool ShouldDestroyTemps; CXXExprWithTemporaries(Expr *SubExpr, CXXTemporary **Temps, - unsigned NumTemps, bool DestroyTemps); + unsigned NumTemps, bool ShouldDestroyTemps); ~CXXExprWithTemporaries(); public: static CXXExprWithTemporaries *Create(ASTContext &C, Expr *SubExpr, - CXXTemporary **Temps, - unsigned NumTemps, - bool DestroyTems); + CXXTemporary **Temps, unsigned NumTemps, + bool ShouldDestroyTemporaries); void Destroy(ASTContext &C); unsigned getNumTemporaries() const { return NumTemps; } @@ -1046,6 +1045,8 @@ public: return Temps[i]; } + bool shouldDestroyTemporaries() const { return ShouldDestroyTemps; } + void removeLastTemporary() { NumTemps--; } Expr *getSubExpr() { return cast(SubExpr); } diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 8fd66a29817d..18c0f77ab29e 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -306,10 +306,11 @@ void CXXConstructExpr::Destroy(ASTContext &C) { CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, CXXTemporary **temps, unsigned numtemps, - bool destroytemps) + bool shoulddestroytemps) : Expr(CXXExprWithTemporariesClass, subexpr->getType(), subexpr->isTypeDependent(), subexpr->isValueDependent()), - SubExpr(subexpr), Temps(0), NumTemps(numtemps), DestroyTemps(destroytemps) { + SubExpr(subexpr), Temps(0), NumTemps(numtemps), + ShouldDestroyTemps(shoulddestroytemps) { if (NumTemps > 0) { Temps = new CXXTemporary*[NumTemps]; for (unsigned i = 0; i < NumTemps; ++i) @@ -321,9 +322,9 @@ CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps, unsigned NumTemps, - bool DestroyTemps) { + bool ShouldDestroyTemps){ return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps, - DestroyTemps); + ShouldDestroyTemps); } void CXXExprWithTemporaries::Destroy(ASTContext &C) { diff --git a/clang/lib/CodeGen/CGCXXTemp.cpp b/clang/lib/CodeGen/CGCXXTemp.cpp index 141726a649cf..a6e6d11505b6 100644 --- a/clang/lib/CodeGen/CGCXXTemp.cpp +++ b/clang/lib/CodeGen/CGCXXTemp.cpp @@ -85,6 +85,11 @@ RValue CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, llvm::Value *AggLoc, bool isAggLocVolatile) { + // If we shouldn't destroy the temporaries, just emit the + // child expression. + if (!E->shouldDestroyTemporaries()) + return EmitAnyExpr(E->getSubExpr(), AggLoc, isAggLocVolatile); + // Keep track of the current cleanup stack depth. size_t CleanupStackDepth = CleanupEntries.size(); (void) CleanupStackDepth; diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 34513e7d588c..28fb918fefad 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1661,8 +1661,8 @@ public: /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is /// non-empty, will create a new CXXExprWithTemporaries expression. /// Otherwise, just returs the passed in expression. - Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, - bool DestroyTemps = true); + Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, + bool ShouldDestroyTemporaries); virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 8f64e78c522b..70057a34dfb4 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -147,8 +147,11 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, return; } + DefaultArgPtr = MaybeCreateCXXExprWithTemporaries(DefaultArg.take(), + /*DestroyTemps=*/false); + // Okay: add the default argument to the parameter - Param->setDefaultArg(DefaultArg.take()); + Param->setDefaultArg(DefaultArgPtr); } /// ActOnParamUnparsedDefaultArgument - We've seen a default diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c01c812be601..c0469416e422 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2491,8 +2491,21 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FDecl << cast(FDecl->getDeclContext())->getDeclName(); Diag(UnparsedDefaultArgLocs[FDecl->getParamDecl(i)], diag::note_default_argument_declared_here); + } else { + Expr *DefaultExpr = FDecl->getParamDecl(i)->getDefaultArg(); + + // If the default expression creates temporaries, we need to + // push them to the current stack of expression temporaries so they'll + // be properly destroyed. + if (CXXExprWithTemporaries *E + = dyn_cast_or_null(DefaultExpr)) { + assert(!E->shouldDestroyTemporaries() && + "Can't destroy temporaries in a default argument expr!"); + for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) + ExprTemporaries.push_back(E->getTemporary(I)); + } } - + // We already type-checked the argument, so we know it works. Arg = new (Context) CXXDefaultArgExpr(FDecl->getParamDecl(i)); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index ed4ac555add9..7353efbae7df 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1589,7 +1589,7 @@ Expr *Sema::RemoveOutermostTemporaryBinding(Expr *E) { } Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, - bool DestroyTemps) { + bool ShouldDestroyTemps) { assert(SubExpr && "sub expression can't be null!"); if (ExprTemporaries.empty()) @@ -1598,7 +1598,7 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr, &ExprTemporaries[0], ExprTemporaries.size(), - DestroyTemps); + ShouldDestroyTemps); ExprTemporaries.clear(); return E; @@ -1607,7 +1607,8 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs(); if (FullExpr) - FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr); + FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr, + /*ShouldDestroyTemps=*/true); return Owned(FullExpr); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp b/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp index 3c67f2ad0d30..bf19701d6bed 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -1165,7 +1165,10 @@ TemplateExprInstantiator::VisitCXXExprWithTemporaries( if (SubExpr.isInvalid()) return SemaRef.ExprError(); - return SemaRef.ActOnFinishFullExpr(move(SubExpr)); + Expr *Temp = + SemaRef.MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs(), + E->shouldDestroyTemporaries()); + return SemaRef.Owned(Temp); } Sema::OwningExprResult diff --git a/clang/test/CodeGenCXX/default-arg-temps.cpp b/clang/test/CodeGenCXX/default-arg-temps.cpp new file mode 100644 index 000000000000..2dcf773346a8 --- /dev/null +++ b/clang/test/CodeGenCXX/default-arg-temps.cpp @@ -0,0 +1,15 @@ +// RUN: clang-cc -emit-llvm %s -o %t -triple=x86_64-apple-darwin9 && + +struct T { + T(); + ~T(); +}; + +void f(const T& t = T()); + +void g() { + // RUN: grep "call void @_ZN1TC1Ev" %t | count 2 && + // RUN: grep "call void @_ZN1TD1Ev" %t | count 2 + f(); + f(); +}