mizvekov updated this revision to Diff 332140.
mizvekov added a comment.

- Removed special flag, now is enabled on -std=c++2b
- Always enabled for coroutines
- Ran test suite
- Some relevant test files updated to also run c++2b
- Some new tests added


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D99005/new/

https://reviews.llvm.org/D99005

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaCoroutine.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CXX/class/class.init/class.copy.elision/p3.cpp
  clang/test/CXX/special/class.copy/p33-0x.cpp

Index: clang/test/CXX/special/class.copy/p33-0x.cpp
===================================================================
--- clang/test/CXX/special/class.copy/p33-0x.cpp
+++ clang/test/CXX/special/class.copy/p33-0x.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++2b -fsyntax-only -verify=expected,cxx2b %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -fsyntax-only -verify=expected,cxx11 %s
+// cxx2b-no-diagnostics
 class X {
   X(const X&);
 
@@ -27,7 +29,7 @@
   struct X {
     X();
     X(X&&);
-    X(const X&) = delete; // expected-note 2{{'X' has been explicitly marked deleted here}}
+    X(const X&) = delete; // cxx11-note 2{{'X' has been explicitly marked deleted here}}
   };
 
   void f(int i) {
@@ -36,7 +38,7 @@
       X x2;
       if (i)
         throw x2; // okay
-      throw x; // expected-error{{call to deleted constructor of 'PR10142::X'}}
+      throw x; // cxx11-error{{call to deleted constructor of 'PR10142::X'}}
     } catch (...) {
     }
   }
@@ -48,10 +50,10 @@
       T x2;
       if (i)
         throw x2; // okay
-      throw x; // expected-error{{call to deleted constructor of 'PR10142::X'}}
+      throw x; // cxx11-error{{call to deleted constructor of 'PR10142::X'}}
     } catch (...) {
     }
   }
 
-  template void f2<X>(int); // expected-note{{in instantiation of function template specialization 'PR10142::f2<PR10142::X>' requested here}}
+  template void f2<X>(int); // cxx11-note{{in instantiation of function template specialization 'PR10142::f2<PR10142::X>' requested here}}
 }
Index: clang/test/CXX/class/class.init/class.copy.elision/p3.cpp
===================================================================
--- clang/test/CXX/class/class.init/class.copy.elision/p3.cpp
+++ clang/test/CXX/class/class.init/class.copy.elision/p3.cpp
@@ -1,7 +1,8 @@
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected,cxx20 %s
-// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_14_17 %s
-// RUN: %clang_cc1 -std=c++14 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_14_17 %s
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_14_17 %s
+// RUN: %clang_cc1 -std=c++2b -fsyntax-only -fcxx-exceptions -verify=expected,cxx20_2b,cxx2b %s
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_14_17_20,cxx20_2b %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_14_17_20,cxx11_14_17 %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_14_17_20,cxx11_14_17 %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_14_17_20,cxx11_14_17 %s
 
 namespace test_delete_function {
 struct A1 {
@@ -72,20 +73,20 @@
 
 struct B1 {
   B1(const B1 &);
-  B1(B1 &&) = delete; // cxx20-note {{'B1' has been explicitly marked deleted here}}
+  B1(B1 &&) = delete; // cxx20_2b-note {{'B1' has been explicitly marked deleted here}}
 };
 B1 test3(B1 &&b) {
-  return b; // cxx20-error {{call to deleted constructor of 'test_implicitly_movable_rvalue_ref::B1'}}
+  return b; // cxx20_2b-error {{call to deleted constructor of 'test_implicitly_movable_rvalue_ref::B1'}}
 }
 
 struct B2 {
   B2(const B2 &);
 
 private:
-  B2(B2 &&); // cxx20-note {{declared private here}}
+  B2(B2 &&); // cxx20_2b-note {{declared private here}}
 };
 B2 test4(B2 &&b) {
-  return b; // cxx20-error {{calling a private constructor of class 'test_implicitly_movable_rvalue_ref::B2'}}
+  return b; // cxx20_2b-error {{calling a private constructor of class 'test_implicitly_movable_rvalue_ref::B2'}}
 }
 } // namespace test_implicitly_movable_rvalue_ref
 
@@ -96,13 +97,13 @@
 
 struct A1 {
   A1(const A1 &);
-  A1(A1 &&) = delete; // cxx20-note {{'A1' has been explicitly marked deleted here}}
+  A1(A1 &&) = delete; // cxx20_2b-note {{'A1' has been explicitly marked deleted here}}
 };
 void test1() {
   try {
     func();
   } catch (A1 a) {
-    throw a; // cxx20-error {{call to deleted constructor of 'test_throw_parameter::A1'}}
+    throw a; // cxx20_2b-error {{call to deleted constructor of 'test_throw_parameter::A1'}}
   }
 }
 
@@ -110,13 +111,13 @@
   A2(const A2 &);
 
 private:
-  A2(A2 &&); // cxx20-note {{declared private here}}
+  A2(A2 &&); // cxx20_2b-note {{declared private here}}
 };
 void test2() {
   try {
     func();
   } catch (A2 a) {
-    throw a; // cxx20-error {{calling a private constructor of class 'test_throw_parameter::A2'}}
+    throw a; // cxx20_2b-error {{calling a private constructor of class 'test_throw_parameter::A2'}}
   }
 }
 } // namespace test_throw_parameter
