]> granicus.if.org Git - clang/commitdiff
Promote the static getNRVOCandidate() function, which computed the
authorDouglas Gregor <dgregor@apple.com>
Fri, 21 Jan 2011 18:05:27 +0000 (18:05 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 21 Jan 2011 18:05:27 +0000 (18:05 +0000)
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

include/clang/Sema/Sema.h
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaStmt.cpp
test/CodeGenCXX/nrvo.cpp

index 05f266086b05f86a31cf606bdb139d4b968a29a9..108a60b4f7f83dfc5d82840a8aad5f8aff04bda7 100644 (file)
@@ -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);
 
index c497d7278fc0aa4cf29a50c534fcc07e95f72cca..2e5204f2584ed8870e195956e261eb7b3d2f0b2c 100644 (file)
@@ -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);
index 3ed336dbb83b2dea9283bfe8d61e419236e354c7..9e8a15739f1b75bd7120d8dc2285c7537d3c1dd0 100644 (file)
@@ -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
index 3ce96612c230d7f868dc5a5a57a25dded3fba44d..3bd9e453c9ac4431e5420e854aab2c3acdff61a1 100644 (file)
@@ -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<DeclRefExpr>(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<DeclRefExpr>(E->IgnoreParens());
   if (!DR)
     return 0;
   const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
   if (!VD)
     return 0;
   
-  if (VD->getKind() == Decl::Var && VD->hasLocalStorage() && 
+  if (VD->hasLocalStorage() && !VD->isExceptionVariable() &&
       !VD->getType()->isReferenceType() && !VD->hasAttr<BlocksAttr>() &&
-      !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,
index 8d19b1effe956633b154022ca4c99e72bf112f11..ecf6afdc7ca7ccf439643b9f513e3065dca8cb22 100644 (file)
@@ -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;
+  }
+}