From a5227e0c9f9e145457db0aa03b3edf615bcb9d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Mon, 29 May 2023 22:00:40 -0400 Subject: [PATCH 1/3] fix(parse): make template-argument-list optional --- ...x-for-optional-template-argument-list.cpp2 | 2 + ...ix-for-optional-template-argument-list.cpp | 23 ++++++++++ ...ptional-template-argument-list.cpp2.output | 2 + source/cppfront.cpp | 4 +- source/parse.h | 44 +++++++++---------- 5 files changed, 51 insertions(+), 24 deletions(-) create mode 100644 regression-tests/pure2-bugfix-for-optional-template-argument-list.cpp2 create mode 100644 regression-tests/test-results/pure2-bugfix-for-optional-template-argument-list.cpp create mode 100644 regression-tests/test-results/pure2-bugfix-for-optional-template-argument-list.cpp2.output diff --git a/regression-tests/pure2-bugfix-for-optional-template-argument-list.cpp2 b/regression-tests/pure2-bugfix-for-optional-template-argument-list.cpp2 new file mode 100644 index 0000000000..d6fad5067c --- /dev/null +++ b/regression-tests/pure2-bugfix-for-optional-template-argument-list.cpp2 @@ -0,0 +1,2 @@ +plus: const std::plus<> = (); +main: () -> int = std::plus<>()(0, 0); diff --git a/regression-tests/test-results/pure2-bugfix-for-optional-template-argument-list.cpp b/regression-tests/test-results/pure2-bugfix-for-optional-template-argument-list.cpp new file mode 100644 index 0000000000..3b78d806f0 --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-optional-template-argument-list.cpp @@ -0,0 +1,23 @@ + +#define CPP2_USE_MODULES Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + + + +//=== Cpp2 type definitions and function declarations =========================== + +#line 1 "pure2-bugfix-for-optional-template-argument-list.cpp2" +extern std::plus<> const plus; +[[nodiscard]] auto main() -> int; + + +//=== Cpp2 function definitions ================================================= + +#line 1 "pure2-bugfix-for-optional-template-argument-list.cpp2" +std::plus<> const plus {}; +[[nodiscard]] auto main() -> int { return std::plus<>()(0, 0); } + diff --git a/regression-tests/test-results/pure2-bugfix-for-optional-template-argument-list.cpp2.output b/regression-tests/test-results/pure2-bugfix-for-optional-template-argument-list.cpp2.output new file mode 100644 index 0000000000..cd793f10af --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-optional-template-argument-list.cpp2.output @@ -0,0 +1,2 @@ +pure2-bugfix-for-optional-template-argument-list.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 382dfe122d..1a849bf3f4 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -1666,10 +1666,10 @@ class cppfront assert(n.identifier); emit(*n.identifier, is_qualified); // inform the identifier if we know this is qualified - if (!n.template_args.empty()) { + if (n.template_args.has_value()) { printer.print_cpp2("<", n.open_angle); auto first = true; - for (auto& a : n.template_args) { + for (auto& a : n.template_args.value()) { if (!first) { printer.print_cpp2(",", a.comma); } diff --git a/source/parse.h b/source/parse.h index 4ff01cbb09..1e654cd8a0 100644 --- a/source/parse.h +++ b/source/parse.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace cpp2 { @@ -682,18 +683,21 @@ struct unqualified_id_node std::unique_ptr > arg; }; - std::vector template_args; + std::optional> template_args; auto template_args_count() -> int { - return std::ssize(template_args); + if (template_args.has_value()) + return std::ssize(template_args.value()); + // else + return 0; } auto get_token() const -> token const* { - if (template_args.empty()) { + if (!template_args.has_value()) { assert (identifier); return identifier; } @@ -718,13 +722,14 @@ struct unqualified_id_node assert (identifier); v.start(*identifier, depth+1); - if (!template_args.empty()) { + if (template_args.has_value()) { // Inform the visitor that this is a template args list v.start(template_args_tag{}, depth); assert(open_angle != source_position{}); assert(close_angle != source_position{}); - assert(template_args.front().comma == source_position{}); - for (auto& a : template_args) { + assert(template_args.value().empty() + || template_args.value().front().comma == source_position{}); + for (auto& a : template_args.value()) { try_visit(a.arg, v, depth+1); try_visit(a.arg, v, depth+1); } @@ -925,9 +930,9 @@ auto unqualified_id_node::to_string() const { assert(identifier); auto ret = identifier->to_string(true); - if (!template_args.empty()) { + if (template_args.has_value()) { auto separator = std::string{"<"}; - for (auto& t : template_args) { + for (auto& t : template_args.value()) { ret += separator; assert(t.arg.index() != empty); if (t.arg.index() == expression) { @@ -4454,18 +4459,10 @@ class parser // Remember current position, in case this < is isn't a template argument list auto start_pos = pos; - // And since we'll do this in two places, factor it into a local function - auto back_out_template_arg_list = [&]{ - // Aha, this wasn't a template argument list after all, - // so back out just that part and return the identifier - n->open_angle = source_position{}; - n->template_args.clear(); - pos = start_pos; - }; - n->open_angle = curr().position(); next(); - + + n->template_args.emplace(); auto term = unqualified_id_node::term{}; do { @@ -4477,10 +4474,9 @@ class parser term.arg = std::move(i); } else { - back_out_template_arg_list(); - return n; + break; } - n->template_args.push_back( std::move(term) ); + n->template_args.value().push_back( std::move(term) ); } // Use the lambda trick to jam in a "next" clause while ( @@ -4492,7 +4488,11 @@ class parser // next term.comma = curr().position(); if (curr().type() != lexeme::Greater) { - back_out_template_arg_list(); + // Aha, this wasn't a template argument list after all, + // so back out just that part and return the identifier + n->open_angle = source_position{}; + n->template_args.reset(); + pos = start_pos; return n; } n->close_angle = curr().position(); From 237b792ef73ef57b86a3d99cbb6dc55698b92eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sat, 3 Jun 2023 10:13:01 -0400 Subject: [PATCH 2/3] refactor: use `open_angle` as cue for temp arg list --- source/cppfront.cpp | 4 ++-- source/parse.h | 27 +++++++++++---------------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 1a849bf3f4..35d5001d96 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -1666,10 +1666,10 @@ class cppfront assert(n.identifier); emit(*n.identifier, is_qualified); // inform the identifier if we know this is qualified - if (n.template_args.has_value()) { + if (n.open_angle != source_position{}) { printer.print_cpp2("<", n.open_angle); auto first = true; - for (auto& a : n.template_args.value()) { + for (auto& a : n.template_args) { if (!first) { printer.print_cpp2(",", a.comma); } diff --git a/source/parse.h b/source/parse.h index 1e654cd8a0..4eee1a3996 100644 --- a/source/parse.h +++ b/source/parse.h @@ -22,7 +22,6 @@ #include #include #include -#include namespace cpp2 { @@ -683,21 +682,18 @@ struct unqualified_id_node std::unique_ptr > arg; }; - std::optional> template_args; + std::vector template_args; auto template_args_count() -> int { - if (template_args.has_value()) - return std::ssize(template_args.value()); - // else - return 0; + return std::ssize(template_args); } auto get_token() const -> token const* { - if (!template_args.has_value()) { + if (open_angle == source_position{}) { assert (identifier); return identifier; } @@ -722,14 +718,14 @@ struct unqualified_id_node assert (identifier); v.start(*identifier, depth+1); - if (template_args.has_value()) { + if (open_angle != source_position{}) { // Inform the visitor that this is a template args list v.start(template_args_tag{}, depth); assert(open_angle != source_position{}); assert(close_angle != source_position{}); - assert(template_args.value().empty() - || template_args.value().front().comma == source_position{}); - for (auto& a : template_args.value()) { + assert(template_args.empty() + || template_args.front().comma == source_position{}); + for (auto& a : template_args) { try_visit(a.arg, v, depth+1); try_visit(a.arg, v, depth+1); } @@ -930,9 +926,9 @@ auto unqualified_id_node::to_string() const { assert(identifier); auto ret = identifier->to_string(true); - if (template_args.has_value()) { + if (open_angle != source_position{}) { auto separator = std::string{"<"}; - for (auto& t : template_args.value()) { + for (auto& t : template_args) { ret += separator; assert(t.arg.index() != empty); if (t.arg.index() == expression) { @@ -4462,7 +4458,6 @@ class parser n->open_angle = curr().position(); next(); - n->template_args.emplace(); auto term = unqualified_id_node::term{}; do { @@ -4476,7 +4471,7 @@ class parser else { break; } - n->template_args.value().push_back( std::move(term) ); + n->template_args.push_back( std::move(term) ); } // Use the lambda trick to jam in a "next" clause while ( @@ -4491,7 +4486,7 @@ class parser // Aha, this wasn't a template argument list after all, // so back out just that part and return the identifier n->open_angle = source_position{}; - n->template_args.reset(); + n->template_args.clear(); pos = start_pos; return n; } From 98bc9d547c869ab00ab86f2a52fc43add685f977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Tue, 6 Jun 2023 11:33:19 -0400 Subject: [PATCH 3/3] test: add `test-results/gcc-13` --- regression-tests/test-results/gcc-13/gcc-version.output | 5 +++++ ...-bugfix-for-optional-template-argument-list.cpp.execution | 0 ...re2-bugfix-for-optional-template-argument-list.cpp.output | 0 3 files changed, 5 insertions(+) create mode 100644 regression-tests/test-results/gcc-13/gcc-version.output create mode 100644 regression-tests/test-results/gcc-13/pure2-bugfix-for-optional-template-argument-list.cpp.execution create mode 100644 regression-tests/test-results/gcc-13/pure2-bugfix-for-optional-template-argument-list.cpp.output diff --git a/regression-tests/test-results/gcc-13/gcc-version.output b/regression-tests/test-results/gcc-13/gcc-version.output new file mode 100644 index 0000000000..7bbac4c854 --- /dev/null +++ b/regression-tests/test-results/gcc-13/gcc-version.output @@ -0,0 +1,5 @@ +c++ (GCC) 13.1.1 20230429 +Copyright (C) 2023 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-optional-template-argument-list.cpp.execution b/regression-tests/test-results/gcc-13/pure2-bugfix-for-optional-template-argument-list.cpp.execution new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-optional-template-argument-list.cpp.output b/regression-tests/test-results/gcc-13/pure2-bugfix-for-optional-template-argument-list.cpp.output new file mode 100644 index 0000000000..e69de29bb2