diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/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( diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/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(); diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/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(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; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/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(); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/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(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(E->IgnoreParens()); @@ -3086,15 +3088,14 @@ if (VD->hasAttr()) 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() && - Context.getDeclAlign(VD) > Context.getTypeAlignInChars(VD->getType())) + if (!VDNonRefType->isDependentType() && VD->hasAttr() && + 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(getCurFunction())) return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8839,6 +8839,10 @@ if (E->isTypeDependent()) return S.Context.DependentTy; + Expr *IDExpr = E; + if (auto *ImplCastExpr = dyn_cast(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(E)) + if (const auto *SNTTPE = dyn_cast(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(E)) { + if (const DeclRefExpr *DRE = dyn_cast(IDExpr)) { const ValueDecl *VD = DRE->getDecl(); if (auto *TPO = dyn_cast(VD)) return TPO->getType().getUnqualifiedType(); return VD->getType(); - } else if (const MemberExpr *ME = dyn_cast(E)) { + } else if (const MemberExpr *ME = dyn_cast(IDExpr)) { if (const ValueDecl *VD = ME->getMemberDecl()) if (isa(VD) || isa(VD)) return VD->getType(); - } else if (const ObjCIvarRefExpr *IR = dyn_cast(E)) { + } else if (const ObjCIvarRefExpr *IR = dyn_cast(IDExpr)) { return IR->getDecl()->getType(); - } else if (const ObjCPropertyRefExpr *PR = dyn_cast(E)) { + } else if (const ObjCPropertyRefExpr *PR = + dyn_cast(IDExpr)) { if (PR->isExplicitProperty()) return PR->getExplicitProperty()->getType(); - } else if (auto *PE = dyn_cast(E)) { + } else if (auto *PE = dyn_cast(IDExpr)) { return PE->getType(); } @@ -8885,8 +8890,8 @@ // entity. using namespace sema; if (S.getCurLambda()) { - if (isa(E)) { - if (DeclRefExpr *DRE = dyn_cast(E->IgnoreParens())) { + if (isa(IDExpr)) { + if (DeclRefExpr *DRE = dyn_cast(IDExpr->IgnoreParens())) { if (VarDecl *Var = dyn_cast(DRE->getDecl())) { QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation()); if (!T.isNull()) diff --git a/clang/test/CXX/class/class.init/class.copy.elision/p3.cpp b/clang/test/CXX/class/class.init/class.copy.elision/p3.cpp --- a/clang/test/CXX/class/class.init/class.copy.elision/p3.cpp +++ b/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 T &&test3(T &&x) { return x; } // cxx11_20-error {{cannot bind to lvalue of type}} +template MoveOnly& test3(MoveOnly&); +template MoveOnly&& test3(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 diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-14.cpp rename from clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp rename to clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-14.cpp --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp +++ b/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 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)); diff --git a/clang/test/CXX/special/class.copy/p33-0x.cpp b/clang/test/CXX/special/class.copy/p33-0x.cpp --- a/clang/test/CXX/special/class.copy/p33-0x.cpp +++ b/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&); diff --git a/clang/test/SemaCXX/coroutine-rvo.cpp b/clang/test/SemaCXX/coroutine-rvo.cpp --- a/clang/test/SemaCXX/coroutine-rvo.cpp +++ b/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 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 @@ -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 f() { - MoveOnly value; +task local2val() { + NoCopyNoMove value; + co_return value; +} + +task 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 param2val(MoveOnly value) { co_return value; } -int main() { - f(); - return 0; +task lvalue2val(NoCopyNoMove &value) { + co_return value; // expected-error {{rvalue reference to type 'NoCopyNoMove' cannot bind to lvalue of type 'NoCopyNoMove'}} +} + +task rvalue2val(NoCopyNoMove &&value) { + co_return value; +} + +task lvalue2ref(NoCopyNoMove &value) { + co_return value; +} + +task 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 conversion_operator() { + To t; + co_return t; +} + +struct Construct { + Construct(MoveOnly); +}; +task converting_constructor() { + MoveOnly w; + co_return w; } -// expected-no-diagnostics +struct Derived : MoveOnly {}; +task derived2base() { + Derived result; + co_return result; +} + +struct RetThis { + task foo() && { + co_return *this; // expected-error {{rvalue reference to type 'RetThis' cannot bind to lvalue of type 'RetThis'}} + } +}; + +template +struct is_same { static constexpr bool value = false; }; + +template +struct is_same { static constexpr bool value = true; }; + +template +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 + void return_value(U &&value) { + static_assert(is_same::value); + } + }; +}; + +template_return_task param2template(MoveOnly value) { + co_return value; // We should deduce U = MoveOnly. +} + +template_return_task lvalue2template(NoCopyNoMove &value) { + co_return value; // We should deduce U = NoCopyNoMove&. +}