diff --git a/regression-tests/pure2-variadics.cpp2 b/regression-tests/pure2-variadics.cpp2 new file mode 100644 index 000000000..3bfe5d796 --- /dev/null +++ b/regression-tests/pure2-variadics.cpp2 @@ -0,0 +1,17 @@ + +x: type = { + tup: std::tuple = (); +} + +make_string: (forward args...: Args) -> _ = :std::string = args...; + +make: (forward args...: Args) -> _ = :T = args...; + +main: () += { + a: x = (); + + std::cout << std::string("xyzzy", 3) << "\n"; + std::cout << make_string("plugh", :u8=3) << "\n"; + std::cout << make("abracadabra", :u8=3) << "\n"; +} diff --git a/regression-tests/test-results/clang-12/pure2-variadics.cpp.execution b/regression-tests/test-results/clang-12/pure2-variadics.cpp.execution new file mode 100644 index 000000000..632435310 --- /dev/null +++ b/regression-tests/test-results/clang-12/pure2-variadics.cpp.execution @@ -0,0 +1,3 @@ +xyz +plu +abr diff --git a/regression-tests/test-results/clang-12/pure2-variadics.cpp.output b/regression-tests/test-results/clang-12/pure2-variadics.cpp.output new file mode 100644 index 000000000..e69de29bb diff --git a/regression-tests/test-results/gcc-10/pure2-variadics.cpp.execution b/regression-tests/test-results/gcc-10/pure2-variadics.cpp.execution new file mode 100644 index 000000000..632435310 --- /dev/null +++ b/regression-tests/test-results/gcc-10/pure2-variadics.cpp.execution @@ -0,0 +1,3 @@ +xyz +plu +abr diff --git a/regression-tests/test-results/gcc-10/pure2-variadics.cpp.output b/regression-tests/test-results/gcc-10/pure2-variadics.cpp.output new file mode 100644 index 000000000..e69de29bb diff --git a/regression-tests/test-results/gcc-13/pure2-variadics.cpp.execution b/regression-tests/test-results/gcc-13/pure2-variadics.cpp.execution new file mode 100644 index 000000000..632435310 --- /dev/null +++ b/regression-tests/test-results/gcc-13/pure2-variadics.cpp.execution @@ -0,0 +1,3 @@ +xyz +plu +abr diff --git a/regression-tests/test-results/gcc-13/pure2-variadics.cpp.output b/regression-tests/test-results/gcc-13/pure2-variadics.cpp.output new file mode 100644 index 000000000..e69de29bb diff --git a/regression-tests/test-results/msvc-2022/pure2-variadics.cpp.execution b/regression-tests/test-results/msvc-2022/pure2-variadics.cpp.execution new file mode 100644 index 000000000..632435310 --- /dev/null +++ b/regression-tests/test-results/msvc-2022/pure2-variadics.cpp.execution @@ -0,0 +1,3 @@ +xyz +plu +abr diff --git a/regression-tests/test-results/msvc-2022/pure2-variadics.cpp.output b/regression-tests/test-results/msvc-2022/pure2-variadics.cpp.output new file mode 100644 index 000000000..01aa45382 --- /dev/null +++ b/regression-tests/test-results/msvc-2022/pure2-variadics.cpp.output @@ -0,0 +1 @@ +pure2-variadics.cpp diff --git a/regression-tests/test-results/pure2-variadics.cpp b/regression-tests/test-results/pure2-variadics.cpp new file mode 100644 index 000000000..fc59ef63e --- /dev/null +++ b/regression-tests/test-results/pure2-variadics.cpp @@ -0,0 +1,50 @@ + +#define CPP2_USE_MODULES Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + + +#line 2 "pure2-variadics.cpp2" +template class x; + + +//=== Cpp2 type definitions and function declarations =========================== + + +#line 2 "pure2-variadics.cpp2" +template class x { + private: std::tuple tup {}; + public: x() = default; + public: x(x const&) = delete; /* No 'that' constructor, suppress copy */ + public: auto operator=(x const&) -> void = delete; + +#line 4 "pure2-variadics.cpp2" +}; + +template [[nodiscard]] auto make_string(Args&& ...args) -> auto; + +template [[nodiscard]] auto make(Args&& ...args) -> auto; + +auto main() -> int; + + +//=== Cpp2 function definitions ================================================= + + +#line 6 "pure2-variadics.cpp2" +template [[nodiscard]] auto make_string(Args&& ...args) -> auto { return std::string{CPP2_FORWARD(args)...}; } + +template [[nodiscard]] auto make(Args&& ...args) -> auto { return T{CPP2_FORWARD(args)...}; } + +auto main() -> int +{ + x a {}; + + std::cout << std::string("xyzzy", 3) << "\n"; + std::cout << make_string("plugh", cpp2::u8{3}) << "\n"; + std::cout << make("abracadabra", cpp2::u8{3}) << "\n"; +} + diff --git a/regression-tests/test-results/pure2-variadics.cpp2.output b/regression-tests/test-results/pure2-variadics.cpp2.output new file mode 100644 index 000000000..bf976aac4 --- /dev/null +++ b/regression-tests/test-results/pure2-variadics.cpp2.output @@ -0,0 +1,2 @@ +pure2-variadics.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/regression-tests/test-results/version b/regression-tests/test-results/version index 52acda843..f9603c154 100644 --- a/regression-tests/test-results/version +++ b/regression-tests/test-results/version @@ -1,5 +1,5 @@ -cppfront compiler v0.2.1 Build 8911:1701 +cppfront compiler v0.2.1 Build 8912:1051 Copyright(c) Herb Sutter All rights reserved SPDX-License-Identifier: CC-BY-NC-ND-4.0 diff --git a/source/build.info b/source/build.info index 81c7f576b..cbce88813 100644 --- a/source/build.info +++ b/source/build.info @@ -1 +1 @@ -"8911:1701" \ No newline at end of file +"8912:1051" \ No newline at end of file diff --git a/source/cppfront.cpp b/source/cppfront.cpp index b6ccebc30..b0e337534 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -2514,7 +2514,14 @@ class cppfront emit(*type_id); printer.print_cpp2("{", decl->position()); - assert(decl->initializer); + if (!decl->initializer) { + errors.emplace_back( + decl->position(), + "an anonymous object declaration must have '=' and an initializer" + ); + return; + } + emit(*decl->initializer, false); printer.print_cpp2("}", decl->position()); @@ -3888,8 +3895,6 @@ class cppfront ) { pass = "&&"; - //assert(emitting_move_that_function); // this should already have been set - ////emitting_move_that_function = true; } auto func_name = get_enclosing_function_name(); @@ -3918,6 +3923,12 @@ class cppfront if (n.declaration->is_type()) { printer.print_cpp2("typename ", n.declaration->identifier->position()); + if (n.declaration->is_variadic) { + printer.print_cpp2( + "...", + n.declaration->identifier->position() + ); + } assert (n.declaration->identifier); emit(*n.declaration->identifier); return; @@ -3999,6 +4010,7 @@ class cppfront if ( !is_returns + && !n.declaration->is_variadic && !type_id.is_wildcard() && !is_dependent_parameter_type && !type_id.is_pointer_qualified() @@ -4023,6 +4035,7 @@ class cppfront else if ( type_id.is_wildcard() || is_dependent_parameter_type + || n.declaration->is_variadic ) { auto name = std::string{"auto"}; @@ -4080,6 +4093,7 @@ class cppfront && !type_id.is_wildcard() && !is_dependent_parameter_type && !type_id.is_pointer_qualified() + && !n.declaration->is_variadic ) { switch (n.pass) { @@ -4097,7 +4111,23 @@ class cppfront printer.print_extra( " " + identifier); } else { - printer.print_cpp2( " " + identifier, n.declaration->identifier->position()); + printer.print_cpp2( " ", n.declaration->identifier->position()); + if (n.declaration->is_variadic) + { + if (n.direction() == passing_style::out) { + errors.emplace_back( + n.declaration->position(), + "a variadic parameter cannot be 'out'" + ); + return; + } + + printer.print_cpp2( + "...", + n.declaration->identifier->position() + ); + } + printer.print_cpp2( identifier, n.declaration->identifier->position()); } if ( @@ -5167,7 +5197,7 @@ class cppfront || n.is_object() || ( n.is_function() - && n.has_name() // only if it is not unnambed function aka lambda + && n.has_name() // only if it is not unnamed function aka lambda && n.initializer // only if the function has a definition (is not abstract) && printer.get_phase() == printer.phase2_func_defs ) diff --git a/source/parse.h b/source/parse.h index 9123c0596..914a7a9cd 100644 --- a/source/parse.h +++ b/source/parse.h @@ -55,7 +55,7 @@ auto is_prefix_operator(token const& tok) //G postfix-operator: -//G one of '++' '--' '*' '&' '~' '$' +//G one of '++' '--' '*' '&' '~' '$' '...' //G auto is_postfix_operator(lexeme l) -> bool @@ -67,6 +67,7 @@ auto is_postfix_operator(lexeme l) case lexeme::Ampersand: case lexeme::Tilde: case lexeme::Dollar: + case lexeme::Ellipsis: return true; break;default: return false; @@ -2346,11 +2347,11 @@ struct declaration_node { // The capture_group is declared first, because it should outlive // any owned postfix_expressions that could refer to it - capture_group captures; - - source_position pos; + capture_group captures; + source_position pos; + bool is_variadic = false; std::unique_ptr identifier; - accessibility access = accessibility::default_; + accessibility access = accessibility::default_; enum active : std::uint8_t { a_function, an_object, a_type, a_namespace, an_alias }; std::variant< @@ -6224,7 +6225,7 @@ class parser pos = start_pos; // backtrack } else { - error("expected , in parameter list", true, {}, true); + error("expected ',' in parameter list", true, {}, true); } return {}; } @@ -6496,15 +6497,17 @@ class parser bool is_parameter = false, bool is_template_parameter = false, std::unique_ptr id = {}, - accessibility access = {} + accessibility access = {}, + bool is_variadic = false ) -> std::unique_ptr { auto n = std::make_unique( current_declarations.back() ); n->pos = start; - n->identifier = std::move(id); - n->access = access; + n->identifier = std::move(id); + n->access = access; + n->is_variadic = is_variadic; // If we're in a type scope and the next token is ';', treat this as if // ': _;' without an initializer. @@ -7164,6 +7167,12 @@ class parser return {}; } + auto is_variadic = false; + if (curr().type() == lexeme::Ellipsis) { + is_variadic = true; + next(); + } + // Provide some useful Cpp1->Cpp2 migration diagnostics for common mistakes // if ( @@ -7232,6 +7241,14 @@ class parser return {}; } + if (is_variadic) { + errors.emplace_back( + curr().position(), + "an alias declaration may not be variadic" + ); + return {}; + } + n->pos = start_pos; n->identifier = std::move(id); n->access = access; @@ -7247,7 +7264,8 @@ class parser is_parameter, is_template_parameter, std::move(id), - access + access, + is_variadic ); if (!n) { pos = start_pos; // backtrack @@ -7539,6 +7557,7 @@ class parse_tree_printer : printing_visitor { o << pre(indent) << "declaration [" << &n << "]\n"; o << pre(indent+1) << "parent: [" << n.parent_declaration << "]\n"; + o << pre(indent+1) << "is_variadic: [" << std::boolalpha << n.is_variadic << "]\n"; switch (n.type.index()) { break;case declaration_node::a_function: o << pre(indent+1) << "function\n";