mizvekov updated this revision to Diff 332186.
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/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/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>();
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -3428,8 +3428,7 @@
ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
const VarDecl *NRVOCandidate,
- QualType ResultType,
- Expr *Value,
+ QualType ResultType, Expr *Value,
bool AllowNRVO = true);
bool CanPerformAggregateInitializationForOverloadResolution(
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits