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

small cleanup.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D99005

Files:
  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/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-14.cpp
  clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
  clang/test/CXX/special/class.copy/p33-0x.cpp
  clang/test/SemaCXX/coroutine-rvo.cpp

Index: clang/test/SemaCXX/coroutine-rvo.cpp
===================================================================
--- clang/test/SemaCXX/coroutine-rvo.cpp
+++ clang/test/SemaCXX/coroutine-rvo.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -stdlib=libc++ -std=c++1z -fcoroutines-ts -fsyntax-only
+// RUN: %clang_cc1 -verify -std=c++17 -fcoroutines-ts -fsyntax-only %s
 
 namespace std::experimental {
 template <class Promise = void> struct coroutine_handle {
@@ -39,10 +39,14 @@
 };
 
 struct MoveOnly {
-  MoveOnly() {};
+  MoveOnly() = default;
   MoveOnly(const MoveOnly&) = delete;
-  MoveOnly(MoveOnly&&) noexcept {};
-  ~MoveOnly() {};
+  MoveOnly(MoveOnly &&) = default;
+};
+
+struct NoCopyNoMove {
+  NoCopyNoMove() = default;
+  NoCopyNoMove(const NoCopyNoMove &) = delete;
 };
 
 template <typename T>
@@ -52,18 +56,93 @@
     auto final_suspend() noexcept { return suspend_never{}; }
     auto get_return_object() { return task{}; }
     static void unhandled_exception() {}
-    void return_value(T&& value) {}
+    void return_value(T &&value) {} // expected-note 4{{passing argument}}
   };
 };
 
-task<MoveOnly> f() {
-  MoveOnly value;
+task<NoCopyNoMove> local2val() {
+  NoCopyNoMove value;
+  co_return value;
+}
+
+task<NoCopyNoMove &> local2ref() {
+  NoCopyNoMove value;
+  co_return value; // expected-error {{non-const lvalue reference to type 'NoCopyNoMove' cannot bind to a temporary of type 'NoCopyNoMove'}}
+}
+
+// We need the move constructor for construction of the coroutine.
+task<MoveOnly> param2val(MoveOnly value) {
   co_return value;
 }
 
-int main() {
-  f();
-  return 0;
+task<NoCopyNoMove> lvalue2val(NoCopyNoMove &value) {
+  co_return value; // expected-error {{rvalue reference to type 'NoCopyNoMove' cannot bind to lvalue of type 'NoCopyNoMove'}}
+}
+
+task<NoCopyNoMove> rvalue2val(NoCopyNoMove &&value) {
+  co_return value;
+}
+
+task<NoCopyNoMove &> lvalue2ref(NoCopyNoMove &value) {
+  co_return value;
+}
+
+task<NoCopyNoMove &> rvalue2ref(NoCopyNoMove &&value) {
+  co_return value; // expected-error {{non-const lvalue reference to type 'NoCopyNoMove' cannot bind to a temporary of type 'NoCopyNoMove'}}
+}
+
+struct To {
+  operator MoveOnly() &&;
+};
+task<MoveOnly> conversion_operator() {
+  To t;
+  co_return t;
+}
+
+struct Construct {
+  Construct(MoveOnly);
+};
+task<Construct> converting_constructor() {
+  MoveOnly w;
+  co_return w;
 }
 
-// expected-no-diagnostics
+struct Derived : MoveOnly {};
+task<MoveOnly> derived2base() {
+  Derived result;
+  co_return result;
+}
+
+struct RetThis {
+  task<RetThis> foo() && {
+    co_return *this; // expected-error {{rvalue reference to type 'RetThis' cannot bind to lvalue of type 'RetThis'}}
+  }
+};
+
+template <typename, typename>
+struct is_same { static constexpr bool value = false; };
+
+template <typename T>
+struct is_same<T, T> { static constexpr bool value = true; };
+
+template <typename T>
+struct template_return_task {
+  struct promise_type {
+    auto initial_suspend() { return suspend_never{}; }
+    auto final_suspend() noexcept { return suspend_never{}; }
+    auto get_return_object() { return template_return_task{}; }
+    static void unhandled_exception();
+    template <typename U>
+    void return_value(U &&value) {
+      static_assert(is_same<T, U>::value);
+    }
+  };
+};
+
+template_return_task<MoveOnly> param2template(MoveOnly value) {
+  co_return value; // We should deduce U = MoveOnly.
+}
+
+template_return_task<NoCopyNoMove &> lvalue2template(NoCopyNoMove &value) {
+  co_return value; // We should deduce U = NoCopyNoMove&.
+}
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,5 @@
-// 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 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -fsyntax-only -verify=expected %s
 class X {
   X(const X&);
 
Index: clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-14.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-14.cpp
+++ clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-14.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -verify -std=c++1y %s
+// RUN: %clang_cc1 -verify -std=c++2b -verify=expected,cxx2b %s
+// RUN: %clang_cc1 -verify -std=c++14 -verify=expected,cxx14 %s
 
 namespace std {
   template<typename T> struct initializer_list {
@@ -28,7 +29,7 @@
 auto x4a = (i);
 decltype(auto) x4d = (i);
 using Int = decltype(x4a);
-using IntLRef = decltype(x4d);
+using IntLRef = decltype(x4d); // cxx2b-note {{previous definition is here}}
 
 auto x5a = f();
 decltype(auto) x5d = f();
@@ -79,7 +80,7 @@
 auto f3a(int n) { return (n); }
 decltype(auto) f3d(int n) { return (n); } // expected-warning {{reference to stack memory}}
 using Int = decltype(f3a(0));
-using IntLRef = decltype(f3d(0));
+using IntLRef = decltype(f3d(0)); // cxx2b-error {{type alias redefinition with different types ('decltype(f3d(0))' (aka 'int &&') vs 'decltype(x4d)' (aka 'int &'))}}
 
 auto f4a(int n) { return f(); }
 decltype(auto) f4d(int n) { return f(); }
@@ -89,7 +90,7 @@
 auto f5aa(int n) { auto x = f(); return x; }
 auto f5ad(int n) { decltype(auto) x = f(); return x; }
 decltype(auto) f5da(int n) { auto x = f(); return x; }
-decltype(auto) f5dd(int n) { decltype(auto) x = f(); return x; } // expected-error {{rvalue reference to type 'int' cannot bind to lvalue}}
+decltype(auto) f5dd(int n) { decltype(auto) x = f(); return x; } // cxx14-error {{rvalue reference to type 'int' cannot bind to lvalue}}
 using Int = decltype(f5aa(0));
 using Int = decltype(f5ad(0));
 using Int = decltype(f5da(0));
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_20,cxx20_2b %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17,cxx11_20 %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17,cxx11_20 %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17,cxx11_20 %s
 
 namespace test_delete_function {
 struct A1 {
@@ -54,38 +55,38 @@
 namespace test_implicitly_movable_rvalue_ref {
 struct A1 {
   A1(A1 &&);
-  A1(const A1 &) = delete; // cxx11_14_17-note {{'A1' has been explicitly marked deleted here}}
+  A1(const A1 &) = delete; // cxx11_17-note {{'A1' has been explicitly marked deleted here}}
 };
 A1 test1(A1 &&a) {
-  return a; // cxx11_14_17-error {{call to deleted constructor of 'test_implicitly_movable_rvalue_ref::A1'}}
+  return a; // cxx11_17-error {{call to deleted constructor of 'test_implicitly_movable_rvalue_ref::A1'}}
 }
 
 struct A2 {
   A2(A2 &&);
 
 private:
-  A2(const A2 &); // cxx11_14_17-note {{declared private here}}
+  A2(const A2 &); // cxx11_17-note {{declared private here}}
 };
 A2 test2(A2 &&a) {
-  return a; // cxx11_14_17-error {{calling a private constructor of class 'test_implicitly_movable_rvalue_ref::A2'}}
+  return a; // cxx11_17-error {{calling a private constructor of class 'test_implicitly_movable_rvalue_ref::A2'}}
 }
 
 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,14 @@
 
 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}}
+  // expected-note@-1 {{'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,15 +112,21 @@
   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'}}
   }
 }
+
+void test3(A1 a) try {
+  func();
+} catch (...) {
+  throw a; // expected-error {{call to deleted constructor of 'test_throw_parameter::A1'}}
+}
 } // namespace test_throw_parameter
 
 // In C++20, during the first overload resolution, the selected function no
@@ -128,42 +136,42 @@
 
 struct A1 {
   operator C() &&;
-  operator C() const & = delete; // cxx11_14_17-note {{'operator C' has been explicitly marked deleted here}}
+  operator C() const & = delete; // cxx11_17-note {{'operator C' has been explicitly marked deleted here}}
 };
 C test1() {
   A1 a;
-  return a; // cxx11_14_17-error {{conversion function from 'test_non_ctor_conversion::A1' to 'test_non_ctor_conversion::C' invokes a deleted function}}
+  return a; // cxx11_17-error {{conversion function from 'test_non_ctor_conversion::A1' to 'test_non_ctor_conversion::C' invokes a deleted function}}
 }
 
 struct A2 {
   operator C() &&;
 
 private:
-  operator C() const &; // cxx11_14_17-note {{declared private here}}
+  operator C() const &; // cxx11_17-note {{declared private here}}
 };
 C test2() {
   A2 a;
-  return a; // cxx11_14_17-error {{'operator C' is a private member of 'test_non_ctor_conversion::A2'}}
+  return a; // cxx11_17-error {{'operator C' is a private member of 'test_non_ctor_conversion::A2'}}
 }
 
 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
 
@@ -182,35 +190,35 @@
   NeedRvalueRef(B2 &&);
 };
 struct NeedValue {
-  NeedValue(A1); // cxx11_14_17-note 2 {{passing argument to parameter here}}
+  NeedValue(A1); // cxx11_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);
 };
 
 struct A1 {
   A1();
   A1(A1 &&);
-  A1(const A1 &) = delete; // cxx11_14_17-note 3 {{'A1' has been explicitly marked deleted here}}
+  A1(const A1 &) = delete; // cxx11_17-note 3 {{'A1' has been explicitly marked deleted here}}
 };
 NeedValue test_1_1() {
   // not rvalue reference
   // same type
   A1 a;
-  return a; // cxx11_14_17-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::A1'}}
+  return a; // cxx11_17-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::A1'}}
 }
 class DerivedA1 : public A1 {};
 A1 test_1_2() {
   // rvalue reference
   // not same type
   DerivedA1 a;
-  return a; // cxx11_14_17-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::A1'}}
+  return a; // cxx11_17-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::A1'}}
 }
 NeedValue test_1_3() {
   // not rvalue reference
   // not same type
   DerivedA1 a;
-  return a; // cxx11_14_17-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::A1'}}
+  return a; // cxx11_17-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::A1'}}
 }
 
 struct A2 {
@@ -218,51 +226,51 @@
   A2(A2 &&);
 
 private:
-  A2(const A2 &); // cxx11_14_17-note 3 {{declared private here}}
+  A2(const A2 &); // cxx11_17-note 3 {{declared private here}}
 };
 NeedValue test_2_1() {
   // not rvalue reference
   // same type
   A2 a;
-  return a; // cxx11_14_17-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::A2'}}
+  return a; // cxx11_17-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::A2'}}
 }
 class DerivedA2 : public A2 {};
 A2 test_2_2() {
   // rvalue reference
   // not same type
   DerivedA2 a;
-  return a; // cxx11_14_17-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::A2'}}
+  return a; // cxx11_17-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::A2'}}
 }
 NeedValue test_2_3() {
   // not rvalue reference
   // not same type
   DerivedA2 a;
-  return a; // cxx11_14_17-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::A2'}}
+  return a; // cxx11_17-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::A2'}}
 }
 
 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 +278,67 @@
   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}}