@@ -148,22 +149,22 @@
 
 struct B1 {
   operator C() const &;
-  operator C() && = delete; // cxx20-note {{'operator C' has been explicitly marked deleted here}}
+  operator C() && = delete; // cxx20_2b-note {{'operator C' has been explicitly marked deleted here}}
 };
 C test3() {
   B1 b;
-  return b; // cxx20-error {{conversion function from 'test_non_ctor_conversion::B1' to 'test_non_ctor_conversion::C' invokes a deleted function}}
+  return b; // cxx20_2b-error {{conversion function from 'test_non_ctor_conversion::B1' to 'test_non_ctor_conversion::C' invokes a deleted function}}
 }
 
 struct B2 {
   operator C() const &;
 
 private:
-  operator C() &&; // cxx20-note {{declared private here}}
+  operator C() &&; // cxx20_2b-note {{declared private here}}
 };
 C test4() {
   B2 b;
-  return b; // cxx20-error {{'operator C' is a private member of 'test_non_ctor_conversion::B2'}}
+  return b; // cxx20_2b-error {{'operator C' is a private member of 'test_non_ctor_conversion::B2'}}
 }
 } // namespace test_non_ctor_conversion
 
@@ -184,7 +185,7 @@
 struct NeedValue {
   NeedValue(A1); // cxx11_14_17-note 2 {{passing argument to parameter here}}
   NeedValue(A2);
-  NeedValue(B1); // cxx20-note 2 {{passing argument to parameter here}}
+  NeedValue(B1); // cxx20_2b-note 2 {{passing argument to parameter here}}
   NeedValue(B2);
 };
 
@@ -243,26 +244,26 @@
 struct B1 {
   B1();
   B1(const B1 &);
-  B1(B1 &&) = delete; // cxx20-note 3 {{'B1' has been explicitly marked deleted here}}
+  B1(B1 &&) = delete; // cxx20_2b-note 3 {{'B1' has been explicitly marked deleted here}}
 };
 NeedValue test_3_1() {
   // not rvalue reference
   // same type
   B1 b;
-  return b; // cxx20-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::B1'}}
+  return b; // cxx20_2b-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::B1'}}
 }
 class DerivedB1 : public B1 {};
 B1 test_3_2() {
   // rvalue reference
   // not same type
   DerivedB1 b;
-  return b; // cxx20-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::B1'}}
+  return b; // cxx20_2b-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::B1'}}
 }
 NeedValue test_3_3() {
   // not rvalue reference
   // not same type
   DerivedB1 b;
-  return b; // cxx20-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::B1'}}
+  return b; // cxx20_2b-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::B1'}}
 }
 
 struct B2 {
@@ -270,25 +271,68 @@
   B2(const B2 &);
 
 private:
-  B2(B2 &&); // cxx20-note 3 {{declared private here}}
+  B2(B2 &&); // cxx20_2b-note 3 {{declared private here}}
 };
 NeedValue test_4_1() {
   // not rvalue reference
   // same type
   B2 b;
-  return b; // cxx20-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::B2'}}
+  return b; // cxx20_2b-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::B2'}}
 }
 class DerivedB2 : public B2 {};
 B2 test_4_2() {
   // rvalue reference
   // not same type
   DerivedB2 b;
-  return b; // cxx20-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::B2'}}
+  return b; // cxx20_2b-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::B2'}}
 }
 NeedValue test_4_3() {
   // not rvalue reference
   // not same type
   DerivedB2 b;
-  return b; // cxx20-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::B2'}}
+  return b; // cxx20_2b-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::B2'}}
 }
 } // namespace test_ctor_param_rvalue_ref
