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 @@ -4763,7 +4763,7 @@ bool isMoveEligible() const { return S != None; }; bool isCopyElidable() const { return S == MoveEligibleAndCopyElidable; } }; - NamedReturnInfo getNamedReturnInfo(const Expr *E, bool ForceCXX20 = false); + NamedReturnInfo getNamedReturnInfo(Expr *&E, bool ForceCXX2b = false); NamedReturnInfo getNamedReturnInfo(const VarDecl *VD, bool ForceCXX20 = false); const VarDecl *getCopyElisionCandidate(NamedReturnInfo &Info, 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,22 +994,10 @@ E = R.get(); } - // Move the return value if we can - NamedReturnInfo NRInfo = getNamedReturnInfo(E, /*ForceCXX20=*/true); - if (NRInfo.isMoveEligible()) { - InitializedEntity Entity = InitializedEntity::InitializeResult( - Loc, E->getType(), NRInfo.Candidate); - ExprResult MoveResult = PerformMoveOrCopyInitialization(Entity, NRInfo, 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())) { + getNamedReturnInfo(E, /*ForceCXX2b=*/true); PC = buildPromiseCall(*this, Promise, Loc, "return_value", E); } else { E = MakeFullDiscardedValueExpr(E).get(); 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 @@ -854,10 +854,6 @@ Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw"; if (Ex && !Ex->isTypeDependent()) { - QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType()); - if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex)) - return ExprError(); - // Initialize the exception result. This implicitly weeds out // abstract types or types with inaccessible copy constructors. @@ -876,6 +872,10 @@ NamedReturnInfo NRInfo = IsThrownVarInScope ? getNamedReturnInfo(Ex) : NamedReturnInfo(); + QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType()); + if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex)) + return ExprError(); + InitializedEntity Entity = InitializedEntity::InitializeException( OpLoc, ExceptionObjectTy, /*NRVO=*/NRInfo.isCopyElidable()); 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 @@ -3312,15 +3312,16 @@ /// without considering function return type, if applicable. /// /// \param E The expression being returned from the function or block, -/// being thrown, or being co_returned from a coroutine. +/// being thrown, or being co_returned from a coroutine. This expression +/// might be modified by the implementation. /// -/// \param ForceCXX20 Overrides detection of current language mode -/// and uses the rules for C++20. +/// \param ForceCXX2b Overrides detection of current language mode +/// and uses the rules for C++2b. /// /// \returns An aggregate which contains the Candidate and isMoveEligible /// and isCopyElidable methods. If Candidate is non-null, it means /// isMoveEligible() would be true under the most permissive language standard. -Sema::NamedReturnInfo Sema::getNamedReturnInfo(const Expr *E, bool ForceCXX20) { +Sema::NamedReturnInfo Sema::getNamedReturnInfo(Expr *&E, bool ForceCXX2b) { if (!E) return NamedReturnInfo(); // - in a return statement in a function [where] ... @@ -3331,7 +3332,14 @@ const auto *VD = dyn_cast(DR->getDecl()); if (!VD) return NamedReturnInfo(); - return getNamedReturnInfo(VD, ForceCXX20); + NamedReturnInfo Res = getNamedReturnInfo(VD, /*ForceCXX20=*/ForceCXX2b); + if (Res.Candidate && !E->isXValue() && + (ForceCXX2b || getLangOpts().CPlusPlus2b)) { + E = ImplicitCastExpr::Create(Context, VD->getType().getNonReferenceType(), + CK_NoOp, E, nullptr, VK_XValue, + FPOptionsOverride()); + } + return Res; } /// Updates the status in the given NamedReturnInfo object to disallow @@ -3566,7 +3574,7 @@ const NamedReturnInfo &NRInfo, Expr *Value) { - if (NRInfo.Candidate) { + if (NRInfo.Candidate && !getLangOpts().CPlusPlus2b) { if (NRInfo.isMoveEligible()) { ExprResult Res; if (!TryMoveInitialization(*this, Entity, NRInfo.Candidate, Value, 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 @@ -8899,6 +8899,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: @@ -8909,7 +8913,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 @@ -8918,21 +8922,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(); } @@ -8945,8 +8950,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,8 +1,8 @@ -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -fcxx-exceptions -verify=expected,cxx20_2b %s -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected,cxx20_2b %s -// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17 %s -// RUN: %clang_cc1 -std=c++14 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17 %s -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_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 { @@ -409,8 +409,10 @@ namespace test_simpler_implicit_move { struct CopyOnly { - CopyOnly(); - CopyOnly(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(); @@ -419,7 +421,7 @@ MoveOnly &&rref(); MoveOnly &&test1(MoveOnly &&w) { - return w; // expected-error {{cannot bind to lvalue of type}} + return w; // cxx11_20-error {{cannot bind to lvalue of type}} } CopyOnly test2(bool b) { @@ -428,22 +430,22 @@ if (b) { return w1; } else { - return w2; + return w2; // cxx2b-error {{no matching constructor for initialization}} } } -template T &&test3(T &&x) { return x; } // expected-error {{cannot bind to lvalue of type}} +template T &&test3(T &&x) { return x; } // cxx11_20-error {{cannot bind to lvalue of type}} template MoveOnly& test3(MoveOnly&); -template MoveOnly&& test3(MoveOnly&&); // expected-note {{in instantiation of function template specialization}} +template MoveOnly &&test3(MoveOnly &&); // cxx11_20-note {{in instantiation of function template specialization}} MoveOnly &&test4() { MoveOnly &&x = rref(); - return x; // expected-error {{cannot bind to lvalue of type}} + return x; // cxx11_20-error {{cannot bind to lvalue of type}} } void test5() try { CopyOnly x; - throw x; + throw x; // cxx2b-error {{no matching constructor for initialization}} } catch (...) { } diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -std=c++2b -verify %s -// RUN: %clang_cc1 -verify -std=c++20 -verify %s -// RUN: %clang_cc1 -verify -std=c++14 -verify %s +// RUN: %clang_cc1 -verify -std=c++2b -verify=expected,cxx2b %s +// RUN: %clang_cc1 -verify -std=c++20 -verify=expected,cxx14_20 %s +// RUN: %clang_cc1 -verify -std=c++14 -verify=expected,cxx14_20 %s namespace std { template struct initializer_list { @@ -30,7 +30,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(); @@ -81,7 +81,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(); } @@ -91,7 +91,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_20-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/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp --- a/clang/test/CXX/drs/dr3xx.cpp +++ b/clang/test/CXX/drs/dr3xx.cpp @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -std=c++2b -verify=expected,cxx20_2b -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors -// RUN: %clang_cc1 -std=c++20 -verify=expected,cxx20_2b -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors -// RUN: %clang_cc1 -std=c++17 -verify=expected,cxx98_17 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors -// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx98_17 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors -// RUN: %clang_cc1 -std=c++11 -verify=expected,cxx98_17 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors -// RUN: %clang_cc1 -std=c++98 -verify=expected,cxx98_17 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++2b -verify=expected,cxx20_2b,cxx2b -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++20 -verify=expected,cxx98_20,cxx20_2b -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++17 -verify=expected,cxx98_17,cxx98_20 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx98_17,cxx98_20 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++11 -verify=expected,cxx98_17,cxx98_20 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++98 -verify=expected,cxx98_17,cxx98_20 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors namespace dr300 { // dr300: yes template void f(R (&)(A)) {} @@ -628,7 +628,8 @@ struct A { template operator T ***() { int ***p = 0; - return p; // expected-error {{cannot initialize return object of type 'const int ***' with an lvalue of type 'int ***'}} + return p; // cxx98_20-error {{cannot initialize return object of type 'const int ***' with an lvalue of type 'int ***'}} + // cxx2b-error@-1 {{cannot initialize return object of type 'const int ***' with an rvalue of type 'int ***'}} } }; diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-cxx14.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-cxx14.cpp --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-cxx14.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-cxx14.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify %s -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s -// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx2b %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx14_20 %s +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14_20 %s int a; int &b = [] (int &r) -> decltype(auto) { return r; } (a); @@ -9,13 +9,15 @@ int &e = [] (int &r) -> auto { return r; } (a); // expected-error {{cannot bind to a temporary}} int &f = [] (int r) -> decltype(auto) { return r; } (a); // expected-error {{cannot bind to a temporary}} int &g = [] (int r) -> decltype(auto) { return (r); } (a); // expected-warning {{reference to stack}} +// cxx2b-error@-1 {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} int test_explicit_auto_return() { struct X {}; auto L = [](auto F, auto a) { return F(a); }; auto M = [](auto a) -> auto { return a; }; // OK - auto MRef = [](auto b) -> auto& { return b; }; //expected-warning{{reference to stack}} + auto MRef = [](auto b) -> auto & { return b; }; //cxx14_20-warning{{reference to stack}} + // cxx2b-error@-1 {{non-const lvalue reference to type 'X' cannot bind to a temporary of type 'X'}} auto MPtr = [](auto c) -> auto* { return &c; }; //expected-warning{{address of stack}} auto MDeclType = [](auto&& d) -> decltype(auto) { return static_cast(d); }; //OK M(3); diff --git a/clang/test/CXX/temp/temp.decls/temp.mem/p5.cpp b/clang/test/CXX/temp/temp.decls/temp.mem/p5.cpp --- a/clang/test/CXX/temp/temp.decls/temp.mem/p5.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.mem/p5.cpp @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify %s -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s -// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx2b %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx98_20 %s +// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify=expected,cxx98_20 %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98_20 %s struct A { template operator T*(); @@ -67,8 +67,10 @@ template operator const T*() const { T x = T(); - return x; // expected-error{{cannot initialize return object of type 'const char *' with an lvalue of type 'char'}} \ - // expected-error{{cannot initialize return object of type 'const int *' with an lvalue of type 'int'}} + return x; // cxx98_20-error{{cannot initialize return object of type 'const char *' with an lvalue of type 'char'}} \ + // cxx98_20-error{{cannot initialize return object of type 'const int *' with an lvalue of type 'int'}} \ + // cxx2b-error{{cannot initialize return object of type 'const char *' with an rvalue of type 'char'}} \ + // cxx2b-error{{cannot initialize return object of type 'const int *' with an rvalue of type 'int'}} } }; diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx20_2b -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify=expected,cxx11 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b,cxx2b -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx11_20,cxx20_2b -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify=expected,cxx11_20,cxx11 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion namespace StaticAssertFoldTest { @@ -1938,13 +1938,18 @@ } constexpr int &get(int &&n) { return n; } + // cxx2b-error@-1 {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} + // cxx2b-error@-2 {{no return statement in constexpr function}} See PR40598 constexpr int &&get_rv(int &&n) { return static_cast(n); } struct S { int &&r; int &s; int t; constexpr S() : r(get_rv(0)), s(get(0)), t(r) {} // expected-note {{read of object outside its lifetime}} - constexpr S(int) : r(get_rv(0)), s(get(0)), t(s) {} // expected-note {{read of object outside its lifetime}} + constexpr S(int) : r(get_rv(0)), s(get(0)), t(s) {} + // cxx2b-warning@-1 {{reference 's' is not yet bound to a value when used here}} + // cxx2b-note@-2 {{read of uninitialized object is not allowed in a constant expression}} + // cxx11_20-note@-3 {{read of object outside its lifetime}} }; constexpr int k1 = S().t; // expected-error {{constant expression}} expected-note {{in call}} constexpr int k2 = S(0).t; // expected-error {{constant expression}} expected-note {{in call}} diff --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp b/clang/test/SemaCXX/constant-expression-cxx14.cpp --- a/clang/test/SemaCXX/constant-expression-cxx14.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b %s -fcxx-exceptions -triple=x86_64-linux-gnu -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx20_2b %s -fcxx-exceptions -triple=x86_64-linux-gnu -// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14 %s -fcxx-exceptions -triple=x86_64-linux-gnu +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b,cxx2b %s -fcxx-exceptions -triple=x86_64-linux-gnu +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx14_20,cxx20_2b,cxx20 %s -fcxx-exceptions -triple=x86_64-linux-gnu +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14_20,cxx14 %s -fcxx-exceptions -triple=x86_64-linux-gnu struct S { // dummy ctor to make this a literal type @@ -269,16 +269,23 @@ namespace incdec { template constexpr T &ref(T &&r) { return r; } + // cxx2b-error@-1 {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} template constexpr T postinc(T &&r) { return (r++, r); } template constexpr T postdec(T &&r) { return (r--, r); } + template int &ref(int &&); + // cxx2b-note@-1 {{in instantiation of function template specialization}} + + static_assert(postinc(0) == 1, ""); + static_assert(postdec(0) == -1, ""); +#if __cplusplus <= 202002L static_assert(++ref(0) == 1, ""); static_assert(ref(0)++ == 0, ""); - static_assert(postinc(0) == 1, ""); static_assert(--ref(0) == -1, ""); static_assert(ref(0)-- == 0, ""); - static_assert(postdec(0) == -1, ""); +#endif +#if __cplusplus <= 202002L constexpr int overflow_int_inc_1 = ref(0x7fffffff)++; // expected-error {{constant}} expected-note {{2147483648}} constexpr int overflow_int_inc_1_ok = ref(0x7ffffffe)++; constexpr int overflow_int_inc_2 = ++ref(0x7fffffff); // expected-error {{constant}} expected-note {{2147483648}} @@ -291,37 +298,42 @@ // inc on bool sets to true static_assert(++ref(false), ""); // cxx14-warning@-1 {{incrementing expression of type bool}} - // cxx20_2b-error@-2 {{incrementing expression of type bool}} + // cxx20-error@-2 {{incrementing expression of type bool}} static_assert(++ref(true), ""); // cxx14-warning@-1 {{incrementing expression of type bool}} - // cxx20_2b-error@-2 {{incrementing expression of type bool}} + // cxx20-error@-2 {{incrementing expression of type bool}} +#endif int arr[10]; + static_assert(postinc(&arr[0]) == &arr[1], ""); + static_assert(postdec(&arr[1]) == &arr[0], ""); +#if __cplusplus <= 202002L static_assert(++ref(&arr[0]) == &arr[1], ""); static_assert(++ref(&arr[9]) == &arr[10], ""); static_assert(++ref(&arr[10]) == &arr[11], ""); // expected-error {{constant}} expected-note {{cannot refer to element 11}} static_assert(ref(&arr[0])++ == &arr[0], ""); static_assert(ref(&arr[10])++ == &arr[10], ""); // expected-error {{constant}} expected-note {{cannot refer to element 11}} - static_assert(postinc(&arr[0]) == &arr[1], ""); static_assert(--ref(&arr[10]) == &arr[9], ""); static_assert(--ref(&arr[1]) == &arr[0], ""); static_assert(--ref(&arr[0]) != &arr[0], ""); // expected-error {{constant}} expected-note {{cannot refer to element -1}} static_assert(ref(&arr[1])-- == &arr[1], ""); static_assert(ref(&arr[0])-- == &arr[0], ""); // expected-error {{constant}} expected-note {{cannot refer to element -1}} - static_assert(postdec(&arr[1]) == &arr[0], ""); +#endif + static_assert(postinc(0.0) == 1.0, ""); + static_assert(postdec(0.0) == -1.0, ""); +#if __cplusplus <= 202002L int x; static_assert(++ref(&x) == &x + 1, ""); static_assert(++ref(0.0) == 1.0, ""); static_assert(ref(0.0)++ == 0.0, ""); - static_assert(postinc(0.0) == 1.0, ""); static_assert(--ref(0.0) == -1.0, ""); static_assert(ref(0.0)-- == 0.0, ""); - static_assert(postdec(0.0) == -1.0, ""); static_assert(++ref(1e100) == 1e100, ""); static_assert(--ref(1e100) == 1e100, ""); +#endif union U { int a, b; @@ -863,9 +875,13 @@ namespace Lifetime { constexpr int &get(int &&r) { return r; } + // cxx2b-error@-1 {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} + // cxx2b-error@-2 {{no return statement in constexpr function}} See PR40598 constexpr int f() { int &r = get(123); - return r; // expected-note {{read of object outside its lifetime}} + return r; + // cxx2b-note@-1 {{use of reference outside its lifetime is not allowed in a constant expression}} + // cxx14_20-note@-2 {{read of object outside its lifetime}} } static_assert(f() == 123, ""); // expected-error {{constant expression}} expected-note {{in call}} 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 @@ -39,15 +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; // expected-note 4{{'NoCopyNoMove' has been explicitly marked deleted here}} + NoCopyNoMove(const NoCopyNoMove &) = delete; }; template @@ -63,13 +62,12 @@ task local2val() { NoCopyNoMove value; - co_return value; // expected-error {{call to deleted constructor of 'NoCopyNoMove'}} - // expected-error@-1 {{value reference to type 'NoCopyNoMove' cannot bind to lvalue of type 'NoCopyNoMove'}} + co_return value; } task local2ref() { NoCopyNoMove value; - co_return value; // expected-error {{call to deleted constructor of 'NoCopyNoMove'}} + 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. @@ -82,8 +80,7 @@ } task rvalue2val(NoCopyNoMove &&value) { - co_return value; // expected-error {{rvalue reference to type 'NoCopyNoMove' cannot bind to lvalue of type 'NoCopyNoMove'}} - // expected-error@-1 {{call to deleted constructor of 'NoCopyNoMove'}} + co_return value; } task lvalue2ref(NoCopyNoMove &value) { @@ -91,7 +88,7 @@ } task rvalue2ref(NoCopyNoMove &&value) { - co_return value; // expected-error {{call to deleted constructor of 'NoCopyNoMove'}} + co_return value; // expected-error {{non-const lvalue reference to type 'NoCopyNoMove' cannot bind to a temporary of type 'NoCopyNoMove'}} } struct To { diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp --- a/clang/test/SemaCXX/coroutines.cpp +++ b/clang/test/SemaCXX/coroutines.cpp @@ -1,9 +1,9 @@ // This file contains references to sections of the Coroutines TS, which can be // found at http://wg21.link/coroutines. -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b %s -fcxx-exceptions -fexceptions -Wunused-result -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx20_2b %s -fcxx-exceptions -fexceptions -Wunused-result -// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -fsyntax-only -verify=expected %s -fcxx-exceptions -fexceptions -Wunused-result +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b,cxx2b %s -fcxx-exceptions -fexceptions -Wunused-result +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx14_20,cxx20_2b %s -fcxx-exceptions -fexceptions -Wunused-result +// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -fsyntax-only -verify=expected,cxx14_20 %s -fcxx-exceptions -fexceptions -Wunused-result void no_coroutine_traits_bad_arg_await() { co_await a; // expected-error {{include }} @@ -934,7 +934,8 @@ }; extern "C" int f(mismatch_gro_type_tag2) { - // expected-error@-1 {{cannot initialize return object of type 'int' with an lvalue of type 'void *'}} + // cxx2b-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void *'}} + // cxx14_20-error@-2 {{cannot initialize return object of type 'int' with an lvalue of type 'void *'}} co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} } diff --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp --- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp +++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp @@ -1,11 +1,11 @@ -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b %s -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b,cxx2b %s +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b,cxx2b %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx20_2b %s -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx20_2b %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx14_20,cxx20_2b %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx14_20,cxx20_2b %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING -// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14 %s -// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14_20,cxx14 %s +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14_20,cxx14 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING auto f(); // expected-note {{previous}} int f(); // expected-error {{differ only in their return type}} @@ -129,10 +129,14 @@ return T() + 1; } template auto &f2(T &&v) { return v; } + // cxx2b-error@-1 {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} + // cxx2b-error@-2 {{non-const lvalue reference to type 'double' cannot bind to a temporary of type 'double'}} + // cxx2b-note@-3 {{candidate template ignored: substitution failure [with T = double]}} int a = f1(); - const int &b = f2(0); + const int &b = f2(0); // cxx2b-note {{in instantiation of function template specialization 'Templates::f2' requested here}} double d; float &c = f2(0.0); // expected-error {{non-const lvalue reference to type 'float' cannot bind to a value of unrelated type 'double'}} + // cxx2b-note@-1 {{in instantiation of function template specialization 'Templates::f2' requested here}} template auto fwd_decl(); // expected-note {{declared here}} int e = fwd_decl(); // expected-error {{cannot be used before it is defined}} @@ -145,8 +149,9 @@ auto (*p)() = f1; // expected-error {{incompatible initializer}} auto (*q)() = f1; // ok - typedef decltype(f2(1.2)) dbl; // expected-note {{previous}} - typedef float dbl; // expected-error {{typedef redefinition with different types ('float' vs 'decltype(f2(1.2))' (aka 'double &'))}} + typedef decltype(f2(1.2)) dbl; // cxx14_20-note {{previous}} + // cxx2b-error@-1 {{no matching function for call to 'f2'}} + typedef float dbl; // cxx14_20-error {{typedef redefinition with different types ('float' vs 'decltype(f2(1.2))' (aka 'double &'))}} extern template auto fwd_decl(); int k1 = fwd_decl(); diff --git a/clang/test/SemaCXX/return-stack-addr.cpp b/clang/test/SemaCXX/return-stack-addr.cpp --- a/clang/test/SemaCXX/return-stack-addr.cpp +++ b/clang/test/SemaCXX/return-stack-addr.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected %s -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected %s -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify=expected,cxx11 %s +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx2b %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx11_20 %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify=expected,cxx11_20,cxx11 %s int* ret_local() { int x = 1; @@ -29,7 +29,8 @@ int& ret_local_ref() { int x = 1; - return x; // expected-warning {{reference to stack memory}} + return x; // cxx11_20-warning {{reference to stack memory}} + // cxx2b-error@-1 {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} } int* ret_local_addrOf() { @@ -154,8 +155,10 @@ (void) [&]() -> int& { return b; }; (void) [=]() mutable -> int& { return a; }; (void) [=]() mutable -> int& { return b; }; - (void) [&]() -> int& { int a; return a; }; // expected-warning {{reference to stack}} - (void) [=]() -> int& { int a; return a; }; // expected-warning {{reference to stack}} + (void) [&]() -> int& { int a; return a; }; // cxx11_20-warning {{reference to stack}} + // cxx2b-error@-1 {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} + (void) [=]() -> int& { int a; return a; }; // cxx11_20-warning {{reference to stack}} + // cxx2b-error@-1 {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} (void) [&]() -> int& { int &a = b; return a; }; (void) [=]() mutable -> int& { int &a = b; return a; }; diff --git a/clang/test/SemaCXX/warn-return-std-move.cpp b/clang/test/SemaCXX/warn-return-std-move.cpp --- a/clang/test/SemaCXX/warn-return-std-move.cpp +++ b/clang/test/SemaCXX/warn-return-std-move.cpp @@ -1,8 +1,8 @@ -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=cxx20_2b -fcxx-exceptions -Wreturn-std-move %s -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=cxx20_2b -fcxx-exceptions -Wreturn-std-move %s -// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify=cxx11_17 -fcxx-exceptions -Wreturn-std-move %s -// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=cxx11_17 -fcxx-exceptions -Wreturn-std-move %s -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify=cxx11_17 -fcxx-exceptions -Wreturn-std-move %s +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=cxx20_2b,cxx2b -fcxx-exceptions -Wreturn-std-move %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=cxx20_2b -fcxx-exceptions -Wreturn-std-move %s +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify=cxx11_17 -fcxx-exceptions -Wreturn-std-move %s +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=cxx11_17 -fcxx-exceptions -Wreturn-std-move %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify=cxx11_17 -fcxx-exceptions -Wreturn-std-move %s // RUN: %clang_cc1 -std=c++17 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -check-prefix=CHECK // RUN: %clang_cc1 -std=c++14 -fsyntax-only -fcxx-exceptions -Wreturn-std-move -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -check-prefix=CHECK @@ -217,8 +217,8 @@ } // 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; } +Derived &testRetRef1(Derived &&d) { return d; } // cxx2b-error {{non-const lvalue reference to type 'Derived' cannot bind to a temporary of type 'Derived'}} +Base &testRetRef2(Derived &&d) { return d; } // cxx2b-error {{non-const lvalue reference to type 'Base' cannot bind to a temporary of type 'Derived'}} #if __cplusplus >= 201402L auto&& testRetRef3(Derived&& d) { return d; } decltype(auto) testRetRef4(Derived&& d) { return (d); }