diff options
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 181 |
1 files changed, 105 insertions, 76 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index d9210f6a1b..f8fe4fe21c 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1058,29 +1058,42 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { return Owned(new (Context) BreakStmt(BreakLoc)); } -/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that -/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p34). -static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType, - Expr *RetExpr) { +/// \brief Determine whether a return statement is a candidate for the named +/// return value optimization (C++0x 12.8p34, bullet 1). +/// +/// \param Ctx The context in which the return expression and type occur. +/// +/// \param RetType The return type of the function or block. +/// +/// \param RetExpr The expression being returned from the function or block. +/// +/// \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(); // - in a return statement in a function with ... // ... a class return type ... if (!RetType->isRecordType()) - return false; + return 0; // ... the same cv-unqualified type as the function return type ... if (!Ctx.hasSameUnqualifiedType(RetType, ExprType)) - return false; + 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<DeclRefExpr>(RetExpr->IgnoreParens()); if (!DR) - return false; + return 0; const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) - return false; - return VD->getKind() == Decl::Var && VD->hasLocalStorage() && - !VD->getType()->isReferenceType() && !VD->getType().isVolatileQualified(); + return 0; + + if (VD->getKind() == Decl::Var && VD->hasLocalStorage() && + !VD->getType()->isReferenceType() && !VD->getType().isVolatileQualified()) + return VD; + + return 0; } /// ActOnBlockReturnStmt - Utility routine to figure out block's return type. @@ -1117,46 +1130,58 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Otherwise, verify that this result type matches the previous one. We are // pickier with blocks than for normal functions because we don't have GCC // compatibility to worry about here. + ReturnStmt *Result = 0; if (CurBlock->ReturnType->isVoidType()) { if (RetValExp) { Diag(ReturnLoc, diag::err_return_block_has_expr); RetValExp->Destroy(Context); RetValExp = 0; } - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); - } - - if (!RetValExp) + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); + } else if (!RetValExp) { return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); + } else { + const VarDecl *NRVOCandidate = 0; + + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + // we have a non-void block with an expression, continue checking + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // overlap restriction of subclause 6.5.16.1 does not apply to the case of + // function return. + + // 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); + OwningExprResult Res = PerformCopyInitialization( + InitializedEntity::InitializeResult(ReturnLoc, + FnRetType, + NRVOCandidate != 0), + SourceLocation(), + Owned(RetValExp)); + if (Res.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? + return StmtError(); + } + + if (RetValExp) + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); - if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { - // we have a non-void block with an expression, continue checking - - // C99 6.8.6.4p3(136): The return statement is not an assignment. The - // overlap restriction of subclause 6.5.16.1 does not apply to the case of - // function return. - - // In C++ the return statement is handled via a copy initialization. - // the C version of which boils down to CheckSingleAssignmentConstraints. - OwningExprResult Res = PerformCopyInitialization( - InitializedEntity::InitializeResult(ReturnLoc, - FnRetType, - IsReturnCopyElidable(Context, - FnRetType, - RetValExp)), - SourceLocation(), - Owned(RetValExp)); - if (Res.isInvalid()) { - // FIXME: Cleanup temporaries here, anyway? - return StmtError(); + RetValExp = Res.takeAs<Expr>(); + if (RetValExp) + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } - RetValExp = Res.takeAs<Expr>(); - if (RetValExp) - CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); } - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); + // If we need to check for the named return value optimization, save the + // return statement in our scope for later processing. + if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && + !CurContext->isDependentContext()) + FunctionScopes.back()->Returns.push_back(Result); + + return Owned(Result); } Action::OwningStmtResult @@ -1177,6 +1202,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { else // If we don't have a function/method context, bail. return StmtError(); + ReturnStmt *Result = 0; if (FnRetType->isVoidType()) { if (RetValExp && !RetValExp->isTypeDependent()) { // C99 6.8.6.4p1 (ext_ since GCC warns) @@ -1195,10 +1221,9 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); } - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); - } - - if (!RetValExp && !FnRetType->isDependentType()) { + + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); + } else if (!RetValExp && !FnRetType->isDependentType()) { unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4 // C99 6.8.6.4p1 (ext_ since GCC warns) if (getLangOptions().C99) DiagID = diag::ext_return_missing_expr; @@ -1207,43 +1232,47 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/; else Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/; - return Owned(new (Context) ReturnStmt(ReturnLoc, (Expr*)0)); - } - - if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { - // we have a non-void function with an expression, continue checking - - // C99 6.8.6.4p3(136): The return statement is not an assignment. The - // overlap restriction of subclause 6.5.16.1 does not apply to the case of - // function return. + Result = new (Context) ReturnStmt(ReturnLoc); + } else { + const VarDecl *NRVOCandidate = 0; + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + // we have a non-void function with an expression, continue checking + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // overlap restriction of subclause 6.5.16.1 does not apply to the case of + // function return. + + // 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); + OwningExprResult Res = PerformCopyInitialization( + InitializedEntity::InitializeResult(ReturnLoc, + FnRetType, + NRVOCandidate != 0), + SourceLocation(), + Owned(RetValExp)); + if (Res.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? + return StmtError(); + } - // C++0x [class.copy]p34: - // - - - // In C++ the return statement is handled via a copy initialization. - // the C version of which boils down to CheckSingleAssignmentConstraints. - OwningExprResult Res = PerformCopyInitialization( - InitializedEntity::InitializeResult(ReturnLoc, - FnRetType, - IsReturnCopyElidable(Context, - FnRetType, - RetValExp)), - SourceLocation(), - Owned(RetValExp)); - if (Res.isInvalid()) { - // FIXME: Cleanup temporaries here, anyway? - return StmtError(); + RetValExp = Res.takeAs<Expr>(); + if (RetValExp) + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } - - RetValExp = Res.takeAs<Expr>(); - if (RetValExp) - CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + + if (RetValExp) + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); + Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); } - - if (RetValExp) - RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp); - return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); + + // If we need to check for the named return value optimization, save the + // return statement in our scope for later processing. + if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && + !CurContext->isDependentContext()) + FunctionScopes.back()->Returns.push_back(Result); + + return Owned(Result); } /// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently |