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">;
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">,
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,
// 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);
// Return false if VD is a __block variable. We don't want to implicitly move
// out of a __block variable during a return because we cannot assume the
// variable will no longer be used.
- if (VD->hasAttr<BlocksAttr>()) return false;
+ if (VD->hasAttr<BlocksAttr>())
+ return false;
// ...non-volatile...
if (VD->getType().isVolatileQualified())
return false;
+ // C++20 [class.copy.elision]p3:
+ // ...rvalue reference to a non-volatile...
+ if (VD->getType()->isRValueReferenceType() &&
+ (!(CESK & CES_AllowRValueReferenceType) ||
+ VD->getType().getNonReferenceType().isVolatileQualified()))
+ return false;
+
if (CESK & CES_AllowDifferentTypes)
return true;
/// 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.
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.
// 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
/// 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.
-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.
+/// 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) {
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, false, 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()) {
-// 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 {
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 2 {{passing argument to parameter here}}
+ NeedValue(A2);
+ NeedValue(B1); // cxx20-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}}
+};
+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'}}
+}
+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'}}
+}
+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'}}
+}
+
+struct A2 {
+ A2();
+ A2(A2 &&);
+
+private:
+ A2(const A2 &); // cxx11_14_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'}}
+}
+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'}}
+}
+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'}}
+}
+
+struct B1 {
+ B1();
+ B1(const B1 &);
+ B1(B1 &&) = delete; // cxx20-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'}}
+}
+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'}}
+}
+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'}}
+}
+
+struct B2 {
+ B2();
+ B2(const B2 &);
+
+private:
+ B2(B2 &&); // cxx20-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'}}
+}
+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'}}
+}
+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'}}
+}
+} // namespace test_ctor_param_rvalue_ref
--- /dev/null
+// 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
-// 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=expected %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++14 -verify=expected %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++11 -verify=expected %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++17 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -check-prefix=CHECK
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++14 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -check-prefix=CHECK
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -check-prefix=CHECK
// definitions for std::move
namespace std {
inline namespace foo {
template <class T> struct remove_reference { typedef T type; };
-template <class T> struct remove_reference<T&> { typedef T type; };
-template <class T> struct remove_reference<T&&> { typedef T type; };
+template <class T> struct remove_reference<T &> { typedef T type; };
+template <class T> struct remove_reference<T &&> { typedef T type; };
template <class T> typename remove_reference<T>::type &&move(T &&t);
} // namespace foo
// 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)"
+ Derived d3;
+ return d3; // ok
}
ConstructFromBase test4() {
Derived d4;
// 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
// 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() {
// 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)"
+ Derived d;
+ return (d); // ok
}
-
// If the target is a catch-handler parameter, do apply the diagnostic.
void throw_derived();
Derived testEParam1() {
namespace test_delete {
struct Base {
Base();
- Base(Base &&) = delete;
+ Base(Base &&) = delete; // cxx20-note {{'Base' has been explicitly marked deleted here}}
Base(Base const &);
};
Base test_ok() {
Derived d;
- return d;
+ return d; // cxx20-error {{call to deleted constructor of 'test_delete::Base'}}
}
} // namespace test_delete
<td class="full" align="center">Clang 2.9</td>
<tr> <!-- from Kona 2019-->
<td><a href="https://wg21.link/p1825r0">P1825R0</a> (<a href="#dr">DR</a>)</td>
- <td class="none" align="center">No</td>
+ <td class="unreleased" align="center">Clang 13</td>
</tr>
</tr>
<tr>
<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 13</td>
+ </tr>
</table>
<p>