+namespace test_simpler_implicit_move {
+struct CopyOnly {
+  CopyOnly(); // cxx2b-note {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
+  CopyOnly(CopyOnly&); // cxx2b-note {{candidate constructor not viable: expects an lvalue for 1st argument}}
+};
+struct MoveOnly {
+  MoveOnly();
+  MoveOnly(MoveOnly&&); // cxx11_14_17_20-note {{copy constructor is implicitly deleted}}
+};
+MoveOnly&& rref();
+
+MoveOnly&& test_1(MoveOnly&& w) {
+  return w; // cxx11_14_17_20-error {{cannot bind to lvalue of type}}
+}
+
+CopyOnly test_2(bool b) {
+  static CopyOnly w1;
+  CopyOnly w2;
+  if (b) {
+    return w1;
+  } else {
+    return w2; // cxx2b-error {{no matching constructor for initialization}}
+  }
+}
+
+template<class T> T&& test_3a(T&& x) { return x; } // cxx11_14_17_20-error {{cannot bind to lvalue of type}}
+void test_3b(MoveOnly w) {
+  MoveOnly& r = test_3a(w);
+  MoveOnly&& rr = test_3a(static_cast<MoveOnly&&>(w)); // cxx11_14_17_20-note {{in instantiation of function template specialization}}
+}
+
+MoveOnly&& test_4() {
+  MoveOnly &&x = rref();
+  return x; // cxx11_14_17_20-error {{cannot bind to lvalue of type}}
+}
+
+void test_5() {
+  MoveOnly x;
+  try {
+    throw x; // cxx11_14_17_20-error {{call to implicitly-deleted copy constructor}}
+  } catch(...) {}
+}
+} // namespace test_simpler_implicit_move
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -8839,6 +8839,10 @@
   if (E->isTypeDependent())
     return S.Context.DependentTy;
 
+  Expr *IDExpr = E;
+  if (auto *ImplCastExpr = dyn_cast<ImplicitCastExpr>(E))
+    IDExpr = ImplCastExpr->getSubExpr();
+
   // C++11 [dcl.type.simple]p4:
   //   The type denoted by decltype(e) is defined as follows:
 
@@ -8849,7 +8853,7 @@
   // Note that this does not pick up the implicit 'const' for a template
   // parameter object. This rule makes no difference before C++20 so we apply
   // it unconditionally.
-  if (const auto *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
+  if (const auto *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(IDExpr))
     return SNTTPE->getParameterType(S.Context);
 
   //     - if e is an unparenthesized id-expression or an unparenthesized class
@@ -8858,21 +8862,22 @@
   //       functions, the program is ill-formed;
   //
   // We apply the same rules for Objective-C ivar and property references.
-  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr)) {
     const ValueDecl *VD = DRE->getDecl();
     if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(VD))
       return TPO->getType().getUnqualifiedType();
     return VD->getType();
-  } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+  } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(IDExpr)) {
     if (const ValueDecl *VD = ME->getMemberDecl())
       if (isa<FieldDecl>(VD) || isa<VarDecl>(VD))
         return VD->getType();
-  } else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(E)) {
+  } else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) {
     return IR->getDecl()->getType();
-  } else if (const ObjCPropertyRefExpr *PR = dyn_cast<ObjCPropertyRefExpr>(E)) {
+  } else if (const ObjCPropertyRefExpr *PR =
+                 dyn_cast<ObjCPropertyRefExpr>(IDExpr)) {
     if (PR->isExplicitProperty())
       return PR->getExplicitProperty()->getType();
-  } else if (auto *PE = dyn_cast<PredefinedExpr>(E)) {
+  } else if (auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) {
     return PE->getType();
   }
 
