forked from OSchip/llvm-project
[c++2b] Implement P0849R8 auto(x)
https://wg21.link/p0849 Reviewed By: aaron.ballman, erichkeane Differential Revision: https://reviews.llvm.org/D113393
This commit is contained in:
parent
cb254d5919
commit
136b293129
|
@ -123,6 +123,7 @@ C++2b Feature Support
|
|||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Implemented `P2128R6: Multidimensional subscript operator <https://wg21.link/P2128R6>`_.
|
||||
- Implemented `P0849R8: auto(x): decay-copy in the language <https://wg21.link/P0849R8>`_.
|
||||
|
||||
CUDA Language Changes in Clang
|
||||
------------------------------
|
||||
|
|
|
@ -2320,13 +2320,23 @@ def ext_auto_new_list_init : Extension<
|
|||
"type %0 to use list-initialization">, InGroup<CXX17>;
|
||||
def err_auto_var_init_no_expression : Error<
|
||||
"initializer for variable %0 with type %1 is empty">;
|
||||
def err_auto_expr_init_no_expression : Error<
|
||||
"initializer for functional-style cast to %0 is empty">;
|
||||
def err_auto_var_init_multiple_expressions : Error<
|
||||
"initializer for variable %0 with type %1 contains multiple expressions">;
|
||||
def err_auto_expr_init_multiple_expressions : Error<
|
||||
"initializer for functional-style cast to %0 contains multiple expressions">;
|
||||
def err_auto_var_init_paren_braces : Error<
|
||||
"cannot deduce type for variable %1 with type %2 from "
|
||||
"%select{parenthesized|nested}0 initializer list">;
|
||||
def err_auto_new_ctor_multiple_expressions : Error<
|
||||
"new expression for type %0 contains multiple constructor arguments">;
|
||||
def err_auto_expr_init_paren_braces : Error<
|
||||
"cannot deduce actual type for %1 from "
|
||||
"%select{parenthesized|nested}0 initializer list">;
|
||||
def warn_cxx20_compat_auto_expr : Warning<
|
||||
"'auto' as a functional-style cast is incompatible with C++ standards "
|
||||
"before C++2b">, InGroup<CXXPre2bCompat>, DefaultIgnore;
|
||||
def err_auto_missing_trailing_return : Error<
|
||||
"'auto' return without trailing return type; deduced return types are a "
|
||||
"C++14 extension">;
|
||||
|
@ -2340,6 +2350,8 @@ def err_auto_var_deduction_failure : Error<
|
|||
"variable %0 with type %1 has incompatible initializer of type %2">;
|
||||
def err_auto_var_deduction_failure_from_init_list : Error<
|
||||
"cannot deduce actual type for variable %0 with type %1 from initializer list">;
|
||||
def err_auto_expr_deduction_failure : Error<
|
||||
"functional-style cast to %0 has incompatible initializer of type %1">;
|
||||
def err_auto_new_deduction_failure : Error<
|
||||
"new expression for type %0 has incompatible constructor argument of type %1">;
|
||||
def err_auto_inconsistent_deduction : Error<
|
||||
|
|
|
@ -1940,14 +1940,23 @@ void StmtPrinter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Node) {
|
|||
}
|
||||
|
||||
void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
|
||||
Node->getType().print(OS, Policy);
|
||||
// If there are no parens, this is list-initialization, and the braces are
|
||||
// part of the syntax of the inner construct.
|
||||
if (Node->getLParenLoc().isValid())
|
||||
OS << "(";
|
||||
auto TargetType = Node->getType();
|
||||
auto *Auto = TargetType->getContainedDeducedType();
|
||||
bool Bare = Auto && Auto->isDeduced();
|
||||
|
||||
// Parenthesize deduced casts.
|
||||
if (Bare)
|
||||
OS << '(';
|
||||
TargetType.print(OS, Policy);
|
||||
if (Bare)
|
||||
OS << ')';
|
||||
|
||||
// No extra braces surrounding the inner construct.
|
||||
if (!Node->isListInitialization())
|
||||
OS << '(';
|
||||
PrintExpr(Node->getSubExpr());
|
||||
if (Node->getLParenLoc().isValid())
|
||||
OS << ")";
|
||||
if (!Node->isListInitialization())
|
||||
OS << ')';
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
|
||||
|
|
|
@ -1030,10 +1030,9 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
|
|||
}
|
||||
|
||||
// Check for C++1y 'decltype(auto)'.
|
||||
if (Tok.is(tok::kw_auto)) {
|
||||
// No need to disambiguate here: an expression can't start with 'auto',
|
||||
// because the typename-specifier in a function-style cast operation can't
|
||||
// be 'auto'.
|
||||
if (Tok.is(tok::kw_auto) && NextToken().is(tok::r_paren)) {
|
||||
// the typename-specifier in a function-style cast expression may
|
||||
// be 'auto' since C++2b.
|
||||
Diag(Tok.getLocation(),
|
||||
getLangOpts().CPlusPlus14
|
||||
? diag::warn_cxx11_compat_decltype_auto_type_specifier
|
||||
|
|
|
@ -1524,6 +1524,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
|
|||
case tok::kw___float128:
|
||||
case tok::kw___ibm128:
|
||||
case tok::kw_void:
|
||||
case tok::kw_auto:
|
||||
case tok::kw_typename:
|
||||
case tok::kw_typeof:
|
||||
case tok::kw___vector:
|
||||
|
|
|
@ -2231,6 +2231,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
|
|||
case tok::kw_void:
|
||||
DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID, Policy);
|
||||
break;
|
||||
case tok::kw_auto:
|
||||
DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID, Policy);
|
||||
break;
|
||||
case tok::kw_char:
|
||||
DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID, Policy);
|
||||
break;
|
||||
|
|
|
@ -1468,6 +1468,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
|
|||
// C++1z [expr.type.conv]p1:
|
||||
// If the type is a placeholder for a deduced class type, [...perform class
|
||||
// template argument deduction...]
|
||||
// C++2b:
|
||||
// Otherwise, if the type contains a placeholder type, it is replaced by the
|
||||
// type determined by placeholder type deduction.
|
||||
DeducedType *Deduced = Ty->getContainedDeducedType();
|
||||
if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
|
||||
Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity,
|
||||
|
@ -1475,6 +1478,41 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
|
|||
if (Ty.isNull())
|
||||
return ExprError();
|
||||
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
|
||||
} else if (Deduced) {
|
||||
MultiExprArg Inits = Exprs;
|
||||
if (ListInitialization) {
|
||||
auto *ILE = cast<InitListExpr>(Exprs[0]);
|
||||
Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
|
||||
}
|
||||
|
||||
if (Inits.empty())
|
||||
return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_init_no_expression)
|
||||
<< Ty << FullRange);
|
||||
if (Inits.size() > 1) {
|
||||
Expr *FirstBad = Inits[1];
|
||||
return ExprError(Diag(FirstBad->getBeginLoc(),
|
||||
diag::err_auto_expr_init_multiple_expressions)
|
||||
<< Ty << FullRange);
|
||||
}
|
||||
if (getLangOpts().CPlusPlus2b) {
|
||||
if (Ty->getAs<AutoType>())
|
||||
Diag(TyBeginLoc, diag::warn_cxx20_compat_auto_expr) << FullRange;
|
||||
}
|
||||
Expr *Deduce = Inits[0];
|
||||
if (isa<InitListExpr>(Deduce))
|
||||
return ExprError(
|
||||
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
|
||||
<< ListInitialization << Ty << FullRange);
|
||||
QualType DeducedType;
|
||||
if (DeduceAutoType(TInfo, Deduce, DeducedType) == DAR_Failed)
|
||||
return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure)
|
||||
<< Ty << Deduce->getType() << FullRange
|
||||
<< Deduce->getSourceRange());
|
||||
if (DeducedType.isNull())
|
||||
return ExprError();
|
||||
|
||||
Ty = DeducedType;
|
||||
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
|
||||
}
|
||||
|
||||
if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) {
|
||||
|
@ -1937,12 +1975,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
|||
initStyle = CXXNewExpr::NoInit;
|
||||
}
|
||||
|
||||
Expr **Inits = &Initializer;
|
||||
unsigned NumInits = Initializer ? 1 : 0;
|
||||
MultiExprArg Exprs(&Initializer, Initializer ? 1 : 0);
|
||||
if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) {
|
||||
assert(initStyle == CXXNewExpr::CallInit && "paren init for non-call init");
|
||||
Inits = List->getExprs();
|
||||
NumInits = List->getNumExprs();
|
||||
Exprs = MultiExprArg(List->getExprs(), List->getNumExprs());
|
||||
}
|
||||
|
||||
// C++11 [expr.new]p15:
|
||||
|
@ -1978,23 +2014,21 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
|||
InitializedEntity Entity
|
||||
= InitializedEntity::InitializeNew(StartLoc, AllocType);
|
||||
AllocType = DeduceTemplateSpecializationFromInitializer(
|
||||
AllocTypeInfo, Entity, Kind, MultiExprArg(Inits, NumInits));
|
||||
AllocTypeInfo, Entity, Kind, Exprs);
|
||||
if (AllocType.isNull())
|
||||
return ExprError();
|
||||
} else if (Deduced) {
|
||||
MultiExprArg Inits = Exprs;
|
||||
bool Braced = (initStyle == CXXNewExpr::ListInit);
|
||||
if (NumInits == 1) {
|
||||
if (auto p = dyn_cast_or_null<InitListExpr>(Inits[0])) {
|
||||
Inits = p->getInits();
|
||||
NumInits = p->getNumInits();
|
||||
Braced = true;
|
||||
}
|
||||
if (Braced) {
|
||||
auto *ILE = cast<InitListExpr>(Exprs[0]);
|
||||
Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
|
||||
}
|
||||
|
||||
if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
|
||||
if (initStyle == CXXNewExpr::NoInit || Inits.empty())
|
||||
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
|
||||
<< AllocType << TypeRange);
|
||||
if (NumInits > 1) {
|
||||
if (Inits.size() > 1) {
|
||||
Expr *FirstBad = Inits[1];
|
||||
return ExprError(Diag(FirstBad->getBeginLoc(),
|
||||
diag::err_auto_new_ctor_multiple_expressions)
|
||||
|
@ -2004,6 +2038,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
|||
Diag(Initializer->getBeginLoc(), diag::ext_auto_new_list_init)
|
||||
<< AllocType << TypeRange;
|
||||
Expr *Deduce = Inits[0];
|
||||
if (isa<InitListExpr>(Deduce))
|
||||
return ExprError(
|
||||
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
|
||||
<< Braced << AllocType << TypeRange);
|
||||
QualType DeducedType;
|
||||
if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
|
||||
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
|
||||
|
@ -2304,8 +2342,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
|||
// Initializer lists are also allowed, in C++11. Rely on the parser for the
|
||||
// dialect distinction.
|
||||
if (ArraySize && !isLegalArrayNewInitializer(initStyle, Initializer)) {
|
||||
SourceRange InitRange(Inits[0]->getBeginLoc(),
|
||||
Inits[NumInits - 1]->getEndLoc());
|
||||
SourceRange InitRange(Exprs.front()->getBeginLoc(),
|
||||
Exprs.back()->getEndLoc());
|
||||
Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
|
||||
return ExprError();
|
||||
}
|
||||
|
@ -2313,8 +2351,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
|||
// If we can perform the initialization, and we've not already done so,
|
||||
// do it now.
|
||||
if (!AllocType->isDependentType() &&
|
||||
!Expr::hasAnyTypeDependentArguments(
|
||||
llvm::makeArrayRef(Inits, NumInits))) {
|
||||
!Expr::hasAnyTypeDependentArguments(Exprs)) {
|
||||
// The type we initialize is the complete type, including the array bound.
|
||||
QualType InitType;
|
||||
if (KnownArraySize)
|
||||
|
@ -2331,10 +2368,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
|||
|
||||
InitializedEntity Entity
|
||||
= InitializedEntity::InitializeNew(StartLoc, InitType);
|
||||
InitializationSequence InitSeq(*this, Entity, Kind,
|
||||
MultiExprArg(Inits, NumInits));
|
||||
ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind,
|
||||
MultiExprArg(Inits, NumInits));
|
||||
InitializationSequence InitSeq(*this, Entity, Kind, Exprs);
|
||||
ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, Exprs);
|
||||
if (FullInit.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
|
|
|
@ -3509,6 +3509,9 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
|||
case DeclaratorContext::FunctionalCast:
|
||||
if (isa<DeducedTemplateSpecializationType>(Deduced))
|
||||
break;
|
||||
if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType &&
|
||||
!Auto->isDecltypeAuto())
|
||||
break; // auto(x)
|
||||
LLVM_FALLTHROUGH;
|
||||
case DeclaratorContext::TypeName:
|
||||
Error = 15; // Generic
|
||||
|
|
|
@ -46,13 +46,18 @@ void j() {
|
|||
U<auto> v; // expected-error{{'auto' not allowed in template argument}}
|
||||
|
||||
int n;
|
||||
(void)dynamic_cast<auto&>(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)static_cast<auto*>(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)reinterpret_cast<auto*>(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)const_cast<auto>(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)*(auto*)(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)auto(n); // expected-error{{expected expression}}
|
||||
(void)auto{n}; // expected-error{{expected expression}}
|
||||
(void)dynamic_cast<auto &>(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)static_cast<auto *>(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)reinterpret_cast<auto *>(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)const_cast<auto const>(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)*(auto *)(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)dynamic_cast<auto>(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)static_cast<auto>(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)reinterpret_cast<auto>(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)const_cast<auto>(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)(auto)(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)auto(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)auto{n}; // expected-error{{'auto' not allowed here}}
|
||||
}
|
||||
|
||||
template <auto a = 10> class C { }; // expected-error{{'auto' not allowed in template parameter}}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
// RUN: %clang_cc1 -std=c++2b -verify %s
|
||||
|
||||
// p2.3 allows only T = auto in T(x).
|
||||
|
||||
void test_decay() {
|
||||
int v[3];
|
||||
static_assert(__is_same(decltype(auto(v)), int *));
|
||||
static_assert(__is_same(decltype(auto{v}), int *));
|
||||
static_assert(__is_same(decltype(auto("lit")), char const *));
|
||||
static_assert(__is_same(decltype(auto{"lit"}), char const *));
|
||||
|
||||
constexpr long i = 1;
|
||||
static_assert(__is_same(decltype(i), long const));
|
||||
static_assert(__is_same(decltype(auto(1L)), long));
|
||||
static_assert(__is_same(decltype(auto{1L}), long));
|
||||
static_assert(__is_same(decltype(auto(i)), long));
|
||||
static_assert(__is_same(decltype(auto{i}), long));
|
||||
|
||||
class A {
|
||||
} a;
|
||||
A const ac;
|
||||
|
||||
static_assert(__is_same(decltype(auto(a)), A));
|
||||
static_assert(__is_same(decltype(auto(ac)), A));
|
||||
|
||||
A &lr = a;
|
||||
A const &lrc = a;
|
||||
A &&rr = static_cast<A &&>(a);
|
||||
A const &&rrc = static_cast<A &&>(a);
|
||||
|
||||
static_assert(__is_same(decltype(auto(lr)), A));
|
||||
static_assert(__is_same(decltype(auto(lrc)), A));
|
||||
static_assert(__is_same(decltype(auto(rr)), A));
|
||||
static_assert(__is_same(decltype(auto(rrc)), A));
|
||||
}
|
||||
|
||||
class cmdline_parser {
|
||||
public:
|
||||
cmdline_parser(char const *);
|
||||
auto add_option(char const *, char const *) && -> cmdline_parser &&;
|
||||
};
|
||||
|
||||
void test_rvalue_fluent_interface() {
|
||||
auto cmdline = cmdline_parser("driver");
|
||||
auto internal = auto{cmdline}.add_option("--dump-full", "do not minimize dump");
|
||||
}
|
||||
|
||||
template <class T> constexpr auto decay_copy(T &&v) { return static_cast<T &&>(v); } // expected-error {{calling a protected constructor}}
|
||||
|
||||
class A {
|
||||
int x;
|
||||
friend void f(A &&);
|
||||
|
||||
public:
|
||||
A();
|
||||
|
||||
auto test_access() {
|
||||
static_assert(__is_same(decltype(auto(*this)), A));
|
||||
static_assert(__is_same(decltype(auto(this)), A *));
|
||||
|
||||
f(A(*this)); // ok
|
||||
f(auto(*this)); // ok in P0849
|
||||
f(decay_copy(*this)); // expected-note {{in instantiation of function template specialization}}
|
||||
}
|
||||
|
||||
auto test_access() const {
|
||||
static_assert(__is_same(decltype(auto(*this)), A)); // ditto
|
||||
static_assert(__is_same(decltype(auto(this)), A const *));
|
||||
}
|
||||
|
||||
protected:
|
||||
A(const A &); // expected-note {{declared protected here}}
|
||||
};
|
||||
|
||||
// post-C++17 semantics
|
||||
namespace auto_x {
|
||||
constexpr struct Uncopyable {
|
||||
constexpr explicit Uncopyable(int) {}
|
||||
constexpr Uncopyable(Uncopyable &&) = delete;
|
||||
} u = auto(Uncopyable(auto(Uncopyable(42))));
|
||||
} // namespace auto_x
|
|
@ -0,0 +1,39 @@
|
|||
// RUN: %clang_cc1 -std=c++2b -verify %s
|
||||
|
||||
template <class T>
|
||||
void foo(T);
|
||||
|
||||
struct A {
|
||||
int m;
|
||||
char g(int);
|
||||
float g(double);
|
||||
} a{1};
|
||||
|
||||
// C++2b [dcl.type.auto.deduct]p2.3
|
||||
// For an explicit type conversion, T is the specified type, which shall be auto.
|
||||
void diagnostics() {
|
||||
foo(auto()); // expected-error {{initializer for functional-style cast to 'auto' is empty}}
|
||||
foo(auto{}); // expected-error {{initializer for functional-style cast to 'auto' is empty}}
|
||||
foo(auto({})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
|
||||
foo(auto{{}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
|
||||
|
||||
// - If the initializer is a parenthesized expression-list, the expression-list shall be a single assignmentexpression and E is the assignment-expression.
|
||||
foo(auto(a));
|
||||
// - If the initializer is a braced-init-list, it shall consist of a single brace-enclosed assignment-expression and E is the assignment-expression.
|
||||
foo(auto{a});
|
||||
foo(auto({a})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
|
||||
foo(auto{{a}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
|
||||
|
||||
foo(auto(&A::g)); // expected-error {{functional-style cast to 'auto' has incompatible initializer of type '<overloaded function type>'}}
|
||||
|
||||
foo(auto(a, 3.14)); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
|
||||
foo(auto{a, 3.14}); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
|
||||
foo(auto({a, 3.14})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
|
||||
foo(auto{{a, 3.14}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
|
||||
foo(auto({a}, {3.14})); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
|
||||
foo(auto{{a}, {3.14}}); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
|
||||
|
||||
foo(auto{1, 2}); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
|
||||
foo(auto({1, 2})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
|
||||
foo(auto{{1, 2}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
|
||||
}
|
|
@ -16,7 +16,7 @@ void f() {
|
|||
new (auto) (1,2,3); // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
|
||||
new auto {}; // expected-error{{new expression for type 'auto' requires a constructor argument}}
|
||||
new auto {1,2,3}; // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
|
||||
new auto ({1,2,3}); // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
|
||||
new auto ({1,2,3}); // expected-error{{cannot deduce actual type for 'auto' from parenthesized initializer list}}
|
||||
}
|
||||
|
||||
void p2example() {
|
||||
|
|
|
@ -5,6 +5,6 @@ void f() {
|
|||
new auto {2}; // expected-warning {{ISO C++ standards before C++17 do not allow new expression for type 'auto' to use list-initialization}}
|
||||
new auto {1, 2}; // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
|
||||
new auto {}; // expected-error{{new expression for type 'auto' requires a constructor argument}}
|
||||
new decltype(auto)({1}); // expected-warning {{ISO C++ standards before C++17 do not allow new expression for type 'decltype(auto)' to use list-initialization}}
|
||||
new decltype(auto)({1, 2}); // expected-error{{new expression for type 'decltype(auto)' contains multiple constructor arguments}}
|
||||
new decltype(auto)({1}); // expected-error{{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
|
||||
new decltype(auto)({1, 2}); // expected-error{{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,30 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++17 -pedantic
|
||||
|
||||
// [expr.new]p2 ... the invented declaration: T x init ;
|
||||
// C++2b [dcl.type.auto.deduct]p2.2
|
||||
// For a variable declared with a type that contains a placeholder type, T is the declared type of the variable.
|
||||
void f() {
|
||||
// - If the initializer is a parenthesized expression-list, the expression-list shall be a single assignmentexpression and E is the assignment-expression.
|
||||
new auto('a');
|
||||
new auto {2};
|
||||
new auto {1, 2}; // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
|
||||
new auto {}; // expected-error{{new expression for type 'auto' requires a constructor argument}}
|
||||
new decltype(auto)({1});
|
||||
new decltype(auto)({1, 2}); // expected-error{{new expression for type 'decltype(auto)' contains multiple constructor arguments}}
|
||||
new decltype(auto)('a');
|
||||
// - If the initializer is a braced-init-list, it shall consist of a single brace-enclosed assignment-expression and E is the assignment-expression.
|
||||
new auto{2};
|
||||
new decltype(auto){2};
|
||||
|
||||
new auto{}; // expected-error{{new expression for type 'auto' requires a constructor argument}}
|
||||
new auto({}); // expected-error{{cannot deduce actual type for 'auto' from parenthesized initializer list}}
|
||||
new auto{{}}; // expected-error{{cannot deduce actual type for 'auto' from nested initializer list}}
|
||||
|
||||
new auto({2}); // expected-error{{cannot deduce actual type for 'auto' from parenthesized initializer list}}
|
||||
new auto{{2}}; // expected-error{{cannot deduce actual type for 'auto' from nested initializer list}}
|
||||
new auto{1, 2}; // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
|
||||
|
||||
new decltype(auto){}; // expected-error{{new expression for type 'decltype(auto)' requires a constructor argument}}
|
||||
new decltype(auto)({}); // expected-error{{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
|
||||
new decltype(auto){{}}; // expected-error{{cannot deduce actual type for 'decltype(auto)' from nested initializer list}}
|
||||
|
||||
new decltype(auto)({1}); // expected-error{{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
|
||||
new decltype(auto){1, 2}; // expected-error{{new expression for type 'decltype(auto)' contains multiple constructor arguments}}
|
||||
new decltype(auto)({1, 2}); // expected-error{{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx2b -std=c++2b -Wpre-c++2b-compat %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s
|
||||
|
||||
void looks_like_decltype_auto() {
|
||||
decltype(auto(42)) b = 42; // cxx20-error {{'auto' not allowed here}} \
|
||||
cxx2b-warning {{'auto' as a functional-style cast is incompatible with C++ standards before C++2b}}
|
||||
decltype(long *) a = 42; // expected-error {{expected '(' for function-style cast or type construction}} \
|
||||
expected-error {{expected expression}}
|
||||
decltype(auto *) a = 42; // expected-error {{expected '(' for function-style cast or type construction}} \
|
||||
expected-error {{expected expression}}
|
||||
decltype(auto()) c = 42; // cxx2b-error {{initializer for functional-style cast to 'auto' is empty}} \
|
||||
cxx20-error {{'auto' not allowed here}}
|
||||
}
|
||||
|
||||
struct looks_like_declaration {
|
||||
int n;
|
||||
} a;
|
||||
|
||||
using T = looks_like_declaration *;
|
||||
void f() { T(&a)->n = 1; }
|
||||
// FIXME: They should be deemed expressions without breaking function pointer
|
||||
// parameter declarations with trailing return types.
|
||||
// void g() { auto(&a)->n = 0; }
|
||||
// void h() { auto{&a}->n = 0; }
|
|
@ -0,0 +1,30 @@
|
|||
// RUN: %clang_cc1 -std=c++2b -fsyntax-only -ast-print %s | FileCheck %s
|
||||
|
||||
void test_auto_expr(long long y, auto &&z) {
|
||||
int x[] = {3, 4};
|
||||
|
||||
// CHECK{LITERAL}: (int)(x[1])
|
||||
void(auto(x[1]));
|
||||
// CHECK{LITERAL}: (int){x[1]}
|
||||
void(auto{x[1]});
|
||||
|
||||
// CHECK{LITERAL}: (int *)(x)
|
||||
void(auto(x));
|
||||
// CHECK{LITERAL}: (int *){x}
|
||||
void(auto{x});
|
||||
|
||||
// CHECK{LITERAL}: auto(z)
|
||||
void(auto(z));
|
||||
// CHECK{LITERAL}: auto({z})
|
||||
void(auto{z}); // T({z}) is legal unless T = auto
|
||||
|
||||
// CHECK{LITERAL}: new int *(x)
|
||||
void(new auto(x));
|
||||
// CHECK{LITERAL}: new int *{x}
|
||||
void(new auto{x});
|
||||
|
||||
// CHECK{LITERAL}: new long long(y)
|
||||
void(new decltype(auto)(y));
|
||||
// CHECK{LITERAL}: new long long{y}
|
||||
void(new decltype(auto){y});
|
||||
}
|
|
@ -1388,6 +1388,11 @@ C++20, informally referred to as C++2b.</p>
|
|||
<td><a href="https://wg21.link/P2360R0">P2360R0</a></td>
|
||||
<td class="unreleased" align="center">Clang 14</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>auto(x): decay-copy in the language</td>
|
||||
<td><a href="https://wg21.link/P0849R8">P0849R8</a></td>
|
||||
<td class="unreleased" align="center">Clang 15</td>
|
||||
</tr>
|
||||
<!-- February 2022 papers -->
|
||||
<tr>
|
||||
<td>Attributes on Lambda-Expressions</td>
|
||||
|
|
Loading…
Reference in New Issue