Skip to content

Commit bf20631

Browse files
committed
[clang] Implement P2266 Simpler implicit move
This Implements [[http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2266r1.html|P2266 Simpler implicit move]]. Signed-off-by: Matheus Izvekov <mizvekov@gmail.com> Reviewed By: Quuxplusone Differential Revision: https://reviews.llvm.org/D99005
1 parent f6b9836 commit bf20631

File tree

17 files changed

+155
-120
lines changed

17 files changed

+155
-120
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4763,7 +4763,7 @@ class Sema final {
47634763
bool isMoveEligible() const { return S != None; };
47644764
bool isCopyElidable() const { return S == MoveEligibleAndCopyElidable; }
47654765
};
4766-
NamedReturnInfo getNamedReturnInfo(const Expr *E, bool ForceCXX20 = false);
4766+
NamedReturnInfo getNamedReturnInfo(Expr *&E, bool ForceCXX2b = false);
47674767
NamedReturnInfo getNamedReturnInfo(const VarDecl *VD,
47684768
bool ForceCXX20 = false);
47694769
const VarDecl *getCopyElisionCandidate(NamedReturnInfo &Info,

clang/lib/Sema/SemaCoroutine.cpp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -994,22 +994,10 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E,
994994
E = R.get();
995995
}
996996

997-
// Move the return value if we can
998-
NamedReturnInfo NRInfo = getNamedReturnInfo(E, /*ForceCXX20=*/true);
999-
if (NRInfo.isMoveEligible()) {
1000-
InitializedEntity Entity = InitializedEntity::InitializeResult(
1001-
Loc, E->getType(), NRInfo.Candidate);
1002-
ExprResult MoveResult = PerformMoveOrCopyInitialization(Entity, NRInfo, E);
1003-
if (MoveResult.get())
1004-
E = MoveResult.get();
1005-
}
1006-
1007-
// FIXME: If the operand is a reference to a variable that's about to go out
1008-
// of scope, we should treat the operand as an xvalue for this overload
1009-
// resolution.
1010997
VarDecl *Promise = FSI->CoroutinePromise;
1011998
ExprResult PC;
1012999
if (E && (isa<InitListExpr>(E) || !E->getType()->isVoidType())) {
1000+
getNamedReturnInfo(E, /*ForceCXX2b=*/true);
10131001
PC = buildPromiseCall(*this, Promise, Loc, "return_value", E);
10141002
} else {
10151003
E = MakeFullDiscardedValueExpr(E).get();

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -854,10 +854,6 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
854854
Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";
855855

856856
if (Ex && !Ex->isTypeDependent()) {
857-
QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType());
858-
if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex))
859-
return ExprError();
860-
861857
// Initialize the exception result. This implicitly weeds out
862858
// abstract types or types with inaccessible copy constructors.
863859

@@ -876,6 +872,10 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
876872
NamedReturnInfo NRInfo =
877873
IsThrownVarInScope ? getNamedReturnInfo(Ex) : NamedReturnInfo();
878874

875+
QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType());
876+
if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex))
877+
return ExprError();
878+
879879
InitializedEntity Entity = InitializedEntity::InitializeException(
880880
OpLoc, ExceptionObjectTy,
881881
/*NRVO=*/NRInfo.isCopyElidable());