@@ -8885,8 +8890,8 @@
   //   entity.
   using namespace sema;
   if (S.getCurLambda()) {
-    if (isa<ParenExpr>(E)) {
-      if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
+    if (isa<ParenExpr>(IDExpr)) {
+      if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr->IgnoreParens())) {
         if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
           QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation());
           if (!T.isNull())
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3041,6 +3041,8 @@
 /// NRVO, or NULL if there is no such candidate.
 VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, Expr *E,
                                        CopyElisionSemanticsKind CESK) {
+  if (auto ImplCastExpr = dyn_cast<ImplicitCastExpr>(E))
+    E = ImplCastExpr->getSubExpr();
   // - in a return statement in a function [where] ...
   // ... the expression is the name of a non-volatile automatic object ...
   DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens());
@@ -3086,15 +3088,14 @@
   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()))
+  QualType VDNonRefType = VDType;
+  if (VDType->isReferenceType()) {
+    if (!(CESK & CES_AllowRValueReferenceType) ||
+        !VDType->isRValueReferenceType())
+      return false;
+    VDNonRefType = VDType.getNonReferenceType();
+  }
+  if (!VDNonRefType->isObjectType() || VDNonRefType.isVolatileQualified())
     return false;
 
   if (CESK & CES_AllowDifferentTypes)
@@ -3102,8 +3103,8 @@
 
   // Variables with higher required alignment than their type's ABI
   // alignment cannot use NRVO.
-  if (!VD->getType()->isDependentType() && VD->hasAttr<AlignedAttr>() &&
-      Context.getDeclAlign(VD) > Context.getTypeAlignInChars(VD->getType()))
+  if (!VDNonRefType->isDependentType() && VD->hasAttr<AlignedAttr>() &&
+      Context.getDeclAlign(VD) > Context.getTypeAlignInChars(VDNonRefType))
     return false;
 
   return true;
@@ -3222,14 +3223,13 @@
   bool NeedSecondOverloadResolution = true;
 
   if (AllowNRVO) {
-    CopyElisionSemanticsKind CESK = CES_Strict;
-    if (getLangOpts().CPlusPlus20) {
-      CESK = CES_ImplicitlyMovableCXX20;
-    } else if (getLangOpts().CPlusPlus11) {
-      CESK = CES_ImplicitlyMovableCXX11CXX14CXX17;
-    }
-
     if (!NRVOCandidate) {
+      CopyElisionSemanticsKind CESK = CES_Strict;
+      if (getLangOpts().CPlusPlus20) {
+        CESK = CES_ImplicitlyMovableCXX20;
+      } else if (getLangOpts().CPlusPlus11) {
+        CESK = CES_ImplicitlyMovableCXX11CXX14CXX17;
+      }
       NRVOCandidate = getCopyElisionCandidate(ResultType, Value, CESK);
     }
 
@@ -3432,8 +3432,9 @@
     InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
                                                                    FnRetType,
                                                       NRVOCandidate != nullptr);
-    ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
-                                                     FnRetType, RetValExp);
+    ExprResult Res = PerformMoveOrCopyInitialization(
+        Entity, NRVOCandidate, FnRetType, RetValExp,
+        /*AllowNRVO=*/!getLangOpts().CPlusPlus2b);
     if (Res.isInvalid()) {
       // FIXME: Cleanup temporaries here, anyway?
       return StmtError();
@@ -3650,6 +3651,15 @@
   if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
     return StmtError();
 
+  if (getLangOpts().CPlusPlus2b && RetValExp) {
+    if (VarDecl *VD = getCopyElisionCandidate(QualType{}, RetValExp,
+                                              CES_ImplicitlyMovableCXX20)) {
+      RetValExp = ImplicitCastExpr::Create(
+          Context, VD->getType().getNonReferenceType(), CK_NoOp, RetValExp,
+          nullptr, VK_XValue, FPOptionsOverride());
+    }
+  }
+
   if (isa<CapturingScopeInfo>(getCurFunction()))
     return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp);
 
@@ -3846,8 +3856,9 @@
       InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
                                                                      RetType,
                                                       NRVOCandidate != nullptr);
