lichray updated this revision to Diff 411845. lichray added a comment. Restore the right diff
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D120589/new/ https://reviews.llvm.org/D120589 Files: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaType.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/SemaCXX/deduced-return-type-cxx14.cpp
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/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp =================================================================== --- clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp +++ clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2b -verify %s +// RUN: %clang_cc1 -std=c++2b -Wno-decltype-auto-cast -verify %s template <class T> void foo(T); @@ -37,3 +37,26 @@ 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 =================================================================== --- clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp +++ clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp @@ -1,6 +1,7 @@ -// RUN: %clang_cc1 -std=c++2b -verify %s +// 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]; @@ -9,6 +10,18 @@ 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)); @@ -16,6 +29,12 @@ 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; @@ -23,6 +42,18 @@ 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); @@ -32,6 +63,11 @@ 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 { @@ -79,3 +115,71 @@ 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/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -3509,9 +3509,8 @@ case DeclaratorContext::FunctionalCast: if (isa<DeducedTemplateSpecializationType>(Deduced)) break; - if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType && - !Auto->isDecltypeAuto()) - break; // auto(x) + 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 @@ -1495,8 +1495,11 @@ << Ty << FullRange); } if (getLangOpts().CPlusPlus2b) { - if (Ty->getAs<AutoType>()) - Diag(TyBeginLoc, diag::warn_cxx20_compat_auto_expr) << FullRange; + 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)) @@ -1512,6 +1515,14 @@ return ExprError(); Ty = DeducedType; + if (Ty->isReferenceType()) { + // decltype(auto)(x) takes a shortcut; see also P0849R2. + // FIXME: Substitute auto here to prevent a crash when diagnosing lifetime + // of array argument in constant evaluation. Shouldn't be done this way. + return BuildCXXFunctionalCastExpr(SubstAutoTypeSourceInfo(TInfo, Ty), Ty, + LParenOrBraceLoc, Deduce, + RParenOrBraceLoc); + } Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); } Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2387,6 +2387,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<
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits