diff --git a/regression-tests/mixed-bugfix-for-ufcs-non-local.cpp2 b/regression-tests/mixed-bugfix-for-ufcs-non-local.cpp2 index 9fff24aedc..f1ddf12091 100644 --- a/regression-tests/mixed-bugfix-for-ufcs-non-local.cpp2 +++ b/regression-tests/mixed-bugfix-for-ufcs-non-local.cpp2 @@ -38,7 +38,7 @@ d: _ == t(); // Fails on Clang 12 (lambda in unevaluated context). u: @struct type = { b: bool == o.f(); - c: bool == :(x: std::type_identity_t) x;(true); // Fails on Clang 12 (lambda in unevaluated context). + c: bool == :(x: decltype(o.f())) x;(true); // Fails on Clang 12 (lambda in unevaluated context). g: (s, sz) pre(s.sz() != 0) = { } } diff --git a/regression-tests/pure2-bugfix-for-non-local-function-expression.cpp2 b/regression-tests/pure2-bugfix-for-non-local-function-expression.cpp2 index 45edbc0b17..8522286511 100644 --- a/regression-tests/pure2-bugfix-for-non-local-function-expression.cpp2 +++ b/regression-tests/pure2-bugfix-for-non-local-function-expression.cpp2 @@ -4,10 +4,10 @@ v: concept = :() -> bool = true;(); -u: type == std::type_identity_t; +u: type == decltype(:() = {}); t: @struct type = { - this: std::type_identity_t; + this: decltype(:() = {}); } main: () = { } diff --git a/regression-tests/pure2-deduction-1-error.cpp2 b/regression-tests/pure2-deduction-1-error.cpp2 new file mode 100644 index 0000000000..6b49ac41ea --- /dev/null +++ b/regression-tests/pure2-deduction-1-error.cpp2 @@ -0,0 +1 @@ +f: () -> decltype(auto) = 0; diff --git a/regression-tests/pure2-deduction-2-error.cpp2 b/regression-tests/pure2-deduction-2-error.cpp2 new file mode 100644 index 0000000000..7d4e5da808 --- /dev/null +++ b/regression-tests/pure2-deduction-2-error.cpp2 @@ -0,0 +1 @@ +x: decltype(auto) = 0; diff --git a/regression-tests/pure2-last-use.cpp2 b/regression-tests/pure2-last-use.cpp2 index a0b73604c4..6aa53ddf96 100644 --- a/regression-tests/pure2-last-use.cpp2 +++ b/regression-tests/pure2-last-use.cpp2 @@ -42,7 +42,7 @@ issue_313: () = { _ = e is (e); f := new(0); - _ = f is std::type_identity_t; // OK? + _ = f is decltype(f); // OK? g := new(0); for (identity(g)* + identity(g)*) diff --git a/regression-tests/pure2-print.cpp2 b/regression-tests/pure2-print.cpp2 index c757e87ef2..23ec488d07 100644 --- a/regression-tests/pure2-print.cpp2 +++ b/regression-tests/pure2-print.cpp2 @@ -100,6 +100,8 @@ outer: @print type = { all: (args...: Args) -> bool = (... && args); + y: (_: decltype(0)) = { } + } main: () = { diff --git a/regression-tests/test-results/clang-12-c++20/mixed-bugfix-for-ufcs-non-local.cpp.output b/regression-tests/test-results/clang-12-c++20/mixed-bugfix-for-ufcs-non-local.cpp.output index a94faf4f22..fef7cc6c3a 100644 --- a/regression-tests/test-results/clang-12-c++20/mixed-bugfix-for-ufcs-non-local.cpp.output +++ b/regression-tests/test-results/clang-12-c++20/mixed-bugfix-for-ufcs-non-local.cpp.output @@ -106,9 +106,9 @@ mixed-bugfix-for-ufcs-non-local.cpp2:27:29: error: a lambda expression cannot ap ../../../include/cpp2util.h:2099:66: note: expanded from macro 'CPP2_UFCS_' #define CPP2_UFCS_(LAMBDADEFCAPT,SFINAE,MVFWD,QUALID,TEMPKW,...) \ ^ -mixed-bugfix-for-ufcs-non-local.cpp2:41:84: error: lambda expression in an unevaluated operand - inline CPP2_CONSTEXPR bool u::c{ [](cpp2::impl::in> x) -> auto { return x; }(true) };// Fails on Clang 12 (lambda in unevaluated context). - ^ +mixed-bugfix-for-ufcs-non-local.cpp2:41:63: error: lambda expression in an unevaluated operand + inline CPP2_CONSTEXPR bool u::c{ [](cpp2::impl::in x) -> auto { return x; }(true) };// Fails on Clang 12 (lambda in unevaluated context). + ^ ../../../include/cpp2util.h:2137:59: note: expanded from macro 'CPP2_UFCS_NONLOCAL' #define CPP2_UFCS_NONLOCAL(...) CPP2_UFCS_(,CPP2_UFCS_IDENTITY,CPP2_UFCS_IDENTITY,(),,__VA_ARGS__) ^ diff --git a/regression-tests/test-results/clang-12-c++20/pure2-bugfix-for-non-local-function-expression.cpp.output b/regression-tests/test-results/clang-12-c++20/pure2-bugfix-for-non-local-function-expression.cpp.output index 7922990a5a..033778a130 100644 --- a/regression-tests/test-results/clang-12-c++20/pure2-bugfix-for-non-local-function-expression.cpp.output +++ b/regression-tests/test-results/clang-12-c++20/pure2-bugfix-for-non-local-function-expression.cpp.output @@ -1,10 +1,10 @@ pure2-bugfix-for-non-local-function-expression.cpp2:5:34: error: lambda expression in an unevaluated operand template concept v = []() -> bool { return true; }(); ^ -pure2-bugfix-for-non-local-function-expression.cpp2:7:41: error: lambda expression in an unevaluated operand -using u = std::type_identity_t void{})>; - ^ -pure2-bugfix-for-non-local-function-expression.cpp2:9:47: error: lambda expression in an unevaluated operand -class t: public std::type_identity_t void{})> { - ^ +pure2-bugfix-for-non-local-function-expression.cpp2:7:20: error: lambda expression in an unevaluated operand +using u = decltype([]() -> void{}); + ^ +pure2-bugfix-for-non-local-function-expression.cpp2:9:26: error: lambda expression in an unevaluated operand +class t: public decltype([]() -> void{}) { + ^ 3 errors generated. diff --git a/regression-tests/test-results/mixed-bugfix-for-ufcs-non-local.cpp b/regression-tests/test-results/mixed-bugfix-for-ufcs-non-local.cpp index 1992bf7230..77fd432e01 100644 --- a/regression-tests/test-results/mixed-bugfix-for-ufcs-non-local.cpp +++ b/regression-tests/test-results/mixed-bugfix-for-ufcs-non-local.cpp @@ -95,7 +95,7 @@ auto g() -> void{ #line 40 "mixed-bugfix-for-ufcs-non-local.cpp2" inline CPP2_CONSTEXPR bool u::b{ CPP2_UFCS_NONLOCAL(f)(o) }; - inline CPP2_CONSTEXPR bool u::c{ [](cpp2::impl::in> x) -> auto { return x; }(true) };// Fails on Clang 12 (lambda in unevaluated context). + inline CPP2_CONSTEXPR bool u::c{ [](cpp2::impl::in x) -> auto { return x; }(true) };// Fails on Clang 12 (lambda in unevaluated context). auto u::g(auto const& s, auto const& sz) -> void{ if (cpp2::cpp2_default.is_active() && !(CPP2_UFCS(sz)(s) != 0) ) { cpp2::cpp2_default.report_violation(""); }} diff --git a/regression-tests/test-results/pure2-bugfix-for-non-local-function-expression.cpp b/regression-tests/test-results/pure2-bugfix-for-non-local-function-expression.cpp index 90b4f54a1f..f7bf2d3d34 100644 --- a/regression-tests/test-results/pure2-bugfix-for-non-local-function-expression.cpp +++ b/regression-tests/test-results/pure2-bugfix-for-non-local-function-expression.cpp @@ -22,9 +22,9 @@ class t; #line 5 "pure2-bugfix-for-non-local-function-expression.cpp2" template concept v = []() -> bool { return true; }(); -using u = std::type_identity_t void{})>; +using u = decltype([]() -> void{}); -class t: public std::type_identity_t void{})> { +class t: public decltype([]() -> void{}) { }; diff --git a/regression-tests/test-results/pure2-deduction-1-error.cpp2.output b/regression-tests/test-results/pure2-deduction-1-error.cpp2.output new file mode 100644 index 0000000000..f9e8a0744b --- /dev/null +++ b/regression-tests/test-results/pure2-deduction-1-error.cpp2.output @@ -0,0 +1,3 @@ +pure2-deduction-1-error.cpp2... +pure2-deduction-1-error.cpp2(1,10): error: decltype(auto) is not needed in Cpp2 - for return types, use '-> forward _' instead + diff --git a/regression-tests/test-results/pure2-deduction-2-error.cpp2.output b/regression-tests/test-results/pure2-deduction-2-error.cpp2.output new file mode 100644 index 0000000000..552c1f3375 --- /dev/null +++ b/regression-tests/test-results/pure2-deduction-2-error.cpp2.output @@ -0,0 +1,3 @@ +pure2-deduction-2-error.cpp2... +pure2-deduction-2-error.cpp2(1,4): error: decltype(auto) is not needed in Cpp2 - for return types, use '-> forward _' instead + diff --git a/regression-tests/test-results/pure2-last-use.cpp b/regression-tests/test-results/pure2-last-use.cpp index cd378b0868..caef6de6ab 100644 --- a/regression-tests/test-results/pure2-last-use.cpp +++ b/regression-tests/test-results/pure2-last-use.cpp @@ -606,7 +606,7 @@ auto issue_313() -> void{ static_cast(cpp2::impl::is(e, (e))); auto f {cpp2_new(0)}; - static_cast(cpp2::impl::is>(f));// OK? + static_cast(cpp2::impl::is(f));// OK? auto g {cpp2_new(0)}; for ( diff --git a/regression-tests/test-results/pure2-print.cpp b/regression-tests/test-results/pure2-print.cpp index 74103903ed..40402c3393 100644 --- a/regression-tests/test-results/pure2-print.cpp +++ b/regression-tests/test-results/pure2-print.cpp @@ -70,12 +70,15 @@ CPP2_REQUIRES_ (cpp2::impl::cmp_greater_eq(sizeof...(Args),0u)) ; #line 100 "pure2-print.cpp2" public: template [[nodiscard]] static auto all(Args const& ...args) -> bool; + +#line 103 "pure2-print.cpp2" + public: static auto y([[maybe_unused]] cpp2::impl::in unnamed_param_1) -> void; public: outer() = default; public: outer(outer const&) = delete; /* No 'that' constructor, suppress copy */ public: auto operator=(outer const&) -> void = delete; -#line 103 "pure2-print.cpp2" +#line 105 "pure2-print.cpp2" }; auto main() -> int; @@ -199,7 +202,10 @@ requires (cpp2::impl::cmp_greater_eq(sizeof...(Args),0u)) { template [[nodiscard]] auto outer::all(Args const& ...args) -> bool { return (... && args); } -#line 105 "pure2-print.cpp2" +#line 103 "pure2-print.cpp2" + auto outer::y([[maybe_unused]] cpp2::impl::in unnamed_param_1) -> void{} + +#line 107 "pure2-print.cpp2" auto main() -> int{ outer::test(); } diff --git a/regression-tests/test-results/pure2-print.cpp2.output b/regression-tests/test-results/pure2-print.cpp2.output index d523e2f544..1c141deb84 100644 --- a/regression-tests/test-results/pure2-print.cpp2.output +++ b/regression-tests/test-results/pure2-print.cpp2.output @@ -146,6 +146,10 @@ outer:/* @print */ type = } all: (in args...: Args, ) -> move bool = (... && args); + + y:(in _: decltype(0), ) = + { + } } ok (all Cpp2, passes safety checks) diff --git a/source/parse.h b/source/parse.h index 44d45c9d68..ff06f26947 100644 --- a/source/parse.h +++ b/source/parse.h @@ -1365,9 +1365,10 @@ struct type_id_node int dereference_cnt = {}; token const* suspicious_initialization = {}; - enum active : u8 { empty=0, qualified, unqualified, function, keyword }; + enum active : u8 { empty=0, decltype_, qualified, unqualified, function, keyword }; std::variant< std::monostate, + std::unique_ptr, std::unique_ptr, std::unique_ptr, std::unique_ptr, @@ -1419,6 +1420,9 @@ struct type_id_node if (id.index() == unqualified) { return std::get(id)->template_arguments(); } + else if (id.index() != qualified) { + cpp2_default.report_violation("ICE: this type_id has no template arguments"); + } // else return std::get(id)->template_arguments(); } @@ -1432,6 +1436,8 @@ struct type_id_node switch (id.index()) { break;case empty: return {}; + break;case decltype_: + return {}; break;case qualified: return {}; break;case unqualified: @@ -1460,6 +1466,7 @@ struct type_id_node for (auto q : pc_qualifiers) { v.start(*q, depth+1); } + try_visit(id, v, depth); try_visit(id, v, depth); try_visit(id, v, depth); try_visit(id, v, depth); @@ -2770,6 +2777,8 @@ auto type_id_node::to_string() const switch (id.index()) { break;case empty: ret += "_"; + break;case decltype_: + ret += std::get(id)->to_string(); break;case qualified: ret += std::get(id)->to_string(); break;case unqualified: @@ -5084,6 +5093,7 @@ auto pretty_print_visualize(type_id_node const& n, int indent) } if (n.id.index() == type_id_node::empty) { ret += "_"; } + ret += try_pretty_print_visualize(n.id, indent); ret += try_pretty_print_visualize(n.id, indent); ret += try_pretty_print_visualize(n.id, indent); ret += try_pretty_print_visualize(n.id, indent); @@ -6867,6 +6877,7 @@ class parser //G type-id: + //G type-qualifier-seq? 'decltype' '(' expression ')' is-type-constraint? //G type-qualifier-seq? qualified-id is-type-constraint? //G type-qualifier-seq? unqualified-id is-type-constraint? //G type-qualifier-seq? function-type is-type-constraint? @@ -6909,7 +6920,39 @@ class parser next(); } - if (auto id = qualified_id()) { + if (auto& c = curr(); + c == "decltype" + ) + { + if ( + peek(1) && peek(1)->type() == lexeme::LeftParen + && peek(2) && *peek(2) == "auto" + && peek(3) && peek(3)->type() == lexeme::RightParen) + { + error( + "decltype(auto) is not needed in Cpp2 - for return types, use '-> forward _' instead", + false, + c.position() + ); + } + if (auto id = postfix_expression(); + id + && id->ops.size() == 1 + && id->ops[0].expr_list->expressions.size() == 1 + && id->ops[0].expr_list->open_paren->type() == lexeme::LeftParen + ) + { + n->pos = id->position(); + n->id = std::move(id); + assert (n->id.index() == type_id_node::decltype_); + } + else + { + error("'decltype' must be followed by a single parenthesized expression", false, c.position()); + return {}; + } + } + else if (auto id = qualified_id()) { n->pos = id->position(); n->id = std::move(id); assert (n->id.index() == type_id_node::qualified); diff --git a/source/to_cpp1.h b/source/to_cpp1.h index 00ac1cdac0..1bfee1f4da 100644 --- a/source/to_cpp1.h +++ b/source/to_cpp1.h @@ -1939,6 +1939,7 @@ class cppfront printer.print_cpp2("auto", pos); } else { + try_emit(n.id); try_emit(n.id, 0, false); try_emit(n.id); try_emit(n.id);