lichray updated this revision to Diff 410915. lichray added a comment. - Add more tests to diagnose other forms of casts
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D113393/new/ https://reviews.llvm.org/D113393 Files: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Parse/ParseDeclCXX.cpp clang/lib/Parse/ParseExpr.cpp clang/lib/Parse/ParseExprCXX.cpp clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaType.cpp clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp clang/test/Parser/cxx2b-auto-x.cpp clang/test/SemaCXX/deduced-return-type-cxx14.cpp clang/www/cxx_status.html
Index: clang/www/cxx_status.html =================================================================== --- clang/www/cxx_status.html +++ clang/www/cxx_status.html @@ -1388,6 +1388,11 @@ <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> Index: clang/test/SemaCXX/deduced-return-type-cxx14.cpp =================================================================== --- clang/test/SemaCXX/deduced-return-type-cxx14.cpp +++ clang/test/SemaCXX/deduced-return-type-cxx14.cpp @@ -442,6 +442,15 @@ B() : decltype(auto)() {} // expected-error {{'decltype(auto)' not allowed here}} }; } + + namespace Cast { + void foo() { + (void)decltype(auto)(0); // cxx14_20-error{{'decltype(auto)' not allowed here}} \ + cxx2b-warning{{functional-style cast to 'decltype(auto)' is a Clang extension}} + (void)decltype(auto){0}; // cxx14_20-error{{'decltype(auto)' not allowed here}} \ + cxx2b-warning{{functional-style cast to 'decltype(auto)' is a Clang extension}} + } + } } namespace CurrentInstantiation { Index: clang/test/Parser/cxx2b-auto-x.cpp =================================================================== --- /dev/null +++ clang/test/Parser/cxx2b-auto-x.cpp @@ -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; } Index: clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp =================================================================== --- clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp +++ clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp @@ -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}} } Index: clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp =================================================================== --- clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp +++ clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp @@ -5,6 +5,6 @@ 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}} } Index: clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp =================================================================== --- clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp +++ clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp @@ -16,7 +16,7 @@ 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() { Index: clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp =================================================================== --- /dev/null +++ clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -std=c++2b -Wno-decltype-auto-cast -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}} +} + +void diagnostics_extension() { + foo(decltype(auto)()); // expected-error {{initializer for functional-style cast to 'decltype(auto)' is empty}} + foo(decltype(auto){}); // expected-error {{initializer for functional-style cast to 'decltype(auto)' is empty}} + foo(decltype(auto)({})); // expected-error {{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}} + foo(decltype(auto){{}}); // expected-error {{cannot deduce actual type for 'decltype(auto)' from nested initializer list}} + + foo(decltype(auto)({a})); // expected-error {{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}} + foo(decltype(auto){{a}}); // expected-error {{cannot deduce actual type for 'decltype(auto)' from nested initializer list}} + + foo(decltype(auto)(&A::g)); // expected-error {{reference to overloaded function could not be resolved}} + + foo(decltype(auto)(a, 3.14)); // expected-error {{initializer for functional-style cast to 'decltype(auto)' contains multiple expressions}} + foo(decltype(auto){a, 3.14}); // expected-error {{initializer for functional-style cast to 'decltype(auto)' contains multiple expressions}} + foo(decltype(auto)({a, 3.14})); // expected-error {{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}} + foo(decltype(auto){{a, 3.14}}); // expected-error {{cannot deduce actual type for 'decltype(auto)' from nested initializer list}} + foo(decltype(auto)({a}, {3.14})); // expected-error {{initializer for functional-style cast to 'decltype(auto)' contains multiple expressions}} + foo(decltype(auto){{a}, {3.14}}); // expected-error {{initializer for functional-style cast to 'decltype(auto)' contains multiple expressions}} + + foo(decltype(auto){1, 2}); // expected-error {{initializer for functional-style cast to 'decltype(auto)' contains multiple expressions}} + foo(decltype(auto)({1, 2})); // expected-error {{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}} + foo(decltype(auto){{1, 2}}); // expected-error {{cannot deduce actual type for 'decltype(auto)' from nested initializer list}} +} Index: clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp =================================================================== --- /dev/null +++ clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp @@ -0,0 +1,185 @@ +// RUN: %clang_cc1 -std=c++2b -Wno-decltype-auto-cast -verify %s + +// p2.3 allows only T = auto in T(x). +// As a Clang extension, we also allow T = decltype(auto) to match p2.2 (new 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 *)); + + void(decltype(auto)(v)); // expected-error {{functional-style cast}} + void(decltype(auto){v}); // expected-error {{cannot initialize an array element}} + static_assert(__is_same(decltype(decltype(auto)("lit")), char const(&)[4])); + static_assert(__is_same(decltype(decltype(auto){"lit"}), char const(&)[4])); + + int fn(char *); + static_assert(__is_same(decltype(auto(fn)), int (*)(char *))); + static_assert(__is_same(decltype(auto{fn}), int (*)(char *))); + + void(decltype(auto)(fn)); // expected-error{{functional-style cast}} + void(decltype(auto){fn}); // expected-error{{cannot create object of function type}} + + 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)); + + // scalar prvalue is not cv-qualified + static_assert(__is_same(decltype(decltype(auto)(1L)), long)); + static_assert(__is_same(decltype(decltype(auto){1L}), long)); + static_assert(__is_same(decltype(decltype(auto)(i)), long)); + static_assert(__is_same(decltype(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)); + + static_assert(__is_same(decltype(decltype(auto)(a)), A)); + static_assert(__is_same(decltype(decltype(auto)(ac)), A const)); + + static_assert(__is_same(decltype(decltype(auto)((a))), A &)); + static_assert(__is_same(decltype(decltype(auto)((ac))), A const &)); + + static_assert(__is_same(decltype(decltype(auto){a}), A)); + static_assert(__is_same(decltype(decltype(auto){ac}), A const)); + + static_assert(__is_same(decltype(decltype(auto){(a)}), A &)); + static_assert(__is_same(decltype(decltype(auto){(ac)}), A const &)); + + 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)); + + static_assert(__is_same(decltype(decltype(auto)(lr)), A &)); + static_assert(__is_same(decltype(decltype(auto)(lrc)), A const &)); + static_assert(__is_same(decltype(decltype(auto)(rr)), A &&)); + static_assert(__is_same(decltype(decltype(auto)(rrc)), A const &&)); +} + +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 + +// decltype(auto) is no-op to prvalues +namespace decltype_auto_x { +constexpr struct Uncopyable { + constexpr explicit Uncopyable(int) {} + constexpr Uncopyable(Uncopyable &&) = delete; +} u = decltype(auto)(Uncopyable(decltype(auto)(Uncopyable(42)))); +} // namespace decltype_auto_x + +// Forward with decltype(auto) +constexpr auto invoke1 = [](auto &&x, auto &&y) { + return decltype(auto)(x)(decltype(auto)(y)); +}; + +struct MoveOnly { + MoveOnly() = default; + MoveOnly(MoveOnly &&) = default; + MoveOnly(MoveOnly const &) = delete; +}; + +constexpr MoveOnly getMoveOnly() { return {}; } + +struct Fn { + constexpr int operator()(MoveOnly &) & { return 0; } + constexpr int operator()(MoveOnly &&) & { return 1; } + + constexpr int operator()(MoveOnly &) && { return 2; } + constexpr int operator()(MoveOnly &&) && { return 3; } + + constexpr int operator()(MoveOnly &) const & { return 4; } + constexpr int operator()(MoveOnly &&) const & { return 5; } + + constexpr int operator()(MoveOnly &) const && { return 6; } + constexpr int operator()(MoveOnly &&) const && { return 7; } +}; + +constexpr void FwdWithDecltypeAuto() { + MoveOnly lv; + Fn f; + constexpr Fn cf; + + static_assert(invoke1(f, lv) == 0); + static_assert(invoke1(f, getMoveOnly()) == 1); + + static_assert(invoke1(Fn{}, lv) == 2); + static_assert(invoke1(Fn{}, getMoveOnly()) == 3); + + static_assert(invoke1(cf, lv) == 4); + static_assert(invoke1(cf, getMoveOnly()) == 5); + + static_assert(invoke1((Fn const){}, lv) == 6); + static_assert(invoke1((Fn const){}, getMoveOnly()) == 7); +} + +struct FnArray { + template <class T, int N> + constexpr int operator()(T (&)[N]) const { return 0; } + + template <class T, int N> + constexpr int operator()(T (&&)[N]) const { return 1; } +}; + +constexpr void FwdArrayWithDecltypeAuto() { + FnArray f; + + static_assert(invoke1(f, "foo") == 0); + static_assert(invoke1(f, (int[]){1, 2, 3}) == 1); +} Index: clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp =================================================================== --- clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp +++ clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp @@ -46,13 +46,18 @@ 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}} Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -3506,6 +3506,8 @@ case DeclaratorContext::FunctionalCast: if (isa<DeducedTemplateSpecializationType>(Deduced)) break; + if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType) + break; // auto(x) and decltype(auto)(x) LLVM_FALLTHROUGH; case DeclaratorContext::TypeName: Error = 15; // Generic Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -1468,6 +1468,9 @@ // 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,50 @@ 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 (auto *TyAuto = Ty->getAs<AutoType>()) + Diag(TyBeginLoc, TyAuto->isDecltypeAuto() + ? diag::ext_decltype_auto_expr + : 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; + if (Ty->isReferenceType()) { + // decltype(auto)(x) takes a shortcut; see also P0849R2. + return BuildCXXFunctionalCastExpr(SubstAutoTypeSourceInfo(TInfo, Ty), Ty, + LParenOrBraceLoc, Deduce, + RParenOrBraceLoc); + } + Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); } if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { @@ -1983,12 +2030,10 @@ return ExprError(); } else if (Deduced) { 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>(Inits[0]); + Inits = ILE->getInits(); + NumInits = ILE->getNumInits(); } if (initStyle == CXXNewExpr::NoInit || NumInits == 0) @@ -2004,6 +2049,10 @@ 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) Index: clang/lib/Parse/ParseExprCXX.cpp =================================================================== --- clang/lib/Parse/ParseExprCXX.cpp +++ clang/lib/Parse/ParseExprCXX.cpp @@ -2231,6 +2231,9 @@ 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; Index: clang/lib/Parse/ParseExpr.cpp =================================================================== --- clang/lib/Parse/ParseExpr.cpp +++ clang/lib/Parse/ParseExpr.cpp @@ -1524,6 +1524,7 @@ 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: Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -1030,10 +1030,9 @@ } // 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 Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2325,13 +2325,23 @@ "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">; @@ -2345,6 +2355,8 @@ "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< @@ -2380,6 +2392,9 @@ "cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">; def err_decltype_auto_initializer_list : Error< "cannot deduce 'decltype(auto)' from initializer list">; +def ext_decltype_auto_expr : ExtWarn< + "functional-style cast to 'decltype(auto)' is a Clang extension">, + InGroup<DiagGroup<"decltype-auto-cast">>; // C++17 deduced class template specialization types def err_deduced_class_template_compound_type : Error< Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -114,6 +114,7 @@ ^^^^^^^^^^^^^^^^^^^^^ - 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 ------------------------------
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits