From 5d36900d7a6840624efcf7522c3d02bdbd3acf17 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 21 Jan 2011 18:05:27 +0000 Subject: [PATCH] Promote the static getNRVOCandidate() function, which computed the NRVO candidate for a return statement, to Sema::getCopyElisionCandidate(), and teach it enough to also determine the NRVO candidate for a throw expression. We still don't use the latter information, however. Along the way, implement core issue 1148, which eliminates copy elision from catch parameters and clarifies that copy elision cannot occur from function parameters (which we already implemented). llvm-svn: 123982 --- clang/include/clang/Sema/Sema.h | 3 ++ clang/lib/Sema/SemaExprCXX.cpp | 2 +- clang/lib/Sema/SemaInit.cpp | 2 +- clang/lib/Sema/SemaStmt.cpp | 51 +++++++++++++++++++-------------- clang/test/CodeGenCXX/nrvo.cpp | 13 +++++++++ 5 files changed, 48 insertions(+), 23 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 05f266086b05..108a60b4f7f8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1648,6 +1648,9 @@ public: StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); StmtResult ActOnBreakStmt(SourceLocation GotoLoc, Scope *CurScope); + const VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, + bool AllowFunctionParameters); + StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index c497d7278fc0..2e5204f2584e 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -517,7 +517,7 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // Initialize the exception result. This implicitly weeds out // abstract types or types with inaccessible copy constructors. - // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p34. + // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p32. InitializedEntity Entity = InitializedEntity::InitializeException(ThrowLoc, E->getType(), /*NRVO=*/false); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 3ed336dbb83b..9e8a15739f1b 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3317,7 +3317,7 @@ static ExprResult CopyObject(Sema &S, if (!Class) return move(CurInit); - // C++0x [class.copy]p34: + // C++0x [class.copy]p32: // When certain criteria are met, an implementation is allowed to // omit the copy/move construction of a class object, even if the // copy/move constructor and/or destructor for the object have diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 3ce96612c230..3bd9e453c9ac 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -1089,40 +1089,49 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { return Owned(new (Context) BreakStmt(BreakLoc)); } -/// \brief Determine whether a return statement is a candidate for the named -/// return value optimization (C++0x 12.8p34, bullet 1). +/// \brief Determine whether the given expression is a candidate for +/// copy elision in either a return statement or a throw expression. /// -/// \param Ctx The context in which the return expression and type occur. +/// \param ReturnType If we're determining the copy elision candidate for +/// a return statement, this is the return type of the function. If we're +/// determining the copy elision candidate for a throw expression, this will +/// be a NULL type. /// -/// \param RetType The return type of the function or block. +/// \param E The expression being returned from the function or block, or +/// being thrown. /// -/// \param RetExpr The expression being returned from the function or block. +/// \param AllowFunctionParameter /// /// \returns The NRVO candidate variable, if the return statement may use the /// NRVO, or NULL if there is no such candidate. -static const VarDecl *getNRVOCandidate(ASTContext &Ctx, QualType RetType, - Expr *RetExpr) { - QualType ExprType = RetExpr->getType(); +const VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, + Expr *E, + bool AllowFunctionParameter) { + QualType ExprType = E->getType(); // - in a return statement in a function with ... // ... a class return type ... - if (!RetType->isRecordType()) - return 0; - // ... the same cv-unqualified type as the function return type ... - if (!Ctx.hasSameUnqualifiedType(RetType, ExprType)) - return 0; - // ... the expression is the name of a non-volatile automatic object ... - // We ignore parentheses here. - // FIXME: Is this compliant? (Everyone else does it) - const DeclRefExpr *DR = dyn_cast(RetExpr->IgnoreParens()); + if (!ReturnType.isNull()) { + if (!ReturnType->isRecordType()) + return 0; + // ... the same cv-unqualified type as the function return type ... + if (!Context.hasSameUnqualifiedType(ReturnType, ExprType)) + return 0; + } + + // ... the expression is the name of a non-volatile automatic object + // (other than a function or catch-clause parameter)) ... + const DeclRefExpr *DR = dyn_cast(E->IgnoreParens()); if (!DR) return 0; const VarDecl *VD = dyn_cast(DR->getDecl()); if (!VD) return 0; - if (VD->getKind() == Decl::Var && VD->hasLocalStorage() && + if (VD->hasLocalStorage() && !VD->isExceptionVariable() && !VD->getType()->isReferenceType() && !VD->hasAttr() && - !VD->getType().isVolatileQualified()) + !VD->getType().isVolatileQualified() && + (VD->getKind() == Decl::Var || + AllowFunctionParameter && VD->getKind() == Decl::ParmVar)) return VD; return 0; @@ -1183,7 +1192,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp); + NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); ExprResult Res = PerformCopyInitialization( InitializedEntity::InitializeResult(ReturnLoc, FnRetType, @@ -1281,7 +1290,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp); + NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); ExprResult Res = PerformCopyInitialization( InitializedEntity::InitializeResult(ReturnLoc, FnRetType, diff --git a/clang/test/CodeGenCXX/nrvo.cpp b/clang/test/CodeGenCXX/nrvo.cpp index 8d19b1effe95..ecf6afdc7ca7 100644 --- a/clang/test/CodeGenCXX/nrvo.cpp +++ b/clang/test/CodeGenCXX/nrvo.cpp @@ -131,3 +131,16 @@ X test4(bool B) { // CHECK: tail call void @exit(i32 1) exit(1); } + +// CHECK-EH: define void @_Z5test5 +void may_throw(); +X test5() { + try { + may_throw(); + } catch (X x) { + // CHECK-EH: invoke void @_ZN1XC1ERKS_ + // CHECK-EH: call void @__cxa_end_catch() + // CHECK-EH: ret void + return x; + } +}