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/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 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..35d5001d96 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -1666,7 +1666,7 @@ 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.open_angle != source_position{}) { printer.print_cpp2("<", n.open_angle); auto first = true; for (auto& a : n.template_args) { diff --git a/source/parse.h b/source/parse.h index 4ff01cbb09..4eee1a3996 100644 --- a/source/parse.h +++ b/source/parse.h @@ -693,7 +693,7 @@ struct unqualified_id_node auto get_token() const -> token const* { - if (template_args.empty()) { + if (open_angle == source_position{}) { assert (identifier); return identifier; } @@ -718,12 +718,13 @@ struct unqualified_id_node assert (identifier); v.start(*identifier, depth+1); - if (!template_args.empty()) { + 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.front().comma == source_position{}); + 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); @@ -925,7 +926,7 @@ auto unqualified_id_node::to_string() const { assert(identifier); auto ret = identifier->to_string(true); - if (!template_args.empty()) { + if (open_angle != source_position{}) { auto separator = std::string{"<"}; for (auto& t : template_args) { ret += separator; @@ -4454,18 +4455,9 @@ 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(); - + auto term = unqualified_id_node::term{}; do { @@ -4477,8 +4469,7 @@ class parser term.arg = std::move(i); } else { - back_out_template_arg_list(); - return n; + break; } n->template_args.push_back( std::move(term) ); } @@ -4492,7 +4483,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.clear(); + pos = start_pos; return n; } n->close_angle = curr().position();