-      ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
-                                                       RetType, RetValExp);
+      ExprResult Res = PerformMoveOrCopyInitialization(
+          Entity, NRVOCandidate, RetType, RetValExp,
+          /*AllowNRVO=*/!getLangOpts().CPlusPlus2b);
       if (Res.isInvalid()) {
         // FIXME: Clean up temporaries here anyway?
         return StmtError();
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -851,6 +851,15 @@
     Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";
 
   if (Ex && !Ex->isTypeDependent()) {
+    if (getLangOpts().CPlusPlus2b) {
+      if (VarDecl *VD = getCopyElisionCandidate(QualType{}, Ex,
+                                                CES_ImplicitlyMovableCXX20)) {
+        Ex = ImplicitCastExpr::Create(
+            Context, VD->getType().getNonReferenceType(), CK_NoOp, Ex, nullptr,
+            VK_XValue, FPOptionsOverride());
+      }
+    }
+
     QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType());
     if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex))
       return ExprError();
@@ -878,7 +887,8 @@
         OpLoc, ExceptionObjectTy,
         /*NRVO=*/NRVOVariable != nullptr);
     ExprResult Res = PerformMoveOrCopyInitialization(
-        Entity, NRVOVariable, QualType(), Ex, IsThrownVarInScope);
+        Entity, NRVOVariable, QualType(), Ex,
+        /*AllowNRVO=*/!getLangOpts().CPlusPlus2b && IsThrownVarInScope);
     if (Res.isInvalid())
       return ExprError();
     Ex = Res.get();
Index: clang/lib/Sema/SemaCoroutine.cpp
===================================================================
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -999,10 +999,14 @@
     const VarDecl *NRVOCandidate = this->getCopyElisionCandidate(
         E->getType(), E, CES_ImplicitlyMovableCXX20);
     if (NRVOCandidate) {
+      QualType T = NRVOCandidate->getType();
+      E = ImplicitCastExpr::Create(Context, T.getNonReferenceType(), CK_NoOp, E,
+                                   nullptr, VK_XValue, FPOptionsOverride());
       InitializedEntity Entity =
-          InitializedEntity::InitializeResult(Loc, E->getType(), NRVOCandidate);
-      ExprResult MoveResult = this->PerformMoveOrCopyInitialization(
-          Entity, NRVOCandidate, E->getType(), E);
+          InitializedEntity::InitializeResult(Loc, T, NRVOCandidate);
+      ExprResult MoveResult =
+          this->PerformMoveOrCopyInitialization(Entity, NRVOCandidate, T, E,
+                                                /*AllowNRVO=*/false);
       if (MoveResult.get())
         E = MoveResult.get();
     }
@@ -1570,7 +1574,8 @@
     // Trigger a nice error message.
     InitializedEntity Entity =
         InitializedEntity::InitializeResult(Loc, FnRetType, false);
-    S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue);
+    S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue,
+                                      /*AllowNRVO=*/false);
     noteMemberDeclaredHere(S, ReturnValue, Fn);
     return false;
   }
@@ -1587,7 +1592,8 @@
 
   InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl);
   ExprResult Res = S.PerformMoveOrCopyInitialization(Entity, nullptr, GroType,
-                                                     this->ReturnValue);
+                                                     this->ReturnValue,
+                                                     /*AllowNRVO=*/false);
   if (Res.isInvalid())
     return false;
 
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -1954,7 +1954,7 @@
       new (S.Context) DeclRefExpr(S.Context, VD, false, T, VK_LValue, Loc);
   ExprResult Result = S.PerformMoveOrCopyInitialization(
       InitializedEntity::InitializeBlock(Loc, T, false), VD, VD->getType(),
-      VarRef, /*AllowNRVO=*/true);
+      VarRef, /*AllowNRVO=*/!S.getLangOpts().CPlusPlus2b);
   if (!Result.isInvalid()) {
     Result = S.MaybeCreateExprWithCleanups(Result);
     Expr *Init = Result.getAs<Expr>();
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -3428,9 +3428,8 @@
 
   ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
                                              const VarDecl *NRVOCandidate,
-                                             QualType ResultType,
-                                             Expr *Value,
-                                             bool AllowNRVO = true);
+                                             QualType ResultType, Expr *Value,
+                                             bool AllowNRVO);
 
   bool CanPerformAggregateInitializationForOverloadResolution(
       const InitializedEntity &Entity, InitListExpr *From);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to