[cfe-commits] r103849 - in /cfe/trunk/lib: CodeGen/CGExprCXX.cpp Frontend/PCHReaderStmt.cpp Frontend/PCHWriterStmt.cpp Sema/SemaExprCXX.cpp Sema/SemaInit.cpp Sema/SemaInit.h Sema/SemaObjCProperty.cpp Sema/SemaStmt.cpp

Douglas Gregor dgregor at apple.com
Fri May 14 17:13:29 PDT 2010


Author: dgregor
Date: Fri May 14 19:13:29 2010
New Revision: 103849

URL: http://llvm.org/viewvc/llvm-project?rev=103849&view=rev
Log:
Recognize when the named return value optimization applies in a
"return" statement and mark the corresponding CXXConstructExpr as
elidable. Teach CodeGen that eliding a temporary is different from
eliding an object construction.

This is just a baby step toward NRVO.

Modified:
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
    cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaInit.h
    cfe/trunk/lib/Sema/SemaObjCProperty.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri May 14 19:13:29 2010
@@ -321,11 +321,13 @@
       return;
   }
   // Code gen optimization to eliminate copy constructor and return
-  // its first argument instead.
+  // its first argument instead, if in fact that argument is a temporary 
+  // object.
   if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
-    const Expr *Arg = E->getArg(0)->getTemporaryObject();
-    EmitAggExpr(Arg, Dest, false);
-    return;
+    if (const Expr *Arg = E->getArg(0)->getTemporaryObject()) {
+      EmitAggExpr(Arg, Dest, false);
+      return;
+    }
   }
   if (Array) {
     QualType BaseElementTy = getContext().getBaseElementType(Array);

Modified: cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderStmt.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReaderStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReaderStmt.cpp Fri May 14 19:13:29 2010
@@ -956,6 +956,7 @@
   E->setRequiresZeroInitialization(Record[Idx++]);
   for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
     E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
+  E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
   return E->getNumArgs();
 }
 

Modified: cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterStmt.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterStmt.cpp Fri May 14 19:13:29 2010
@@ -873,6 +873,7 @@
   Record.push_back(E->getNumArgs());
   for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
     Writer.WriteSubStmt(E->getArg(I));
+  Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
   Code = pch::EXPR_CXX_CONSTRUCT;
 }
 

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri May 14 19:13:29 2010
@@ -441,8 +441,10 @@
 
   // 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));

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri May 14 19:13:29 2010
@@ -1984,6 +1984,26 @@
   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 @@
   //       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 @@
       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 @@
             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();

Modified: cfe/trunk/lib/Sema/SemaInit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.h?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.h (original)
+++ cfe/trunk/lib/Sema/SemaInit.h Fri May 14 19:13:29 2010
@@ -85,11 +85,16 @@
     /// 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 @@
   /// \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 @@
 
   /// \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 @@
   /// 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 @@
   /// 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

Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Fri May 14 19:13:29 2010
@@ -445,8 +445,9 @@
                                       SelfExpr, true, true);
       OwningExprResult Res = 
         PerformCopyInitialization(InitializedEntity::InitializeResult(
-                                  SourceLocation(),
-                                  getterMethod->getResultType()),
+                                    SourceLocation(),
+                                    getterMethod->getResultType(),
+                                    /*NRVO=*/false),
                                   SourceLocation(),
                                   Owned(IvarRefExpr));
       if (!Res.isInvalid()) {

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Fri May 14 19:13:29 2010
@@ -1058,6 +1058,31 @@
   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 @@
     // 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 @@
   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 @@
     // 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()) {





More information about the cfe-commits mailing list