nullptr.cpp created this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
nullptr.cpp requested review of this revision.

In P1825R0, the first parameter of overload resolution selected function does
not need to be an rvalue reference to the returned object's type.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D88220

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaStmt.cpp
  clang/test/SemaCXX/implicit-move.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1201,6 +1201,11 @@
       <td><a href="https://wg21.link/p0593r6";>P0593R6</a> (<a href="#dr">DR</a>)</td>
       <td class="unreleased" align="center">Clang 11</td>
     </tr>
+    <tr>
+        <td>More implicit moves</td>
+        <td><a href="https://wg21.link/p1825r0";>P1825R0</a> (<a href="#dr">DR</a>)</td>
+        <td class="unreleased" align="center">Clang 12 (partial)</td>
+    </tr>
 </table>
 
 <p>
Index: clang/test/SemaCXX/implicit-move.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/implicit-move.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -DCXX20 -verify %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fcxx-exceptions -DCXX17 -verify %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -fcxx-exceptions -DCXX14 -verify %s
+
+class Error;
+
+class NeedRvalueRef {
+public:
+  NeedRvalueRef() {}
+  ~NeedRvalueRef() {}
+  NeedRvalueRef(const NeedRvalueRef &);
+  NeedRvalueRef(NeedRvalueRef &&);
+  NeedRvalueRef(Error &&);
+};
+
+class NoNeedRvalueRef {
+public:
+  NoNeedRvalueRef() {}
+  ~NoNeedRvalueRef() {}
+  NoNeedRvalueRef(const NoNeedRvalueRef &);
+  NoNeedRvalueRef(NoNeedRvalueRef &&);
+  NoNeedRvalueRef(Error);
+};
+
+#ifdef CXX20
+// expected-no-diagnostics
+class Error {
+public:
+  Error() {}
+  ~Error() {}
+  Error(Error &&);
+
+private:
+  Error(const Error &);
+};
+
+NoNeedRvalueRef test() {
+  Error Err;
+  return Err;
+}
+#endif
+
+#ifdef CXX17
+class Error {
+public:
+  Error() {}
+  ~Error() {}
+  Error(Error &&);
+
+private:
+  Error(const Error &); // expected-note {{declared private here}}
+};
+
+NoNeedRvalueRef test2() {
+  Error Err;
+  return Err; // expected-error {{calling a private constructor of class 'Error'}}
+}
+#endif
+
+#ifdef CXX14
+class Error {
+public:
+  Error() {}
+  ~Error() {}
+  Error(Error &&);
+
+private:
+  Error(const Error &); // expected-note {{declared private here}}
+};
+
+NoNeedRvalueRef test2() {
+  Error Err;
+  return Err; // expected-error {{calling a private constructor of class 'Error'}}
+}
+#endif
+
+NeedRvalueRef test_all_ok() {
+  Error Err;
+  return Err;
+}
\ No newline at end of file
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3056,12 +3056,20 @@
   // variable will no longer be used.
   if (VD->hasAttr<BlocksAttr>()) return false;
 
+  // ...non-volatile...
+  if (VD->getType().isVolatileQualified())
+    return false;
+
+  // C++20 [class.copy.elision]p3:
+  // ...rvalue reference to a non-volatile...
+  if (VD->getType()->isRValueReferenceType() &&
+      (!(CESK & CES_AllowRValueReferenceType) ||
+       VD->getType().getNonReferenceType().isVolatileQualified()))
+    return false;
+
   if (CESK & CES_AllowDifferentTypes)
     return true;
 
