forked from OSchip/llvm-project
[clang] C++98 implicit moves are back with a vengeance
After taking C++98 implicit moves out in D104500, we put it back in, but now in a new form which preserves compatibility with pure C++98 programs, while at the same time giving almost all the goodies from P1825. * We use the exact same rules as C++20 with regards to which id-expressions are move eligible. The previous incarnation would only benefit from the proper subset which is copy ellidable. This means we can implicit move, in addition: * Parameters. * RValue references. * Exception variables. * Variables with higher-than-natural required alignment. * Objects with different type from the function return type. * We preserve the two-overload resolution, with one small tweak to the first one: If we either pick a (possibly converting) constructor which does not take an rvalue reference, or a user conversion operator which is not ref-qualified, we abort into the second overload resolution. This gives C++98 almost all the implicit move patterns which we had created test cases for, while at the same time preserving the meaning of these three patterns, which are found in pure C++98 programs: * Classes with both const and non-const copy constructors, but no move constructors, continue to have their non-const copy constructor selected. * We continue to reject as ambiguous the following pattern: ``` struct A { A(B &); }; struct B { operator A(); }; A foo(B x) { return x; } ``` * We continue to pick the copy constructor in the following pattern: ``` class AutoPtrRef { }; struct AutoPtr { AutoPtr(AutoPtr &); AutoPtr(); AutoPtr(AutoPtrRef); operator AutoPtrRef(); }; AutoPtr test_auto_ptr() { AutoPtr p; return p; } ``` Signed-off-by: Matheus Izvekov <mizvekov@gmail.com> Reviewed By: Quuxplusone Differential Revision: https://reviews.llvm.org/D105756
This commit is contained in:
parent
14f77576c9
commit
03282f2fe1
|
@ -3451,6 +3451,28 @@ const VarDecl *Sema::getCopyElisionCandidate(NamedReturnInfo &Info,
|
|||
return Info.isCopyElidable() ? Info.Candidate : nullptr;
|
||||
}
|
||||
|
||||
/// Verify that the initialization sequence that was picked for the
|
||||
/// first overload resolution is permissible under C++98.
|
||||
///
|
||||
/// Reject (possibly converting) contructors not taking an rvalue reference,
|
||||
/// or user conversion operators which are not ref-qualified.
|
||||
static bool
|
||||
VerifyInitializationSequenceCXX98(const Sema &S,
|
||||
const InitializationSequence &Seq) {
|
||||
const auto *Step = llvm::find_if(Seq.steps(), [](const auto &Step) {
|
||||
return Step.Kind == InitializationSequence::SK_ConstructorInitialization ||
|
||||
Step.Kind == InitializationSequence::SK_UserConversion;
|
||||
});
|
||||
if (Step != Seq.step_end()) {
|
||||
const auto *FD = Step->Function.Function;
|
||||
if (isa<CXXConstructorDecl>(FD)
|
||||
? !FD->getParamDecl(0)->getType()->isRValueReferenceType()
|
||||
: cast<CXXMethodDecl>(FD)->getRefQualifier() == RQ_None)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Perform the initialization of a potentially-movable value, which
|
||||
/// is the result of return value.
|
||||
///
|
||||
|
@ -3461,8 +3483,7 @@ ExprResult
|
|||
Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
|
||||
const NamedReturnInfo &NRInfo,
|
||||
Expr *Value) {
|
||||
if (getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus2b &&
|
||||
NRInfo.isMoveEligible()) {
|
||||
if (!getLangOpts().CPlusPlus2b && NRInfo.isMoveEligible()) {
|
||||
ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),
|
||||
CK_NoOp, Value, VK_XValue, FPOptionsOverride());
|
||||
Expr *InitExpr = &AsRvalue;
|
||||
|
@ -3470,7 +3491,9 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
|
|||
Value->getBeginLoc());
|
||||
InitializationSequence Seq(*this, Entity, Kind, InitExpr);
|
||||
auto Res = Seq.getFailedOverloadResult();
|
||||
if (Res == OR_Success || Res == OR_Deleted) {
|
||||
if ((Res == OR_Success || Res == OR_Deleted) &&
|
||||
(getLangOpts().CPlusPlus11 ||
|
||||
VerifyInitializationSequenceCXX98(*this, Seq))) {
|
||||
// Promote "AsRvalue" to the heap, since we now need this
|
||||
// expression node to persist.
|
||||
Value =
|
||||
|
|
|
@ -7,11 +7,11 @@ namespace test_delete_function {
|
|||
struct A1 {
|
||||
A1();
|
||||
A1(const A1 &);
|
||||
A1(A1 &&) = delete; // cxx11_2b-note {{'A1' has been explicitly marked deleted here}}
|
||||
A1(A1 &&) = delete; // expected-note {{'A1' has been explicitly marked deleted here}}
|
||||
};
|
||||
A1 test1() {
|
||||
A1 a;
|
||||
return a; // cxx11_2b-error {{call to deleted constructor of 'test_delete_function::A1'}}
|
||||
return a; // expected-error {{call to deleted constructor of 'test_delete_function::A1'}}
|
||||
}
|
||||
|
||||
struct A2 {
|
||||
|
@ -19,33 +19,33 @@ struct A2 {
|
|||
A2(const A2 &);
|
||||
|
||||
private:
|
||||
A2(A2 &&); // cxx11_2b-note {{declared private here}}
|
||||
A2(A2 &&); // expected-note {{declared private here}}
|
||||
};
|
||||
A2 test2() {
|
||||
A2 a;
|
||||
return a; // cxx11_2b-error {{calling a private constructor of class 'test_delete_function::A2'}}
|
||||
return a; // expected-error {{calling a private constructor of class 'test_delete_function::A2'}}
|
||||
}
|
||||
|
||||
struct C {};
|
||||
|
||||
struct B1 {
|
||||
B1(C &);
|
||||
B1(C &&) = delete; // cxx11_2b-note {{'B1' has been explicitly marked deleted here}}
|
||||
B1(C &&) = delete; // expected-note {{'B1' has been explicitly marked deleted here}}
|
||||
};
|
||||
B1 test3() {
|
||||
C c;
|
||||
return c; // cxx11_2b-error {{conversion function from 'test_delete_function::C' to 'test_delete_function::B1' invokes a deleted function}}
|
||||
return c; // expected-error {{conversion function from 'test_delete_function::C' to 'test_delete_function::B1' invokes a deleted function}}
|
||||
}
|
||||
|
||||
struct B2 {
|
||||
B2(C &);
|
||||
|
||||
private:
|
||||
B2(C &&); // cxx11_2b-note {{declared private here}}
|
||||
B2(C &&); // expected-note {{declared private here}}
|
||||
};
|
||||
B2 test4() {
|
||||
C c;
|
||||
return c; // cxx11_2b-error {{calling a private constructor of class 'test_delete_function::B2'}}
|
||||
return c; // expected-error {{calling a private constructor of class 'test_delete_function::B2'}}
|
||||
}
|
||||
} // namespace test_delete_function
|
||||
|
||||
|
@ -54,38 +54,38 @@ B2 test4() {
|
|||
namespace test_implicitly_movable_rvalue_ref {
|
||||
struct A1 {
|
||||
A1(A1 &&);
|
||||
A1(const A1 &) = delete; // cxx98-note {{marked deleted here}}
|
||||
A1(const A1 &) = delete;
|
||||
};
|
||||
A1 test1(A1 &&a) {
|
||||
return a; // cxx98-error {{call to deleted constructor}}
|
||||
return a;
|
||||
}
|
||||
|
||||
struct A2 {
|
||||
A2(A2 &&);
|
||||
|
||||
private:
|
||||
A2(const A2 &); // cxx98-note {{declared private here}}
|
||||
A2(const A2 &);
|
||||
};
|
||||
A2 test2(A2 &&a) {
|
||||
return a; // cxx98-error {{calling a private constructor}}
|
||||
return a;
|
||||
}
|
||||
|
||||
struct B1 {
|
||||
B1(const B1 &);
|
||||
B1(B1 &&) = delete; // cxx11_2b-note {{'B1' has been explicitly marked deleted here}}
|
||||
B1(B1 &&) = delete; // expected-note {{'B1' has been explicitly marked deleted here}}
|
||||
};
|
||||
B1 test3(B1 &&b) {
|
||||
return b; // cxx11_2b-error {{call to deleted constructor of 'test_implicitly_movable_rvalue_ref::B1'}}
|
||||
return b; // expected-error {{call to deleted constructor of 'test_implicitly_movable_rvalue_ref::B1'}}
|
||||
}
|
||||
|
||||
struct B2 {
|
||||
B2(const B2 &);
|
||||
|
||||
private:
|
||||
B2(B2 &&); // cxx11_2b-note {{declared private here}}
|
||||
B2(B2 &&); // expected-note {{declared private here}}
|
||||
};
|
||||
B2 test4(B2 &&b) {
|
||||
return b; // cxx11_2b-error {{calling a private constructor of class 'test_implicitly_movable_rvalue_ref::B2'}}
|
||||
return b; // expected-error {{calling a private constructor of class 'test_implicitly_movable_rvalue_ref::B2'}}
|
||||
}
|
||||
} // namespace test_implicitly_movable_rvalue_ref
|
||||
|
||||
|
@ -96,13 +96,13 @@ void func();
|
|||
|
||||
struct A1 {
|
||||
A1(const A1 &);
|
||||
A1(A1 &&) = delete; // cxx11_2b-note 2{{'A1' has been explicitly marked deleted here}}
|
||||
A1(A1 &&) = delete; // expected-note 2{{'A1' has been explicitly marked deleted here}}
|
||||
};
|
||||
void test1() {
|
||||
try {
|
||||
func();
|
||||
} catch (A1 a) {
|
||||
throw a; // cxx11_2b-error {{call to deleted constructor of 'test_throw_parameter::A1'}}
|
||||
throw a; // expected-error {{call to deleted constructor of 'test_throw_parameter::A1'}}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,20 +110,20 @@ struct A2 {
|
|||
A2(const A2 &);
|
||||
|
||||
private:
|
||||
A2(A2 &&); // cxx11_2b-note {{declared private here}}
|
||||
A2(A2 &&); // expected-note {{declared private here}}
|
||||
};
|
||||
void test2() {
|
||||
try {
|
||||
func();
|
||||
} catch (A2 a) {
|
||||
throw a; // cxx11_2b-error {{calling a private constructor of class 'test_throw_parameter::A2'}}
|
||||
throw a; // expected-error {{calling a private constructor of class 'test_throw_parameter::A2'}}
|
||||
}
|
||||
}
|
||||
|
||||
void test3(A1 a) try {
|
||||
func();
|
||||
} catch (...) {
|
||||
throw a; // cxx11_2b-error {{call to deleted constructor of 'test_throw_parameter::A1'}}
|
||||
throw a; // expected-error {{call to deleted constructor of 'test_throw_parameter::A1'}}
|
||||
}
|
||||
} // namespace test_throw_parameter
|
||||
|
||||
|
@ -134,42 +134,42 @@ class C {};
|
|||
|
||||
struct A1 {
|
||||
operator C() &&;
|
||||
operator C() const & = delete; // cxx98-note {{marked deleted here}}
|
||||
operator C() const & = delete;
|
||||
};
|
||||
C test1() {
|
||||
A1 a;
|
||||
return a; // cxx98-error {{invokes a deleted function}}
|
||||
return a;
|
||||
}
|
||||
|
||||
struct A2 {
|
||||
operator C() &&;
|
||||
|
||||
private:
|
||||
operator C() const &; // cxx98-note {{declared private here}}
|
||||
operator C() const &;
|
||||
};
|
||||
C test2() {
|
||||
A2 a;
|
||||
return a; // cxx98-error {{'operator C' is a private member}}
|
||||
return a;
|
||||
}
|
||||
|
||||
struct B1 {
|
||||
operator C() const &;
|
||||
operator C() && = delete; // cxx11_2b-note {{'operator C' has been explicitly marked deleted here}}
|
||||
operator C() && = delete; // expected-note {{'operator C' has been explicitly marked deleted here}}
|
||||
};
|
||||
C test3() {
|
||||
B1 b;
|
||||
return b; // cxx11_2b-error {{conversion function from 'test_non_ctor_conversion::B1' to 'test_non_ctor_conversion::C' invokes a deleted function}}
|
||||
return b; // expected-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() &&; // cxx11_2b-note {{declared private here}}
|
||||
operator C() &&; // expected-note {{declared private here}}
|
||||
};
|
||||
C test4() {
|
||||
B2 b;
|
||||
return b; // cxx11_2b-error {{'operator C' is a private member of 'test_non_ctor_conversion::B2'}}
|
||||
return b; // expected-error {{'operator C' is a private member of 'test_non_ctor_conversion::B2'}}
|
||||
}
|
||||
} // namespace test_non_ctor_conversion
|
||||
|
||||
|
@ -197,7 +197,7 @@ struct NeedValue {
|
|||
struct A1 {
|
||||
A1();
|
||||
A1(A1 &&);
|
||||
A1(const A1 &) = delete; // cxx98-note 3{{marked deleted here}}
|
||||
A1(const A1 &) = delete; // cxx98-note 2 {{marked deleted here}}
|
||||
};
|
||||
NeedValue test_1_1() {
|
||||
// not rvalue reference
|
||||
|
@ -210,7 +210,7 @@ A1 test_1_2() {
|
|||
// rvalue reference
|
||||
// not same type
|
||||
DerivedA1 a;
|
||||
return a; // cxx98-error {{call to deleted constructor}}
|
||||
return a;
|
||||
}
|
||||
NeedValue test_1_3() {
|
||||
// not rvalue reference
|
||||
|
@ -224,7 +224,7 @@ struct A2 {
|
|||
A2(A2 &&);
|
||||
|
||||
private:
|
||||
A2(const A2 &); // cxx98-note 3{{declared private here}}
|
||||
A2(const A2 &); // cxx98-note 2 {{declared private here}}
|
||||
};
|
||||
NeedValue test_2_1() {
|
||||
// not rvalue reference
|
||||
|
@ -237,7 +237,7 @@ A2 test_2_2() {
|
|||
// rvalue reference
|
||||
// not same type
|
||||
DerivedA2 a;
|
||||
return a; // cxx98-error {{calling a private constructor}}
|
||||
return a;
|
||||
}
|
||||
NeedValue test_2_3() {
|
||||
// not rvalue reference
|
||||
|
@ -250,6 +250,7 @@ struct B1 {
|
|||
B1();
|
||||
B1(const B1 &);
|
||||
B1(B1 &&) = delete; // cxx11_2b-note 3 {{'B1' has been explicitly marked deleted here}}
|
||||
// cxx98-note@-1 {{'B1' has been explicitly marked deleted here}}
|
||||
};
|
||||
NeedValue test_3_1() {
|
||||
// not rvalue reference
|
||||
|
@ -262,7 +263,7 @@ B1 test_3_2() {
|
|||
// rvalue reference
|
||||
// not same type
|
||||
DerivedB1 b;
|
||||
return b; // cxx11_2b-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::B1'}}
|
||||
return b; // expected-error {{call to deleted constructor of 'test_ctor_param_rvalue_ref::B1'}}
|
||||
}
|
||||
NeedValue test_3_3() {
|
||||
// not rvalue reference
|
||||
|
@ -277,6 +278,7 @@ struct B2 {
|
|||
|
||||
private:
|
||||
B2(B2 &&); // cxx11_2b-note 3 {{declared private here}}
|
||||
// cxx98-note@-1 {{declared private here}}
|
||||
};
|
||||
NeedValue test_4_1() {
|
||||
// not rvalue reference
|
||||
|
@ -289,7 +291,7 @@ B2 test_4_2() {
|
|||
// rvalue reference
|
||||
// not same type
|
||||
DerivedB2 b;
|
||||
return b; // cxx11_2b-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::B2'}}
|
||||
return b; // expected-error {{calling a private constructor of class 'test_ctor_param_rvalue_ref::B2'}}
|
||||
}
|
||||
NeedValue test_4_3() {
|
||||
// not rvalue reference
|
||||
|
@ -302,20 +304,19 @@ NeedValue test_4_3() {
|
|||
namespace test_lvalue_ref_is_not_moved_from {
|
||||
|
||||
struct Target {};
|
||||
// cxx11_2b-note@-1 {{candidate constructor (the implicit copy constructor) not viable}}
|
||||
// cxx98-note@-2 2{{candidate constructor (the implicit copy constructor) not viable}}
|
||||
// cxx11_2b-note@-3 {{candidate constructor (the implicit move constructor) not viable}}
|
||||
// expected-note@-1 {{candidate constructor (the implicit copy constructor) not viable}}
|
||||
// cxx11_2b-note@-2 {{candidate constructor (the implicit move constructor) not viable}}
|
||||
|
||||
struct CopyOnly {
|
||||
CopyOnly(CopyOnly &&) = delete; // cxx11_2b-note {{has been explicitly marked deleted here}}
|
||||
CopyOnly(CopyOnly &&) = delete; // expected-note {{has been explicitly marked deleted here}}
|
||||
CopyOnly(CopyOnly&);
|
||||
operator Target() && = delete; // cxx11_2b-note {{has been explicitly marked deleted here}}
|
||||
operator Target() && = delete; // expected-note {{has been explicitly marked deleted here}}
|
||||
operator Target() &;
|
||||
};
|
||||
|
||||
struct MoveOnly {
|
||||
MoveOnly(MoveOnly &&); // cxx11_2b-note {{copy constructor is implicitly deleted because}}
|
||||
operator Target() &&; // expected-note {{candidate function not viable}} cxx98-note {{candidate function not viable}}
|
||||
operator Target() &&; // expected-note {{candidate function not viable}}
|
||||
};
|
||||
|
||||
extern CopyOnly copyonly;
|
||||
|
@ -328,7 +329,7 @@ CopyOnly t1() {
|
|||
|
||||
CopyOnly t2() {
|
||||
CopyOnly&& r = static_cast<CopyOnly&&>(copyonly);
|
||||
return r; // cxx11_2b-error {{call to deleted constructor}}
|
||||
return r; // expected-error {{call to deleted constructor}}
|
||||
}
|
||||
|
||||
MoveOnly t3() {
|
||||
|
@ -348,7 +349,7 @@ Target t5() {
|
|||
|
||||
Target t6() {
|
||||
CopyOnly&& r = static_cast<CopyOnly&&>(copyonly);
|
||||
return r; // cxx11_2b-error {{invokes a deleted function}}
|
||||
return r; // expected-error {{invokes a deleted function}}
|
||||
}
|
||||
|
||||
Target t7() {
|
||||
|
@ -358,7 +359,7 @@ Target t7() {
|
|||
|
||||
Target t8() {
|
||||
MoveOnly&& r = static_cast<MoveOnly&&>(moveonly);
|
||||
return r; // cxx98-error {{no viable conversion}}
|
||||
return r;
|
||||
}
|
||||
|
||||
} // namespace test_lvalue_ref_is_not_moved_from
|
||||
|
@ -400,6 +401,10 @@ Target t4() {
|
|||
|
||||
} // namespace test_rvalue_ref_to_nonobject
|
||||
|
||||
// Both tests in test_constandnonconstcopy, and also test_conversion::test1, are
|
||||
// "pure" C++98 tests (pretend 'delete' means 'private').
|
||||
// However we may extend implicit moves into C++98, we must make sure the
|
||||
// results in these are not changed.
|
||||
namespace test_constandnonconstcopy {
|
||||
struct ConstCopyOnly {
|
||||
ConstCopyOnly();
|
||||
|
@ -437,9 +442,9 @@ A test1(B x) { return x; } // cxx98-error-re {{conversion {{.*}} is ambiguous}}
|
|||
struct C {};
|
||||
struct D {
|
||||
operator C() &;
|
||||
operator C() const & = delete; // cxx11_2b-note {{marked deleted here}}
|
||||
operator C() const & = delete; // expected-note {{marked deleted here}}
|
||||
};
|
||||
C test2(D x) { return x; } // cxx11_2b-error {{invokes a deleted function}}
|
||||
C test2(D x) { return x; } // expected-error {{invokes a deleted function}}
|
||||
|
||||
} // namespace test_conversion
|
||||
|
||||
|
|
|
@ -120,7 +120,9 @@ void f(Yb& a) {
|
|||
char ch = a; // OK. calls Yb::operator char();
|
||||
}
|
||||
|
||||
// Test conversion + copy construction.
|
||||
// Test conversion + copy construction. This is a pure C++98 test.
|
||||
// However we may extend implicit moves into C++98, we must make sure the
|
||||
// result here is not changed.
|
||||
class AutoPtrRef { };
|
||||
|
||||
class AutoPtr {
|
||||
|
|
|
@ -14,6 +14,10 @@ struct CopyOnly {
|
|||
};
|
||||
TEST(CopyOnly); // cxx2b-error {{no matching constructor}}
|
||||
|
||||
// Both ConstCopyOnly and NonConstCopyOnly are
|
||||
// "pure" C++98 tests (pretend 'delete' means 'private').
|
||||
// However we may extend implicit moves into C++98, we must make sure the
|
||||
// results in these are not changed.
|
||||
struct ConstCopyOnly {
|
||||
ConstCopyOnly();
|
||||
ConstCopyOnly(ConstCopyOnly &) = delete; // cxx98-note {{marked deleted here}}
|
||||
|
@ -31,51 +35,51 @@ TEST(NonConstCopyOnly); // cxx11_2b-error {{call to deleted constructor}}
|
|||
struct CopyNoMove {
|
||||
CopyNoMove();
|
||||
CopyNoMove(CopyNoMove &);
|
||||
CopyNoMove(CopyNoMove &&) = delete; // cxx11_2b-note {{marked deleted here}}
|
||||
CopyNoMove(CopyNoMove &&) = delete; // cxx98_2b-note {{marked deleted here}}
|
||||
};
|
||||
TEST(CopyNoMove); // cxx11_2b-error {{call to deleted constructor}}
|
||||
TEST(CopyNoMove); // cxx98_2b-error {{call to deleted constructor}}
|
||||
|
||||
struct MoveOnly {
|
||||
MoveOnly();
|
||||
MoveOnly(MoveOnly &) = delete; // cxx98-note {{marked deleted here}}
|
||||
MoveOnly(MoveOnly &) = delete;
|
||||
MoveOnly(MoveOnly &&);
|
||||
};
|
||||
TEST(MoveOnly); // cxx98-error {{call to deleted constructor}}
|
||||
TEST(MoveOnly);
|
||||
|
||||
struct NoCopyNoMove {
|
||||
NoCopyNoMove();
|
||||
NoCopyNoMove(NoCopyNoMove &) = delete; // cxx98-note {{marked deleted here}}
|
||||
NoCopyNoMove(NoCopyNoMove &&) = delete; // cxx11_2b-note {{marked deleted here}}
|
||||
NoCopyNoMove(NoCopyNoMove &) = delete;
|
||||
NoCopyNoMove(NoCopyNoMove &&) = delete; // cxx98_2b-note {{marked deleted here}}
|
||||
};
|
||||
TEST(NoCopyNoMove); // cxx98_2b-error {{call to deleted constructor}}
|
||||
|
||||
struct ConvertingRVRef {
|
||||
ConvertingRVRef();
|
||||
ConvertingRVRef(ConvertingRVRef &) = delete; // cxx98-note {{marked deleted here}}
|
||||
ConvertingRVRef(ConvertingRVRef &) = delete;
|
||||
|
||||
struct X {};
|
||||
ConvertingRVRef(X &&);
|
||||
operator X() const & = delete;
|
||||
operator X() &&;
|
||||
};
|
||||
TEST(ConvertingRVRef); // cxx98-error {{call to deleted constructor}}
|
||||
TEST(ConvertingRVRef);
|
||||
|
||||
struct ConvertingCLVRef {
|
||||
ConvertingCLVRef();
|
||||
ConvertingCLVRef(ConvertingCLVRef &);
|
||||
|
||||
struct X {};
|
||||
ConvertingCLVRef(X &&); // cxx11_2b-note {{passing argument to parameter here}}
|
||||
ConvertingCLVRef(X &&); // cxx98_2b-note {{passing argument to parameter here}}
|
||||
operator X() const &;
|
||||
operator X() && = delete; // cxx11_2b-note {{marked deleted here}}
|
||||
operator X() && = delete; // cxx98_2b-note {{marked deleted here}}
|
||||
};
|
||||
TEST(ConvertingCLVRef); // cxx11_2b-error {{invokes a deleted function}}
|
||||
TEST(ConvertingCLVRef); // cxx98_2b-error {{invokes a deleted function}}
|
||||
|
||||
struct SubSubMove {};
|
||||
struct SubMove : SubSubMove {
|
||||
SubMove();
|
||||
SubMove(SubMove &) = delete; // cxx98-note {{marked deleted here}}
|
||||
SubMove(SubMove &) = delete;
|
||||
|
||||
SubMove(SubSubMove &&);
|
||||
};
|
||||
TEST(SubMove); // cxx98-error {{call to deleted constructor}}
|
||||
TEST(SubMove);
|
||||
|
|
Loading…
Reference in New Issue