clang/lib/Sema/SemaStmt.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3312,15 +3312,16 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
33123312
/// without considering function return type, if applicable.
33133313
///
33143314
/// \param E The expression being returned from the function or block,
3315-
/// being thrown, or being co_returned from a coroutine.
3315+
/// being thrown, or being co_returned from a coroutine. This expression
3316+
/// might be modified by the implementation.
33163317
///
3317-
/// \param ForceCXX20 Overrides detection of current language mode
3318-
/// and uses the rules for C++20.
3318+
/// \param ForceCXX2b Overrides detection of current language mode
3319+
/// and uses the rules for C++2b.
33193320
///
33203321
/// \returns An aggregate which contains the Candidate and isMoveEligible
33213322
/// and isCopyElidable methods. If Candidate is non-null, it means
33223323
/// isMoveEligible() would be true under the most permissive language standard.
3323-
Sema::NamedReturnInfo Sema::getNamedReturnInfo(const Expr *E, bool ForceCXX20) {
3324+
Sema::NamedReturnInfo Sema::getNamedReturnInfo(Expr *&E, bool ForceCXX2b) {
33243325
if (!E)
33253326
return NamedReturnInfo();
33263327
// - in a return statement in a function [where] ...
@@ -3331,7 +3332,14 @@ Sema::NamedReturnInfo Sema::getNamedReturnInfo(const Expr *E, bool ForceCXX20) {
33313332
const auto *VD = dyn_cast<VarDecl>(DR->getDecl());
33323333
if (!VD)
33333334
return NamedReturnInfo();
3334-
return getNamedReturnInfo(VD, ForceCXX20);
3335+
NamedReturnInfo Res = getNamedReturnInfo(VD, /*ForceCXX20=*/ForceCXX2b);
3336+
if (Res.Candidate && !E->isXValue() &&
3337+
(ForceCXX2b || getLangOpts().CPlusPlus2b)) {
3338+
E = ImplicitCastExpr::Create(Context, VD->getType().getNonReferenceType(),
3339+
CK_NoOp, E, nullptr, VK_XValue,
3340+
FPOptionsOverride());
3341+
}
3342+
return Res;
33353343
}
33363344

33373345
/// Updates the status in the given NamedReturnInfo object to disallow
@@ -3566,7 +3574,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
35663574
const NamedReturnInfo &NRInfo,
35673575
Expr *Value) {
35683576

3569-
if (NRInfo.Candidate) {
3577+
if (NRInfo.Candidate && !getLangOpts().CPlusPlus2b) {
35703578
if (NRInfo.isMoveEligible()) {
35713579
ExprResult Res;
35723580
if (!TryMoveInitialization(*this, Entity, NRInfo.Candidate, Value,

clang/lib/Sema/SemaType.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8899,6 +8899,10 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
88998899
if (E->isTypeDependent())
89008900
return S.Context.DependentTy;
89018901

8902+
Expr *IDExpr = E;
8903+
if (auto *ImplCastExpr = dyn_cast<ImplicitCastExpr>(E))
8904+
IDExpr = ImplCastExpr->getSubExpr();
8905+
89028906
// C++11 [dcl.type.simple]p4:
89038907
// The type denoted by decltype(e) is defined as follows:
89048908

@@ -8909,7 +8913,7 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
89098913
// Note that this does not pick up the implicit 'const' for a template
89108914
// parameter object. This rule makes no difference before C++20 so we apply
89118915
// it unconditionally.
8912-
if (const auto *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
8916+
if (const auto *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(IDExpr))
89138917
return SNTTPE->getParameterType(S.Context);
89148918

89158919
// - if e is an unparenthesized id-expression or an unparenthesized class
@@ -8918,21 +8922,22 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
89188922
// functions, the program is ill-formed;
89198923
//
89208924
// We apply the same rules for Objective-C ivar and property references.
8921-
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
8925+
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr)) {
89228926
const ValueDecl *VD = DRE->getDecl();
89238927
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(VD))
89248928
return TPO->getType().getUnqualifiedType();
89258929
return VD->getType();
8926-
} else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
8930+
} else if (const MemberExpr *ME = dyn_cast<MemberExpr>(IDExpr)) {
89278931
if (const ValueDecl *VD = ME->getMemberDecl())
89288932
if (isa<FieldDecl>(VD) || isa<VarDecl>(VD))
89298933
return VD->getType();
8930-
} else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(E)) {
8934+
} else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) {
89318935
return IR->getDecl()->getType();
8932-
} else if (const ObjCPropertyRefExpr *PR = dyn_cast<ObjCPropertyRefExpr>(E)) {
8936+
} else if (const ObjCPropertyRefExpr *PR =
8937+
dyn_cast<ObjCPropertyRefExpr>(IDExpr)) {
89338938
if (PR->isExplicitProperty())
89348939
return PR->getExplicitProperty()->getType();
8935-
} else if (auto *PE = dyn_cast<PredefinedExpr>(E)) {
8940+
} else if (auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) {
89368941
return PE->getType();
89378942
}
89388943

@@ -8945,8 +8950,8 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
89458950
// entity.
89468951
using namespace sema;
89478952
if (S.getCurLambda()) {
8948-
if (isa<ParenExpr>(E)) {
8949-
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
8953+
if (isa<ParenExpr>(IDExpr)) {
8954+
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr->IgnoreParens())) {
89508955
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
89518956
QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation());
89528957
if (!T.isNull())

clang/test/CXX/class/class.init/class.copy.elision/p3.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// RUN: %clang_cc1 -std=c++2b -fsyntax-only -fcxx-exceptions -verify=expected,cxx20_2b %s
2-
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected,cxx20_2b %s
3-
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17 %s
4-
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17 %s
5-
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17 %s
1+
// RUN: %clang_cc1 -std=c++2b -fsyntax-only -fcxx-exceptions -verify=expected,cxx20_2b,cxx2b %s
2+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_20,cxx20_2b %s
3+
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17,cxx11_20 %s
4+
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17,cxx11_20 %s
5+
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify=expected,cxx11_17,cxx11_20 %s
66

77
namespace test_delete_function {
88
struct A1 {
@@ -409,8 +409,10 @@ Target t4() {
409409
namespace test_simpler_implicit_move {
410410

411411
struct CopyOnly {
412-
CopyOnly();
413-
CopyOnly(CopyOnly &);
412+
CopyOnly(); // cxx2b-note {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
413+
// cxx2b-note@-1 {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
414+
CopyOnly(CopyOnly &); // cxx2b-note {{candidate constructor not viable: expects an lvalue for 1st argument}}
415+
// cxx2b-note@-1 {{candidate constructor not viable: expects an lvalue for 1st argument}}
414416
};
415417
struct MoveOnly {
416418
MoveOnly();
@@ -419,7 +421,7 @@ struct MoveOnly {
419421
MoveOnly &&rref();
420422

421423
MoveOnly &&test1(MoveOnly &&w) {
422-
return w; // expected-error {{cannot bind to lvalue of type}}
424+
return w; // cxx11_20-error {{cannot bind to lvalue of type}}
423425
}
424426

425427
CopyOnly test2(bool b) {
@@ -428,22 +430,22 @@ CopyOnly test2(bool b) {
428430
if (b) {
429431
return w1;
430432
} else {
431-
return w2;
433+
return w2; // cxx2b-error {{no matching constructor for initialization}}
432434
}
433435
}
434436

435-
template <class T> T &&test3(T &&x) { return x; } // expected-error {{cannot bind to lvalue of type}}
437+
template <class T> T &&test3(T &&x) { return x; } // cxx11_20-error {{cannot bind to lvalue of type}}
436438
template MoveOnly& test3<MoveOnly&>(MoveOnly&);
437-
template MoveOnly&& test3<MoveOnly>(MoveOnly&&); // expected-note {{in instantiation of function template specialization}}
439+
template MoveOnly &&test3<MoveOnly>(MoveOnly &&); // cxx11_20-note {{in instantiation of function template specialization}}
438440

439441
MoveOnly &&test4() {
440442
MoveOnly &&x = rref();
441-
return x; // expected-error {{cannot bind to lvalue of type}}
443+
return x; // cxx11_20-error {{cannot bind to lvalue of type}}
442444
}
443445

444446
void test5() try {
445447
CopyOnly x;
446-
throw x;
448+
throw x; // cxx2b-error {{no matching constructor for initialization}}
447449
} catch (...) {
448450
}
449451

clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: %clang_cc1 -verify -std=c++2b -verify %s
2-
// RUN: %clang_cc1 -verify -std=c++20 -verify %s
3-
// RUN: %clang_cc1 -verify -std=c++14 -verify %s
1+
// RUN: %clang_cc1 -verify -std=c++2b -verify=expected,cxx2b %s
2+
// RUN: %clang_cc1 -verify -std=c++20 -verify=expected,cxx14_20 %s
3+
// RUN: %clang_cc1 -verify -std=c++14 -verify=expected,cxx14_20 %s
44

55
namespace std {
66
template<typename T> struct initializer_list {
@@ -30,7 +30,7 @@ using Int = decltype(x3d);
3030
auto x4a = (i);
3131
decltype(auto) x4d = (i);
3232
using Int = decltype(x4a);
33-
using IntLRef = decltype(x4d);
33+
using IntLRef = decltype(x4d); // cxx2b-note {{previous definition is here}}
3434

3535
auto x5a = f();
3636
decltype(auto) x5d = f();
@@ -81,7 +81,7 @@ using Int = decltype(f2d(0));
8181
auto f3a(int n) { return (n); }
8282
decltype(auto) f3d(int n) { return (n); } // expected-warning {{reference to stack memory}}
8383
using Int = decltype(f3a(0));
84-
using IntLRef = decltype(f3d(0));
84+
using IntLRef = decltype(f3d(0)); // cxx2b-error {{type alias redefinition with different types ('decltype(f3d(0))' (aka 'int &&') vs 'decltype(x4d)' (aka 'int &'))}}
8585

8686
auto f4a(int n) { return f(); }
8787
decltype(auto) f4d(int n) { return f(); }
@@ -91,7 +91,7 @@ using IntRRef = decltype(f4d(0));
9191
auto f5aa(int n) { auto x = f(); return x; }
9292
auto f5ad(int n) { decltype(auto) x = f(); return x; }
9393
decltype(auto) f5da(int n) { auto x = f(); return x; }
94-
decltype(auto) f5dd(int n) { decltype(auto) x = f(); return x; } // expected-error {{rvalue reference to type 'int' cannot bind to lvalue}}
94+
decltype(auto) f5dd(int n) { decltype(auto) x = f(); return x; } // cxx14_20-error {{rvalue reference to type 'int' cannot bind to lvalue}}
9595
using Int = decltype(f5aa(0));
9696
using Int = decltype(f5ad(0));
9797
using Int = decltype(f5da(0));

clang/test/CXX/drs/dr3xx.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// RUN: %clang_cc1 -std=c++2b -verify=expected,cxx20_2b -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
2-
// RUN: %clang_cc1 -std=c++20 -verify=expected,cxx20_2b -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
3-
// RUN: %clang_cc1 -std=c++17 -verify=expected,cxx98_17 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
4-
// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx98_17 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
5-
// RUN: %clang_cc1 -std=c++11 -verify=expected,cxx98_17 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
6-
// RUN: %clang_cc1 -std=c++98 -verify=expected,cxx98_17 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
1+
// RUN: %clang_cc1 -std=c++2b -verify=expected,cxx20_2b,cxx2b -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
2+
// RUN: %clang_cc1 -std=c++20 -verify=expected,cxx98_20,cxx20_2b -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
3+
// RUN: %clang_cc1 -std=c++17 -verify=expected,cxx98_17,cxx98_20 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
4+
// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx98_17,cxx98_20 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
5+
// RUN: %clang_cc1 -std=c++11 -verify=expected,cxx98_17,cxx98_20 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
6+
// RUN: %clang_cc1 -std=c++98 -verify=expected,cxx98_17,cxx98_20 -triple %itanium_abi_triple %s -fexceptions -fcxx-exceptions -pedantic-errors
77

88
namespace dr300 { // dr300: yes
99
template<typename R, typename A> void f(R (&)(A)) {}
@@ -628,7 +628,8 @@ namespace dr349 { // dr349: no
628628
struct A {
629629
template <class T> operator T ***() {
630630
int ***p = 0;
631-
return p; // expected-error {{cannot initialize return object of type 'const int ***' with an lvalue of type 'int ***'}}
631+
return p; // cxx98_20-error {{cannot initialize return object of type 'const int ***' with an lvalue of type 'int ***'}}
632+
// cxx2b-error@-1 {{cannot initialize return object of type 'const int ***' with an rvalue of type 'int ***'}}
632633
}
633634
};
634635

clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-cxx14.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify %s
2-
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
3-
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
1+
// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx2b %s
2+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx14_20 %s
3+
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14_20 %s
44

55
int a;
66
int &b = [] (int &r) -> decltype(auto) { return r; } (a);
@@ -9,13 +9,15 @@ int &d = [] (int &r) -> auto & { return r; } (a);
99
int &e = [] (int &r) -> auto { return r; } (a); // expected-error {{cannot bind to a temporary}}
1010
int &f = [] (int r) -> decltype(auto) { return r; } (a); // expected-error {{cannot bind to a temporary}}
1111
int &g = [] (int r) -> decltype(auto) { return (r); } (a); // expected-warning {{reference to stack}}
12+
// cxx2b-error@-1 {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
1213

1314
int test_explicit_auto_return()
1415
{
1516
struct X {};
1617
auto L = [](auto F, auto a) { return F(a); };
1718
auto M = [](auto a) -> auto { return a; }; // OK
18-
auto MRef = [](auto b) -> auto& { return b; }; //expected-warning{{reference to stack}}
19+
auto MRef = [](auto b) -> auto & { return b; }; //cxx14_20-warning{{reference to stack}}
20+
// cxx2b-error@-1 {{non-const lvalue reference to type 'X' cannot bind to a temporary of type 'X'}}
1921
auto MPtr = [](auto c) -> auto* { return &c; }; //expected-warning{{address of stack}}
2022
auto MDeclType = [](auto&& d) -> decltype(auto) { return static_cast<decltype(d)>(d); }; //OK
2123
M(3);

clang/test/CXX/temp/temp.decls/temp.mem/p5.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify %s
2-
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
3-
// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s
4-
// RUN: %clang_cc1 -fsyntax-only -verify %s
1+
// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx2b %s
2+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx98_20 %s
3+
// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify=expected,cxx98_20 %s
4+
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98_20 %s
55

66
struct A {
77
template <class T> operator T*();
@@ -67,8 +67,10 @@ struct X0 {
6767

6868
template<typename T> operator const T*() const {
6969
T x = T();
70-
return x; // expected-error{{cannot initialize return object of type 'const char *' with an lvalue of type 'char'}} \
71-
// expected-error{{cannot initialize return object of type 'const int *' with an lvalue of type 'int'}}
70+
return x; // cxx98_20-error{{cannot initialize return object of type 'const char *' with an lvalue of type 'char'}} \
71+
// cxx98_20-error{{cannot initialize return object of type 'const int *' with an lvalue of type 'int'}} \
72+
// cxx2b-error{{cannot initialize return object of type 'const char *' with an rvalue of type 'char'}} \
73+
// cxx2b-error{{cannot initialize return object of type 'const int *' with an rvalue of type 'int'}}
7274
}
7375
};
7476

0 commit comments

Comments
 (0)