-  // ...non-volatile...
-  if (VD->getType().isVolatileQualified()) return false;
-
   // Variables with higher required alignment than their type's ABI
   // alignment cannot use NRVO.
   if (!VD->getType()->isDependentType() && VD->hasAttr<AlignedAttr>() &&
@@ -3074,13 +3082,13 @@
 /// Try to perform the initialization of a potentially-movable value,
 /// which is the operand to a return or throw statement.
 ///
-/// This routine implements C++14 [class.copy]p32, which attempts to treat
-/// returned lvalues as rvalues in certain cases (to prefer move construction),
-/// then falls back to treating them as lvalues if that failed.
+/// This routine implements C++20 [class.copy.elision]p3:, which attempts to
+/// treat returned lvalues as rvalues in certain cases (to prefer move
+/// construction), then falls back to treating them as lvalues if that failed.
 ///
-/// \param ConvertingConstructorsOnly If true, follow [class.copy]p32 and reject
-/// resolutions that find non-constructors, such as derived-to-base conversions
-/// or `operator T()&&` member functions. If false, do consider such
+/// \param ConvertingConstructorsOnly If true, follow [class.copy.elision]p3 and
+/// reject resolutions that find non-constructors, such as derived-to-base
+/// conversions or `operator T()&&` member functions. If false, do consider such
 /// conversion sequences.
 ///
 /// \param Res We will fill this in if move-initialization was possible.
@@ -3114,10 +3122,14 @@
 
     FunctionDecl *FD = Step.Function.Function;
     if (ConvertingConstructorsOnly) {
-      if (isa<CXXConstructorDecl>(FD)) {
+      if (!isa<CXXConstructorDecl>(FD)) {
+        continue;
+      }
+      if (!S.getLangOpts().CPlusPlus20) {
+        // C++11 [class.copy]p32:
         // C++14 [class.copy]p32:
-        // [...] If the first overload resolution fails or was not performed,
-        // or if the type of the first parameter of the selected constructor
+        // C++17 [class.copy.elision]p3:
+        // [...] if the type of the first parameter of the selected constructor
         // is not an rvalue reference to the object's type (possibly
         // cv-qualified), overload resolution is performed again, considering
         // the object as an lvalue.
@@ -3128,8 +3140,6 @@
         if (!S.Context.hasSameUnqualifiedType(RRefType->getPointeeType(),
                                               NRVOCandidate->getType()))
           break;
-      } else {
-        continue;
       }
     } else {
       if (isa<CXXConstructorDecl>(FD)) {
@@ -3163,36 +3173,48 @@
 /// Perform the initialization of a potentially-movable value, which
 /// is the result of return value.
 ///
-/// This routine implements C++14 [class.copy]p32, which attempts to treat
-/// returned lvalues as rvalues in certain cases (to prefer move construction),
-/// then falls back to treating them as lvalues if that failed.
+/// This routine implements C++20 [class.copy.elision]p3, which attempts to
+/// treat returned lvalues as rvalues in certain cases (to prefer move
+/// construction), then falls back to treating them as lvalues if that failed.
+///
+/// Standard revision history:
+///   C++11
+///     CWG1579:-returned object type and function return type can be different.
+///   C++14
+///     |--just rephrase rule.
+///   C++17
+///     P0912:-add support for co_return.
+///     P1825:-returned object can be rvalue reference to non-volatile.
+///           -the first parameter of overload resolution selected function does
+///           not need to be an rvalue reference to the returned object's type.
+///   C++20
+
 ExprResult
 Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
                                       const VarDecl *NRVOCandidate,
                                       QualType ResultType,
                                       Expr *Value,
                                       bool AllowNRVO) {
-  // C++14 [class.copy]p32:
-  // When the criteria for elision of a copy/move operation are met, but not for
-  // an exception-declaration, and the object to be copied is designated by an
-  // lvalue, or when the expression in a return statement is a (possibly
-  // parenthesized) id-expression that names an object with automatic storage
-  // duration declared in the body or parameter-declaration-clause of the
-  // innermost enclosing function or lambda-expression, overload resolution to
-  // select the constructor for the copy is first performed as if the object
-  // were designated by an rvalue.
   ExprResult Res = ExprError();
 
   if (AllowNRVO) {
-    bool AffectedByCWG1579 = false;
+    CopyElisionSemanticsKind CESK = CES_Strict;
+    if (getLangOpts().CPlusPlus20) {
+      CESK = CES_ImplicitlyMovableCXX20;
+    } else if (getLangOpts().CPlusPlus14 || LangOptions().CPlusPlus17) {
+      CESK = CES_ImplicitlyMovableCXX14CXX17;
+    } else if (getLangOpts().CPlusPlus11) {
+      CESK = CES_ImplicitlyMovableCXX11;
+    }
 
+    bool AffectedByCWG1579 = false;
     if (!NRVOCandidate) {
-      NRVOCandidate = getCopyElisionCandidate(ResultType, Value, CES_Default);
+      NRVOCandidate = getCopyElisionCandidate(ResultType, Value, CESK);
       if (NRVOCandidate &&
           !getDiagnostics().isIgnored(diag::warn_return_std_move_in_cxx11,
                                       Value->getExprLoc())) {
-        const VarDecl *NRVOCandidateInCXX11 =
-            getCopyElisionCandidate(ResultType, Value, CES_FormerDefault);
+        const VarDecl *NRVOCandidateInCXX11 = getCopyElisionCandidate(
+            ResultType, Value, CES_ImplicitlyMovableCXX11);
         AffectedByCWG1579 = (!NRVOCandidateInCXX11);
       }
     }
@@ -3266,6 +3288,7 @@
   // Either we didn't meet the criteria for treating an lvalue as an rvalue,
   // above, or overload resolution failed. Either way, we need to try
   // (again) now with the return value expression as written.
+  // TODO: C++20 considering the expression or operand as an lvalue
   if (Res.isInvalid())
     Res = PerformCopyInitialization(Entity, SourceLocation(), Value);
 
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -4485,10 +4485,16 @@
     CES_AllowParameters = 1,
     CES_AllowDifferentTypes = 2,
     CES_AllowExceptionVariables = 4,
-    CES_FormerDefault = (CES_AllowParameters),
-    CES_Default = (CES_AllowParameters | CES_AllowDifferentTypes),
-    CES_AsIfByStdMove = (CES_AllowParameters | CES_AllowDifferentTypes |
-                         CES_AllowExceptionVariables),
+    CES_AllowRValueReferenceType = 8,
+    CES_ImplicitlyMovableCXX11 = (CES_AllowParameters),
+    CES_ImplicitlyMovableCXX14CXX17 =
+        (CES_AllowParameters | CES_AllowDifferentTypes),
+    CES_ImplicitlyMovableCXX20 =
+        (CES_AllowParameters | CES_AllowDifferentTypes |
+         CES_AllowRValueReferenceType),
+    CES_AsIfByStdMove =
+        (CES_AllowParameters | CES_AllowDifferentTypes |
+         CES_AllowExceptionVariables | CES_AllowRValueReferenceType),
   };
 
   VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D88220: [C++20] Imp... Yang Fan via Phabricator via cfe-commits

Reply via email to