diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 48 | ||||
-rw-r--r-- | lib/Sema/SemaInit.h | 40 | ||||
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 82 |
5 files changed, 109 insertions, 70 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 15c21008be..48daf84d6b 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -441,8 +441,10 @@ 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. InitializedEntity Entity = - InitializedEntity::InitializeException(ThrowLoc, E->getType()); + InitializedEntity::InitializeException(ThrowLoc, E->getType(), + /*NRVO=*/false); OwningExprResult Res = PerformCopyInitialization(Entity, SourceLocation(), Owned(E)); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 851fb9e835..06d202d3e0 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1984,6 +1984,26 @@ DeclaratorDecl *InitializedEntity::getDecl() const { return 0; } +bool InitializedEntity::allowsNRVO() const { + switch (getKind()) { + case EK_Result: + case EK_Exception: + return LocAndNRVO.NRVO; + + case EK_Variable: + case EK_Parameter: + case EK_Member: + case EK_New: + case EK_Temporary: + case EK_Base: + case EK_ArrayElement: + case EK_VectorElement: + break; + } + + return false; +} + //===----------------------------------------------------------------------===// // Initialization sequence //===----------------------------------------------------------------------===// @@ -3242,9 +3262,9 @@ static Sema::OwningExprResult CopyObject(Sema &S, // directly into the target of the omitted copy/move // // Note that the other three bullets are handled elsewhere. Copy - // elision for return statements and throw expressions are (FIXME: - // not yet) handled as part of constructor initialization, while - // copy elision for exception handlers is handled by the run-time. + // 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()); SourceLocation Loc; @@ -3737,7 +3757,7 @@ InitializationSequence::Perform(Sema &S, unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Step->Function.Function); - + // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); SourceLocation Loc = Kind.getLocation(); @@ -3774,11 +3794,21 @@ InitializationSequence::Perform(Sema &S, CXXConstructExpr::CK_VirtualBase : CXXConstructExpr::CK_NonVirtualBase; } - CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), - Constructor, - move_arg(ConstructorArgs), - ConstructorInitRequiresZeroInit, - ConstructKind); + + // If the entity allows NRVO, mark the construction as elidable + // unconditionally. + if (Entity.allowsNRVO()) + CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Constructor, /*Elidable=*/true, + move_arg(ConstructorArgs), + ConstructorInitRequiresZeroInit, + ConstructKind); + else + CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Constructor, + move_arg(ConstructorArgs), + ConstructorInitRequiresZeroInit, + ConstructKind); } if (CurInit.isInvalid()) return S.ExprError(); diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 5f2592fb77..35adf9e49e 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -85,11 +85,16 @@ private: /// the VarDecl, ParmVarDecl, or FieldDecl, respectively. DeclaratorDecl *VariableOrMember; - /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the - /// location of the 'return', 'throw', or 'new' keyword, - /// respectively. When Kind == EK_Temporary, the location where - /// the temporary is being created. - unsigned Location; + struct { + /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the + /// location of the 'return', 'throw', or 'new' keyword, + /// respectively. When Kind == EK_Temporary, the location where + /// the temporary is being created. + unsigned Location; + + /// \brief Whether the + bool NRVO; + } LocAndNRVO; /// \brief When Kind == EK_Base, the base specifier that provides the /// base class. The lower bit specifies whether the base is an inherited @@ -116,8 +121,13 @@ private: /// \brief Create the initialization entity for the result of a /// function, throwing an object, performing an explicit cast, or /// initializing a parameter for which there is no declaration. - InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type) - : Kind(Kind), Parent(0), Type(Type), Location(Loc.getRawEncoding()) { } + InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type, + bool NRVO = false) + : Kind(Kind), Parent(0), Type(Type) + { + LocAndNRVO.Location = Loc.getRawEncoding(); + LocAndNRVO.NRVO = NRVO; + } /// \brief Create the initialization entity for a member subobject. InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent) @@ -152,14 +162,14 @@ public: /// \brief Create the initialization entity for the result of a function. static InitializedEntity InitializeResult(SourceLocation ReturnLoc, - QualType Type) { - return InitializedEntity(EK_Result, ReturnLoc, Type); + QualType Type, bool NRVO) { + return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); } /// \brief Create the initialization entity for an exception object. static InitializedEntity InitializeException(SourceLocation ThrowLoc, - QualType Type) { - return InitializedEntity(EK_Exception, ThrowLoc, Type); + QualType Type, bool NRVO) { + return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO); } /// \brief Create the initialization entity for an object allocated via new. @@ -208,6 +218,10 @@ public: /// initialized. DeclaratorDecl *getDecl() const; + /// \brief Determine whether this initialization allows the named return + /// value optimization, which also applies to thrown objects. + bool allowsNRVO() const; + /// \brief Retrieve the base specifier. CXXBaseSpecifier *getBaseSpecifier() const { assert(getKind() == EK_Base && "Not a base specifier"); @@ -224,14 +238,14 @@ public: /// the result of a function call. SourceLocation getReturnLoc() const { assert(getKind() == EK_Result && "No 'return' location!"); - return SourceLocation::getFromRawEncoding(Location); + return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); } /// \brief Determine the location of the 'throw' keyword when initializing /// an exception object. SourceLocation getThrowLoc() const { assert(getKind() == EK_Exception && "No 'throw' location!"); - return SourceLocation::getFromRawEncoding(Location); + return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); } /// \brief If this is already the initializer for an array or vector diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index a2aef20f65..002c39b640 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -445,8 +445,9 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, SelfExpr, true, true); OwningExprResult Res = PerformCopyInitialization(InitializedEntity::InitializeResult( - SourceLocation(), - getterMethod->getResultType()), + SourceLocation(), + getterMethod->getResultType(), + /*NRVO=*/false), SourceLocation(), Owned(IvarRefExpr)); if (!Res.isInvalid()) { diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index f9edbaff5f..d9210f6a1b 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1058,6 +1058,31 @@ 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) { + QualType ExprType = RetExpr->getType(); + // - in a return statement in a function with ... + // ... a class return type ... + if (!RetType->isRecordType()) + return false; + // ... the same cv-unqualified type as the function return type ... + if (!Ctx.hasSameUnqualifiedType(RetType, ExprType)) + return false; + // ... 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; + 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(); +} + /// ActOnBlockReturnStmt - Utility routine to figure out block's return type. /// Action::OwningStmtResult @@ -1115,7 +1140,10 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // the C version of which boils down to CheckSingleAssignmentConstraints. OwningExprResult Res = PerformCopyInitialization( InitializedEntity::InitializeResult(ReturnLoc, - FnRetType), + FnRetType, + IsReturnCopyElidable(Context, + FnRetType, + RetValExp)), SourceLocation(), Owned(RetValExp)); if (Res.isInvalid()) { @@ -1131,31 +1159,6 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); } -/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that -/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p15). -static bool IsReturnCopyElidable(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; - // ... the same cv-unqualified type as the function return type ... - if (!Ctx.hasSameUnqualifiedType(RetType, ExprType)) - return false; - // ... the expression is the name of a non-volatile automatic object ... - // We ignore parentheses here. - // FIXME: Is this compliant? - const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens()); - if (!DR) - return false; - const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); - if (!VD) - return false; - return VD->hasLocalStorage() && !VD->getType()->isReferenceType() - && !VD->getType().isVolatileQualified(); -} - Action::OwningStmtResult Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { Expr *RetValExp = rex.takeAs<Expr>(); @@ -1214,29 +1217,18 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { // overlap restriction of subclause 6.5.16.1 does not apply to the case of // function return. - // C++0x 12.8p15: When certain criteria are met, an implementation is - // allowed to omit the copy construction of a class object, [...] - // - in a return statement in a function with a class return type, when - // the expression is the name of a non-volatile automatic object with - // the same cv-unqualified type as the function return type, the copy - // operation can be omitted [...] - // C++0x 12.8p16: When the criteria for elision of a copy operation are met - // and the object to be copied is designated by an lvalue, overload - // resolution to select the constructor for the copy is first performed - // as if the object were designated by an rvalue. - // Note that we only compute Elidable if we're in C++0x, since we don't - // care otherwise. - bool Elidable = getLangOptions().CPlusPlus0x ? - IsReturnCopyElidable(Context, FnRetType, RetValExp) : - false; - // FIXME: Elidable - (void)Elidable; - + // 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), + FnRetType, + IsReturnCopyElidable(Context, + FnRetType, + RetValExp)), SourceLocation(), Owned(RetValExp)); if (Res.isInvalid()) { |