From: Douglas Gregor Date: Fri, 21 Jan 2011 18:05:27 +0000 (+0000) Subject: Promote the static getNRVOCandidate() function, which computed the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f5d8f466c3eebaffc51468812bdcbe7f0fe4891a;p=clang 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). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123982 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 05f266086b..108a60b4f7 100644 --- a/include/clang/Sema/Sema.h +++ b/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/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index c497d7278f..2e5204f258 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/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/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3ed336dbb8..9e8a15739f 100644 --- a/lib/Sema/SemaInit.cpp +++ b/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/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 3ce96612c2..3bd9e453c9 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/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/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp index 8d19b1effe..ecf6afdc7c 100644 --- a/test/CodeGenCXX/nrvo.cpp +++ b/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; + } +}