+  // cxx2b-note@-1 {{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}}
+  // cxx2b-note@-1 {{candidate constructor not viable: expects an lvalue for 1st argument}}
+};
+struct MoveOnly {
+  MoveOnly();
+  MoveOnly(MoveOnly &&);
+};
+MoveOnly &&rref();
+
+MoveOnly &&test1(MoveOnly &&w) {
+  return w; // cxx11_20-error {{cannot bind to lvalue of type}}
+}
+
+CopyOnly test2(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 &&test3(T &&x) { return x; } // cxx11_20-error {{cannot bind to lvalue of type}}
+template MoveOnly& test3<MoveOnly&>(MoveOnly&);
+template MoveOnly&& test3<MoveOnly>(MoveOnly&&); // cxx11_20-note {{in instantiation of function template specialization}}
+
+MoveOnly &&test4() {
+  MoveOnly &&x = rref();
+  return x; // cxx11_20-error {{cannot bind to lvalue of type}}
+}
+
+void test5() try {
+  CopyOnly x;
+  throw x; // cxx2b-error {{no matching constructor for initialization}}
+} 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;
@@ -3221,15 +3222,14 @@
   ExprResult Res = ExprError();
   bool NeedSecondOverloadResolution = true;
 
-  if (AllowNRVO) {
-    CopyElisionSemanticsKind CESK = CES_Strict;
-    if (getLangOpts().CPlusPlus20) {
-      CESK = CES_ImplicitlyMovableCXX20;
-    } else if (getLangOpts().CPlusPlus11) {
-      CESK = CES_ImplicitlyMovableCXX11CXX14CXX17;
-    }
-
+  if (AllowNRVO && !getLangOpts().CPlusPlus2b) {
     if (!NRVOCandidate) {
+      CopyElisionSemanticsKind CESK = CES_Strict;
+      if (getLangOpts().CPlusPlus20) {
+        CESK = CES_ImplicitlyMovableCXX20;
+      } else if (getLangOpts().CPlusPlus11) {
+        CESK = CES_ImplicitlyMovableCXX11CXX14CXX17;
+      }
       NRVOCandidate = getCopyElisionCandidate(ResultType, Value, CESK);
     }
 
@@ -3650,6 +3650,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);
 
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 (IsThrownVarInScope && 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();
@@ -877,8 +886,9 @@
     InitializedEntity Entity = InitializedEntity::InitializeException(
         OpLoc, ExceptionObjectTy,
         /*NRVO=*/NRVOVariable != nullptr);
-    ExprResult Res = PerformMoveOrCopyInitialization(
-        Entity, NRVOVariable, QualType(), Ex, IsThrownVarInScope);
+    ExprResult Res =
+        PerformMoveOrCopyInitialization(Entity, NRVOVariable, QualType(), Ex,
+                                        /*AllowNRVO=*/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
@@ -994,26 +994,15 @@
     E = R.get();
   }
 
-  // Move the return value if we can
-  if (E) {
-    const VarDecl *NRVOCandidate = this->getCopyElisionCandidate(
-        E->getType(), E, CES_ImplicitlyMovableCXX20);
-    if (NRVOCandidate) {
-      InitializedEntity Entity =
-          InitializedEntity::InitializeResult(Loc, E->getType(), NRVOCandidate);
-      ExprResult MoveResult = this->PerformMoveOrCopyInitialization(
-          Entity, NRVOCandidate, E->getType(), E);
-      if (MoveResult.get())
-        E = MoveResult.get();
-    }
-  }
-
-  // FIXME: If the operand is a reference to a variable that's about to go out
-  // of scope, we should treat the operand as an xvalue for this overload
-  // resolution.
   VarDecl *Promise = FSI->CoroutinePromise;
   ExprResult PC;
   if (E && (isa<InitListExpr>(E) || !E->getType()->isVoidType())) {
+    if (const VarDecl *NRVOCandidate = getCopyElisionCandidate(
+            E->getType(), E, CES_ImplicitlyMovableCXX20)) {
+      E = ImplicitCastExpr::Create(
+          Context, NRVOCandidate->getType().getNonReferenceType(), CK_NoOp, E,
+          nullptr, VK_XValue, FPOptionsOverride());
+    }
     PC = buildPromiseCall(*this, Promise, Loc, "return_value", E);
   } else {
     E = MakeFullDiscardedValueExpr(E).get();
@@ -1570,7 +1559,7 @@
     // Trigger a nice error message.
     InitializedEntity Entity =
         InitializedEntity::InitializeResult(Loc, FnRetType, false);
-    S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue);
+    S.PerformCopyInitialization(Entity, SourceLocation(), ReturnValue);
     noteMemberDeclaredHere(S, ReturnValue, Fn);
     return false;
   }
@@ -1586,8 +1575,8 @@
     return false;
 
   InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl);
-  ExprResult Res = S.PerformMoveOrCopyInitialization(Entity, nullptr, GroType,
-                                                     this->ReturnValue);
+  ExprResult Res =
+      S.PerformCopyInitialization(Entity, SourceLocation(), ReturnValue);
   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>();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to