nullptr.cpp updated this revision to Diff 313831.
nullptr.cpp added a comment.
rebase
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D88220/new/
https://reviews.llvm.org/D88220
Files:
clang/include/clang/Basic/DiagnosticGroups.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaCoroutine.cpp
clang/lib/Sema/SemaStmt.cpp
clang/test/CXX/class/class.init/class.copy.elision/p3.cpp
clang/test/SemaCXX/P1155.cpp
clang/test/SemaCXX/warn-return-std-move.cpp
clang/www/cxx_status.html
Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1203,6 +1203,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</td>
+ </tr>
</table>
<p>
Index: clang/test/SemaCXX/warn-return-std-move.cpp
===================================================================
--- clang/test/SemaCXX/warn-return-std-move.cpp
+++ clang/test/SemaCXX/warn-return-std-move.cpp
@@ -1,5 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -Wreturn-std-move-in-c++11 -std=c++14 -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -Wreturn-std-move-in-c++11 -std=c++14 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++20 -verify=cxx20 %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++17 -verify=cxx11_14_17 %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++14 -verify=cxx11_14_17 %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++11 -verify=cxx11_14_17 %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++17 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -check-prefix=CXX11_14_17-CHECK
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++14 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -check-prefix=CXX11_14_17-CHECK
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -check-prefix=CXX11_14_17-CHECK
+// cxx20-no-diagnostics
// definitions for std::move
namespace std {
@@ -71,37 +77,34 @@
Base test2() {
Derived d2;
return d2; // e1
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"std::move(d2)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"std::move(d2)"
}
ConstructFromDerived test3() {
Derived d3;
- return d3; // e2-cxx11
- // expected-warning@-1{{would have been copied despite being returned by name}}
- // expected-note@-2{{to avoid copying on older compilers}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"std::move(d3)"
+ return d3; // ok
}
ConstructFromBase test4() {
Derived d4;
return d4; // e3
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"std::move(d4)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"std::move(d4)"
}
ConvertFromDerived test5() {
Derived d5;
return d5; // e4
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"std::move(d5)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"std::move(d5)"
}
ConvertFromBase test6() {
Derived d6;
return d6; // e5
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"std::move(d6)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"std::move(d6)"
}
// These test cases should not produce the warning.
@@ -148,93 +151,89 @@
Derived testParam1(Derived d) { return d; }
Base testParam2(Derived d) {
return d; // e6
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
}
ConstructFromDerived testParam3(Derived d) {
- return d; // e7-cxx11
- // expected-warning@-1{{would have been copied despite being returned by name}}
- // expected-note@-2{{to avoid copying on older compilers}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ return d; // ok
}
ConstructFromBase testParam4(Derived d) {
return d; // e8
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
}
ConvertFromDerived testParam5(Derived d) {
return d; // e9
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
}
ConvertFromBase testParam6(Derived d) {
return d; // e10
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
}
// If the target is an rvalue reference parameter, do apply the diagnostic.
Derived testRParam1(Derived&& d) {
return d; // e11
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
}
Base testRParam2(Derived&& d) {
return d; // e12
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
}
ConstructFromDerived testRParam3(Derived&& d) {
return d; // e13
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
}
ConstructFromBase testRParam4(Derived&& d) {
return d; // e14
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
}
ConvertFromDerived testRParam5(Derived&& d) {
return d; // e15
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
}
ConvertFromBase testRParam6(Derived&& d) {
return d; // e16
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"std::move(d)"
}
// But if the return type is a reference type, then moving would be wrong.
Derived& testRetRef1(Derived&& d) { return d; }
Base& testRetRef2(Derived&& d) { return d; }
+#if __cplusplus >= 201402L
auto&& testRetRef3(Derived&& d) { return d; }
decltype(auto) testRetRef4(Derived&& d) { return (d); }
+#endif
// As long as we're checking parentheses, make sure parentheses don't disable the warning.
Base testParens1() {
Derived d;
return (d); // e17
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:15}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:15}:"std::move(d)"
}
ConstructFromDerived testParens2() {
Derived d;
- return (d); // e18-cxx11
- // expected-warning@-1{{would have been copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:15}:"std::move(d)"
+ return (d); // ok
}
@@ -242,44 +241,44 @@
void throw_derived();
Derived testEParam1() {
try { throw_derived(); } catch (Derived d) { return d; } // e19
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
__builtin_unreachable();
}
Base testEParam2() {
try { throw_derived(); } catch (Derived d) { return d; } // e20
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
__builtin_unreachable();
}
ConstructFromDerived testEParam3() {
try { throw_derived(); } catch (Derived d) { return d; } // e21
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
__builtin_unreachable();
}
ConstructFromBase testEParam4() {
try { throw_derived(); } catch (Derived d) { return d; } // e22
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
__builtin_unreachable();
}
ConvertFromDerived testEParam5() {
try { throw_derived(); } catch (Derived d) { return d; } // e23
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
__builtin_unreachable();
}
ConvertFromBase testEParam6() {
try { throw_derived(); } catch (Derived d) { return d; } // e24
- // expected-warning@-1{{will be copied despite being returned by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being returned by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:57-[[@LINE-3]]:58}:"std::move(d)"
__builtin_unreachable();
}
@@ -319,9 +318,9 @@
void test_throw1(Derived&& d) {
throw d; // e25
- // expected-warning@-1{{will be copied despite being thrown by name}}
- // expected-note@-2{{to avoid copying}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:12}:"std::move(d)"
+ // cxx11_14_17-warning@-1{{will be copied despite being thrown by name}}
+ // cxx11_14_17-note@-2{{to avoid copying}}
+ // CXX11_14_17-CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:12}:"std::move(d)"
}
void ok_throw1() { Derived d; throw d; }
Index: clang/test/SemaCXX/P1155.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/P1155.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=cxx20 %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fcxx-exceptions -verify=cxx11_14_17 %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -fcxx-exceptions -verify=cxx11_14_17 %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify=cxx11_14_17 %s
+// cxx20-no-diagnostics
+
+// Throwing
+namespace test_throwing {
+class Widget {
+public:
+ Widget(Widget &&);
+ Widget(const Widget &) = delete;
+};
+
+void seven(Widget w) {
+ throw w; // Clang already do this implicit move before -std=c++20
+}
+} // namespace test_throwing
+
+// Non-constructor conversion
+namespace test_non_constructor_conversion {
+class Widget {};
+
+struct To {
+ operator Widget() const & = delete; // cxx11_14_17-note {{'operator Widget' has been explicitly marked deleted here}}
+ operator Widget() &&;
+};
+
+Widget nine() {
+ To t;
+ return t; // cxx11_14_17-error {{conversion function from 'test_non_constructor_conversion::To' to 'test_non_constructor_conversion::Widget' invokes a deleted function}}
+}
+} // namespace test_non_constructor_conversion
+
+// By-value sinks
+namespace test_by_value_sinks {
+class Widget {
+public:
+ Widget();
+ Widget(Widget &&);
+ Widget(const Widget &) = delete; // cxx11_14_17-note {{'Widget' has been explicitly marked deleted here}}
+};
+
+struct Fowl {
+ Fowl(Widget); // cxx11_14_17-note {{passing argument to parameter here}}
+};
+
+Fowl eleven() {
+ Widget w;
+ return w; // cxx11_14_17-error {{call to deleted constructor of 'test_by_value_sinks::Widget'}}
+}
+} // namespace test_by_value_sinks
+
+// Slicing
+namespace test_slicing {
+class Base {
+public:
+ Base();
+ Base(Base &&);
+ Base(Base const &) = delete; // cxx11_14_17-note {{'Base' has been explicitly marked deleted here}}
+};
+
+class Derived : public Base {};
+
+Base thirteen() {
+ Derived result;
+ return result; // cxx11_14_17-error {{call to deleted constructor of 'test_slicing::Base'}}
+}
+} // namespace test_slicing
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,7 @@
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected %s
-// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fcxx-exceptions -verify=expected %s
-// RUN: %clang_cc1 -std=c++14 -fsyntax-only -fcxx-exceptions -verify=expected %s
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify=expected %s
+// 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
namespace test_delete_function {
struct A1 {
@@ -48,3 +48,203 @@
return c; // expected-error {{calling a private constructor of class 'test_delete_function::B2'}}
}
} // namespace test_delete_function
+
+// In C++20, implicitly movable entity can be rvalue reference to non-volatile
+// automatic object.
+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 test1(A1 &&a) {
+ return a; // cxx11_14_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 test2(A2 &&a) {
+ return a; // cxx11_14_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 test3(B1 &&b) {
+ return b; // cxx20-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 test4(B2 &&b) {
+ return b; // cxx20-error {{calling a private constructor of class 'test_implicitly_movable_rvalue_ref::B2'}}
+}
+} // namespace test_implicitly_movable_rvalue_ref
+
+// In C++20, operand of throw-expression can be function parameter or
+// catch-clause parameter.
+namespace test_throw_parameter {
+void func();
+
+struct A1 {
+ A1(const A1 &);
+ A1(A1 &&) = delete; // cxx20-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'}}
+ }
+}
+
+struct A2 {
+ A2(const A2 &);
+
+private:
+ A2(A2 &&); // cxx20-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'}}
+ }
+}
+} // namespace test_throw_parameter
+
+// In C++20, during the first overload resolution, the selected function no
+// need to be a constructor.
+namespace test_non_ctor_conversion {
+class C {};
+
+struct A1 {
+ operator C() &&;
+ operator C() const & = delete; // cxx11_14_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}}
+}
+
+struct A2 {
+ operator C() &&;
+
+private:
+ operator C() const &; // cxx11_14_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'}}
+}
+
+struct B1 {
+ operator C() const &;
+ operator C() && = delete; // cxx20-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}}
+}
+
+struct B2 {
+ operator C() const &;
+
+private:
+ operator C() &&; // cxx20-note {{declared private here}}
+};
+C test4() {
+ B2 b;
+ return b; // cxx20-error {{'operator C' is a private member of 'test_non_ctor_conversion::B2'}}
+}
+} // namespace test_non_ctor_conversion
+
+// In C++20, during the first overload resolution, the first parameter of the
+// selected function no need to be an rvalue reference to the object's type.
+namespace test_ctor_param_rvalue_ref {
+struct A1;
+struct A2;
+struct B1;
+struct B2;
+
+struct NeedRvalueRef {
+ NeedRvalueRef(A1 &&);
+ NeedRvalueRef(A2 &&);
+ NeedRvalueRef(B1 &&);
+ NeedRvalueRef(B2 &&);
+};
+struct NeedValue {
+ NeedValue(A1); // cxx11_14_17-note {{passing argument to parameter here}}
+ NeedValue(A2);
+ NeedValue(B1); // cxx20-note {{passing argument to parameter here}}
+ NeedValue(B2);
+};
+
+struct A1 {
+ A1();
+ A1(A1 &&);
+ A1(const A1 &) = delete; // cxx11_14_17-note {{'A1' has been explicitly marked deleted here}}
+};
+NeedRvalueRef test1() {
+ A1 a;
+ return a;
+}
+NeedValue test2() {
+ A1 a;
+ return a; // cxx11_14_17-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::A1'}}
+}
+
+struct A2 {
+ A2();
+ A2(A2 &&);
+
+private:
+ A2(const A2 &); // cxx11_14_17-note {{declared private here}}
+};
+NeedRvalueRef test3() {
+ A2 a;
+ return a;
+}
+NeedValue test4() {
+ A2 a;
+ return a; // cxx11_14_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 {{'B1' has been explicitly marked deleted here}}
+};
+NeedRvalueRef test5() {
+ B1 b;
+ return b; //TODO: warning?
+}
+NeedValue test6() {
+ B1 b;
+ return b; // cxx20-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::B1'}}
+}
+
+struct B2 {
+ B2();
+ B2(const B2 &);
+
+private:
+ B2(B2 &&); // cxx20-note {{declared private here}}
+};
+NeedRvalueRef test7() {
+ B2 b;
+ return b;
+}
+NeedValue test8() {
+ B2 b;
+ return b; // cxx20-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::B2'}}
+}
+} // namespace test_ctor_param_rvalue_ref
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3090,6 +3090,13 @@
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;
@@ -3105,13 +3112,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.
@@ -3127,7 +3134,7 @@
const VarDecl *NRVOCandidate,
QualType ResultType, Expr *&Value,
bool ConvertingConstructorsOnly,
- ExprResult &Res) {
+ bool IsDiagnosticsCheck, ExprResult &Res) {
ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),
CK_NoOp, Value, VK_XValue, FPOptionsOverride());
@@ -3151,9 +3158,10 @@
FunctionDecl *FD = Step.Function.Function;
if (ConvertingConstructorsOnly) {
if (isa<CXXConstructorDecl>(FD)) {
+ // 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.
@@ -3172,7 +3180,8 @@
// Check that overload resolution selected a constructor taking an
// rvalue reference. If it selected an lvalue reference, then we
// didn't need to cast this thing to an rvalue in the first place.
- if (!isa<RValueReferenceType>(FD->getParamDecl(0)->getType()))
+ if (IsDiagnosticsCheck &&
+ !isa<RValueReferenceType>(FD->getParamDecl(0)->getType()))
break;
} else if (isa<CXXMethodDecl>(FD)) {
// Check that overload resolution selected a conversion operator
@@ -3202,74 +3211,41 @@
/// 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.
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();
bool NeedSecondOverloadResolution = true;
if (AllowNRVO) {
- bool AffectedByCWG1579 = false;
+ CopyElisionSemanticsKind CESK = CES_Strict;
+ if (getLangOpts().CPlusPlus20) {
+ CESK = CES_ImplicitlyMovableCXX20;
+ } else if (getLangOpts().CPlusPlus11) {
+ CESK = CES_ImplicitlyMovableCXX11CXX14CXX17;
+ }
if (!NRVOCandidate) {
- NRVOCandidate = getCopyElisionCandidate(ResultType, Value, CES_Default);
- if (NRVOCandidate &&
- !getDiagnostics().isIgnored(diag::warn_return_std_move_in_cxx11,
- Value->getExprLoc())) {
- const VarDecl *NRVOCandidateInCXX11 =
- getCopyElisionCandidate(ResultType, Value, CES_FormerDefault);
- AffectedByCWG1579 = (!NRVOCandidateInCXX11);
- }
+ NRVOCandidate = getCopyElisionCandidate(ResultType, Value, CESK);
}
if (NRVOCandidate) {
- NeedSecondOverloadResolution = TryMoveInitialization(
- *this, Entity, NRVOCandidate, ResultType, Value, true, Res);
+ NeedSecondOverloadResolution =
+ TryMoveInitialization(*this, Entity, NRVOCandidate, ResultType, Value,
+ !getLangOpts().CPlusPlus20, false, Res);
}
- if (!NeedSecondOverloadResolution && AffectedByCWG1579) {
- QualType QT = NRVOCandidate->getType();
- if (QT.getNonReferenceType()
- .getUnqualifiedType()
- .isTriviallyCopyableType(Context)) {
- // Adding 'std::move' around a trivially copyable variable is probably
- // pointless. Don't suggest it.
- } else {
- // Common cases for this are returning unique_ptr<Derived> from a
- // function of return type unique_ptr<Base>, or returning T from a
- // function of return type Expected<T>. This is totally fine in a
- // post-CWG1579 world, but was not fine before.
- assert(!ResultType.isNull());
- SmallString<32> Str;
- Str += "std::move(";
- Str += NRVOCandidate->getDeclName().getAsString();
- Str += ")";
- Diag(Value->getExprLoc(), diag::warn_return_std_move_in_cxx11)
- << Value->getSourceRange()
- << NRVOCandidate->getDeclName() << ResultType << QT;
- Diag(Value->getExprLoc(), diag::note_add_std_move_in_cxx11)
- << FixItHint::CreateReplacement(Value->getSourceRange(), Str);
- }
- } else if (NeedSecondOverloadResolution &&
- !getDiagnostics().isIgnored(diag::warn_return_std_move,
- Value->getExprLoc())) {
- const VarDecl *FakeNRVOCandidate =
- getCopyElisionCandidate(QualType(), Value, CES_AsIfByStdMove);
+ if (!getLangOpts().CPlusPlus20 && NeedSecondOverloadResolution &&
+ !getDiagnostics().isIgnored(diag::warn_return_std_move,
+ Value->getExprLoc())) {
+ const VarDecl *FakeNRVOCandidate = getCopyElisionCandidate(
+ QualType(), Value, CES_ImplicitlyMovableCXX20);
if (FakeNRVOCandidate) {
QualType QT = FakeNRVOCandidate->getType();
if (QT->isLValueReferenceType()) {
@@ -3284,7 +3260,7 @@
ExprResult FakeRes = ExprError();
Expr *FakeValue = Value;
TryMoveInitialization(*this, Entity, FakeNRVOCandidate, ResultType,
- FakeValue, false, FakeRes);
+ FakeValue, false, true, FakeRes);
if (!FakeRes.isInvalid()) {
bool IsThrow =
(Entity.getKind() == InitializedEntity::EK_Exception);
Index: clang/lib/Sema/SemaCoroutine.cpp
===================================================================
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -996,7 +996,8 @@
// Move the return value if we can
if (E) {
- auto NRVOCandidate = this->getCopyElisionCandidate(E->getType(), E, CES_AsIfByStdMove);
+ const VarDecl *NRVOCandidate = this->getCopyElisionCandidate(
+ E->getType(), E, CES_ImplicitlyMovableCXX20);
if (NRVOCandidate) {
InitializedEntity Entity =
InitializedEntity::InitializeResult(Loc, E->getType(), NRVOCandidate);
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -4609,10 +4609,12 @@
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_ImplicitlyMovableCXX11CXX14CXX17 =
+ (CES_AllowParameters | CES_AllowDifferentTypes),
+ CES_ImplicitlyMovableCXX20 =
+ (CES_AllowParameters | CES_AllowDifferentTypes |
+ CES_AllowExceptionVariables | CES_AllowRValueReferenceType),
};
VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6317,13 +6317,6 @@
InGroup<ReturnStdMove>, DefaultIgnore;
def note_add_std_move : Note<
"call 'std::move' explicitly to avoid copying">;
-def warn_return_std_move_in_cxx11 : Warning<
- "prior to the resolution of a defect report against ISO C++11, "
- "local variable %0 would have been copied despite being returned by name, "
- "due to its not matching the function return type%diff{ ($ vs $)|}1,2">,
- InGroup<ReturnStdMoveInCXX11>, DefaultIgnore;
-def note_add_std_move_in_cxx11 : Note<
- "call 'std::move' explicitly to avoid copying on older compilers">;
def warn_string_plus_int : Warning<
"adding %0 to a string does not append to the string">,
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -495,7 +495,6 @@
def Padded : DiagGroup<"padded">;
def PessimizingMove : DiagGroup<"pessimizing-move">;
-def ReturnStdMoveInCXX11 : DiagGroup<"return-std-move-in-c++11">;
def ReturnStdMove : DiagGroup<"return-std-move">;
def PointerArith : DiagGroup<"pointer-arith">;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits