diff --git a/regression-tests/pure2-static-qualifier-error1.cpp2 b/regression-tests/pure2-static-qualifier-error1.cpp2 new file mode 100644 index 0000000000..0c59ccc28e --- /dev/null +++ b/regression-tests/pure2-static-qualifier-error1.cpp2 @@ -0,0 +1,2 @@ +// Nonsense +foo: (p : static int) -> void = {} diff --git a/regression-tests/pure2-static-qualifier-error2.cpp2 b/regression-tests/pure2-static-qualifier-error2.cpp2 new file mode 100644 index 0000000000..5889e3a764 --- /dev/null +++ b/regression-tests/pure2-static-qualifier-error2.cpp2 @@ -0,0 +1,2 @@ +// Nonsense +foo: () -> static int -> {}; diff --git a/regression-tests/pure2-static-qualifier-error3.cpp2 b/regression-tests/pure2-static-qualifier-error3.cpp2 new file mode 100644 index 0000000000..612bdee3dc --- /dev/null +++ b/regression-tests/pure2-static-qualifier-error3.cpp2 @@ -0,0 +1,11 @@ +main: () -> int = { + // Nonsense + x: std::variant = 42; + + std::cout << + inspect i -> std::string { + is int = "int"; + is bool = "bool"; + is _ = "unknown"; + } << std::endl; +} diff --git a/regression-tests/pure2-static-qualifier-error4.cpp2 b/regression-tests/pure2-static-qualifier-error4.cpp2 new file mode 100644 index 0000000000..4d6e8fdf38 --- /dev/null +++ b/regression-tests/pure2-static-qualifier-error4.cpp2 @@ -0,0 +1,11 @@ +main: () -> int = { + // Nonsense + x: static static std::variant = 42; + + std::cout << + inspect i -> std::string { + is int = "int"; + is static bool = "bool"; + is _ = "unknown"; + } << std::endl; +} diff --git a/regression-tests/pure2-static-qualifier-error5.cpp2 b/regression-tests/pure2-static-qualifier-error5.cpp2 new file mode 100644 index 0000000000..20f7e77481 --- /dev/null +++ b/regression-tests/pure2-static-qualifier-error5.cpp2 @@ -0,0 +1,11 @@ +main: () -> int = { + x: std::variant = 42; + + std::cout << + inspect i -> std::string { + is int = "int"; + // Nonsense + is static bool = "bool"; + is _ = "unknown"; + } << std::endl; +} diff --git a/regression-tests/pure2-static-var.cpp2 b/regression-tests/pure2-static-var.cpp2 new file mode 100644 index 0000000000..17acf866b0 --- /dev/null +++ b/regression-tests/pure2-static-var.cpp2 @@ -0,0 +1,9 @@ +green_bottles: () -> int = { + n: static _ = 10; + std::cout << n << std::endl; + return n--; +} + +main: () -> int = { + while green_bottles() >= 0 {} +} diff --git a/regression-tests/pure2-var-declaration.cpp2 b/regression-tests/pure2-var-declaration.cpp2 new file mode 100644 index 0000000000..89f5863754 --- /dev/null +++ b/regression-tests/pure2-var-declaration.cpp2 @@ -0,0 +1,41 @@ +main: () -> int = { + i1: = 42; + i1c: const _ = 42; + i1s: static _ = 42; + i2: int = 42; + i2s: static int = 42; + i2c: const int = 42; + i2sc: static const int = 42; + + + p1: * _ = i1&; + p1c: const* _ = i1&; + p1s: static* _ = i1s&; + p2: * const _ = i1&; + p2c: const* const _ = i1&; + p2s: static* const _ = i1s&; + p2cs: static const* const _ = i1s&; + p3: * int = i1&; + p3c: const * int = i1&; + p3s: static * int = i1s&; + p3sc: static const * int = i1s&; + p4: * const int = i1&; + p4s: static * const int = i1s&; + p5: const * int = i1&; + p5s: static const * int = i1s&; + p6: const * const * const int = p4&; + p6s: static const * const * const int = p5s&; + + + s1: = "Fred"; + s1c: const _ = "Fred"; + s1s: static _ = "Fred"; + s1sc: static const _ = "Fred"; + s2: std::string = "Fred"; + s2c: const std::string = "Fred"; + s2s: static std::string = "Fred"; + s2sc: static const std::string = "Fred"; + + + std::cout << s2sc << " is " << p6s** << std::endl; +} diff --git a/regression-tests/test-results/apple-clang-14/pure2-static-var.cpp.execution b/regression-tests/test-results/apple-clang-14/pure2-static-var.cpp.execution new file mode 100644 index 0000000000..30b148df54 --- /dev/null +++ b/regression-tests/test-results/apple-clang-14/pure2-static-var.cpp.execution @@ -0,0 +1,11 @@ +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 diff --git a/regression-tests/test-results/apple-clang-14/pure2-static-var.cpp.output b/regression-tests/test-results/apple-clang-14/pure2-static-var.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/apple-clang-14/pure2-var-declaration.cpp.execution b/regression-tests/test-results/apple-clang-14/pure2-var-declaration.cpp.execution new file mode 100644 index 0000000000..c1b3836c48 --- /dev/null +++ b/regression-tests/test-results/apple-clang-14/pure2-var-declaration.cpp.execution @@ -0,0 +1 @@ +Fred is 42 diff --git a/regression-tests/test-results/apple-clang-14/pure2-var-declaration.cpp.output b/regression-tests/test-results/apple-clang-14/pure2-var-declaration.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/clang-12/pure2-static-var.cpp.execution b/regression-tests/test-results/clang-12/pure2-static-var.cpp.execution new file mode 100644 index 0000000000..30b148df54 --- /dev/null +++ b/regression-tests/test-results/clang-12/pure2-static-var.cpp.execution @@ -0,0 +1,11 @@ +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 diff --git a/regression-tests/test-results/clang-12/pure2-static-var.cpp.output b/regression-tests/test-results/clang-12/pure2-static-var.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/clang-12/pure2-var-declaration.cpp.execution b/regression-tests/test-results/clang-12/pure2-var-declaration.cpp.execution new file mode 100644 index 0000000000..c1b3836c48 --- /dev/null +++ b/regression-tests/test-results/clang-12/pure2-var-declaration.cpp.execution @@ -0,0 +1 @@ +Fred is 42 diff --git a/regression-tests/test-results/clang-12/pure2-var-declaration.cpp.output b/regression-tests/test-results/clang-12/pure2-var-declaration.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/gcc-10/pure2-static-var.cpp.execution b/regression-tests/test-results/gcc-10/pure2-static-var.cpp.execution new file mode 100644 index 0000000000..30b148df54 --- /dev/null +++ b/regression-tests/test-results/gcc-10/pure2-static-var.cpp.execution @@ -0,0 +1,11 @@ +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 diff --git a/regression-tests/test-results/gcc-10/pure2-static-var.cpp.output b/regression-tests/test-results/gcc-10/pure2-static-var.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/gcc-10/pure2-var-declaration.cpp.execution b/regression-tests/test-results/gcc-10/pure2-var-declaration.cpp.execution new file mode 100644 index 0000000000..c1b3836c48 --- /dev/null +++ b/regression-tests/test-results/gcc-10/pure2-var-declaration.cpp.execution @@ -0,0 +1 @@ +Fred is 42 diff --git a/regression-tests/test-results/gcc-10/pure2-var-declaration.cpp.output b/regression-tests/test-results/gcc-10/pure2-var-declaration.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/msvc-2022/pure2-static-var.cpp.execution b/regression-tests/test-results/msvc-2022/pure2-static-var.cpp.execution new file mode 100644 index 0000000000..30b148df54 --- /dev/null +++ b/regression-tests/test-results/msvc-2022/pure2-static-var.cpp.execution @@ -0,0 +1,11 @@ +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 diff --git a/regression-tests/test-results/msvc-2022/pure2-static-var.cpp.output b/regression-tests/test-results/msvc-2022/pure2-static-var.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/msvc-2022/pure2-var-declaration.cpp.execution b/regression-tests/test-results/msvc-2022/pure2-var-declaration.cpp.execution new file mode 100644 index 0000000000..c1b3836c48 --- /dev/null +++ b/regression-tests/test-results/msvc-2022/pure2-var-declaration.cpp.execution @@ -0,0 +1 @@ +Fred is 42 diff --git a/regression-tests/test-results/msvc-2022/pure2-var-declaration.cpp.output b/regression-tests/test-results/msvc-2022/pure2-var-declaration.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/pure2-static-qualifier-error1.cpp2.output b/regression-tests/test-results/pure2-static-qualifier-error1.cpp2.output new file mode 100644 index 0000000000..5881a911b3 --- /dev/null +++ b/regression-tests/test-results/pure2-static-qualifier-error1.cpp2.output @@ -0,0 +1,8 @@ +pure2-static-qualifier-error1.cpp2... +pure2-static-qualifier-error1.cpp2(2,11): error: 'static' qualifier not allowed in this context (at 'static') +pure2-static-qualifier-error1.cpp2(2,11): error: a deduced type must have an = initializer (at 'static') +pure2-static-qualifier-error1.cpp2(2,7): error: invalid parameter list (at 'p') +pure2-static-qualifier-error1.cpp2(2,9): error: a deduced type must have an = initializer (at ':') +pure2-static-qualifier-error1.cpp2(2,1): error: unexpected text at end of Cpp2 code section (at 'foo') +pure2-static-qualifier-error1.cpp2(1,0): error: parse failed for section starting here + diff --git a/regression-tests/test-results/pure2-static-qualifier-error2.cpp2.output b/regression-tests/test-results/pure2-static-qualifier-error2.cpp2.output new file mode 100644 index 0000000000..5d12d15271 --- /dev/null +++ b/regression-tests/test-results/pure2-static-qualifier-error2.cpp2.output @@ -0,0 +1,8 @@ +pure2-static-qualifier-error2.cpp2... +pure2-static-qualifier-error2.cpp2(2,12): error: 'static' qualifier not allowed in this context (at 'static') +pure2-static-qualifier-error2.cpp2(2,12): error: missing function return after -> (at 'static') +pure2-static-qualifier-error2.cpp2(2,12): error: 'static' qualifier not allowed in this context (at 'static') +pure2-static-qualifier-error2.cpp2(2,12): error: a deduced type must have an = initializer (at 'static') +pure2-static-qualifier-error2.cpp2(2,1): error: unexpected text at end of Cpp2 code section (at 'foo') +pure2-static-qualifier-error2.cpp2(1,0): error: parse failed for section starting here + diff --git a/regression-tests/test-results/pure2-static-qualifier-error3.cpp2.output b/regression-tests/test-results/pure2-static-qualifier-error3.cpp2.output new file mode 100644 index 0000000000..cd71436739 --- /dev/null +++ b/regression-tests/test-results/pure2-static-qualifier-error3.cpp2.output @@ -0,0 +1,6 @@ +pure2-static-qualifier-error3.cpp2... +pure2-static-qualifier-error3.cpp2(3,20): error: missing semicolon at end of declaration (at '<') +pure2-static-qualifier-error3.cpp2(1,19): error: ill-formed initializer (at '{') +pure2-static-qualifier-error3.cpp2(1,1): error: unexpected text at end of Cpp2 code section (at 'main') +pure2-static-qualifier-error3.cpp2(1,0): error: parse failed for section starting here + diff --git a/regression-tests/test-results/pure2-static-qualifier-error4.cpp2.output b/regression-tests/test-results/pure2-static-qualifier-error4.cpp2.output new file mode 100644 index 0000000000..9be7e58385 --- /dev/null +++ b/regression-tests/test-results/pure2-static-qualifier-error4.cpp2.output @@ -0,0 +1,7 @@ +pure2-static-qualifier-error4.cpp2... +pure2-static-qualifier-error4.cpp2(3,15): error: more than one 'static' not allowed (at 'static') +pure2-static-qualifier-error4.cpp2(3,15): error: a deduced type must have an = initializer (at 'static') +pure2-static-qualifier-error4.cpp2(1,19): error: ill-formed initializer (at '{') +pure2-static-qualifier-error4.cpp2(1,1): error: unexpected text at end of Cpp2 code section (at 'main') +pure2-static-qualifier-error4.cpp2(1,0): error: parse failed for section starting here + diff --git a/regression-tests/test-results/pure2-static-qualifier-error5.cpp2.output b/regression-tests/test-results/pure2-static-qualifier-error5.cpp2.output new file mode 100644 index 0000000000..ecc26d98a3 --- /dev/null +++ b/regression-tests/test-results/pure2-static-qualifier-error5.cpp2.output @@ -0,0 +1,8 @@ +pure2-static-qualifier-error5.cpp2... +pure2-static-qualifier-error5.cpp2(8,16): error: 'static' qualifier not allowed in this context (at 'static') +pure2-static-qualifier-error5.cpp2(8,23): error: expected = at start of inspect alternative body (at 'bool') +pure2-static-qualifier-error5.cpp2(8,23): error: invalid alternative in inspect (at 'bool') +pure2-static-qualifier-error5.cpp2(1,19): error: ill-formed initializer (at '{') +pure2-static-qualifier-error5.cpp2(1,1): error: unexpected text at end of Cpp2 code section (at 'main') +pure2-static-qualifier-error5.cpp2(1,0): error: parse failed for section starting here + diff --git a/regression-tests/test-results/pure2-static-var.cpp b/regression-tests/test-results/pure2-static-var.cpp new file mode 100644 index 0000000000..c51d854bd3 --- /dev/null +++ b/regression-tests/test-results/pure2-static-var.cpp @@ -0,0 +1,23 @@ +// ----- Cpp2 support ----- +#define CPP2_USE_MODULES Yes +#include "cpp2util.h" + + +#line 1 "pure2-static-var.cpp2" +[[nodiscard]] auto green_bottles() -> int; +#line 7 "pure2-static-var.cpp2" +[[nodiscard]] auto main() -> int; + +//=== Cpp2 definitions ========================================================== + +#line 1 "pure2-static-var.cpp2" +[[nodiscard]] auto green_bottles() -> int{ + auto static n {10}; + std::cout << n << std::endl; + return --n; +} + +[[nodiscard]] auto main() -> int{ + while( green_bottles() >= 0 ) {} +} + diff --git a/regression-tests/test-results/pure2-static-var.cpp2.output b/regression-tests/test-results/pure2-static-var.cpp2.output new file mode 100644 index 0000000000..d05c285039 --- /dev/null +++ b/regression-tests/test-results/pure2-static-var.cpp2.output @@ -0,0 +1,2 @@ +pure2-static-var.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/regression-tests/test-results/pure2-var-declaration.cpp b/regression-tests/test-results/pure2-var-declaration.cpp new file mode 100644 index 0000000000..8132175dba --- /dev/null +++ b/regression-tests/test-results/pure2-var-declaration.cpp @@ -0,0 +1,53 @@ +// ----- Cpp2 support ----- +#define CPP2_USE_MODULES Yes +#include "cpp2util.h" + + +#line 1 "pure2-var-declaration.cpp2" +[[nodiscard]] auto main() -> int; + +//=== Cpp2 definitions ========================================================== + +#line 1 "pure2-var-declaration.cpp2" +[[nodiscard]] auto main() -> int{ + auto i1 {42}; + auto const i1c {42}; + auto static i1s {42}; + int i2 {42}; + int static i2s {42}; + int const i2c {42}; + int static const i2sc {42}; + + + auto* p1 {&i1}; + auto* const p1c {&i1}; + auto static* p1s {&i1s}; + auto const* p2 {&i1}; + auto const* const p2c {&i1}; + auto static const* p2s {&i1s}; + auto static const* const p2cs {&i1s}; + int * p3 {&i1}; + int * const p3c {&i1}; + int static* p3s {&i1s}; + int static* const p3sc {&i1s}; + int const* p4 {&i1}; + int static const* p4s {&i1s}; + int * const p5 {&i1}; + int static* const p5s {&i1s}; + int const* const* const p6 {&p4}; + int static const* const* const p6s {&p5s}; + + + auto s1 {"Fred"}; + auto const s1c {"Fred"}; + auto static s1s {"Fred"}; + auto static const s1sc {"Fred"}; + std::string s2 {"Fred"}; + std::string const s2c {"Fred"}; + std::string static s2s {"Fred"}; + std::string static const s2sc {"Fred"}; + + + std::cout << std::move(s2sc) << " is " << *cpp2::assert_not_null(*cpp2::assert_not_null(std::move(p6s))) << std::endl; +} + diff --git a/regression-tests/test-results/pure2-var-declaration.cpp2.output b/regression-tests/test-results/pure2-var-declaration.cpp2.output new file mode 100644 index 0000000000..e048efb87e --- /dev/null +++ b/regression-tests/test-results/pure2-var-declaration.cpp2.output @@ -0,0 +1,2 @@ +pure2-var-declaration.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 50ad1758e9..b232045cdd 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -1229,6 +1229,11 @@ class cppfront try_emit(n.id); } + if(n.is_static_qualified()) { + printer.print_extra(" "); + emit(*n.static_qualifier, false, pos); + } + for (auto i = n.pc_qualifiers.rbegin(); i != n.pc_qualifiers.rend(); ++i) { if ((**i) == "const") { printer.print_cpp2(" ", pos); } emit(**i, false, pos); diff --git a/source/parse.h b/source/parse.h index a5d3e1e99f..e4f092d99d 100644 --- a/source/parse.h +++ b/source/parse.h @@ -519,6 +519,7 @@ struct type_id_node { source_position pos; + token const* static_qualifier = {}; std::vector pc_qualifiers; enum active { empty=0, qualified, unqualified, keyword }; @@ -533,6 +534,10 @@ struct type_id_node return id.index() == type_id_node::empty || (get_token() && *get_token() == "_"); } + auto is_static_qualified() const -> bool { + return static_qualifier != nullptr; + } + auto is_pointer_qualified() const -> bool { for (auto q : pc_qualifiers) { if (q->type() == lexeme::Multiply) { @@ -575,6 +580,9 @@ struct type_id_node auto visit(auto& v, int depth) -> void { v.start(*this, depth); + if(static_qualifier != nullptr) { + v.start(*static_qualifier, depth+1); + } for (auto q : pc_qualifiers) { v.start(*q, depth+1); } @@ -1307,6 +1315,12 @@ struct translation_unit_node } }; +struct allow_static {}; +struct disallow_static {}; + +template +concept static_qualifier_policy = std::is_same_v || std::is_same_v; + //----------------------------------------------------------------------- // @@ -2091,10 +2105,12 @@ class parser return n; } - //G type-id: - //G type-qualifier-seq? qualified-id - //G type-qualifier-seq? unqualified-id + //G static-qualifier? type-qualifier-seq? qualified-id + //G static-qualifier? type-qualifier-seq? unqualified-id + //G + //G static-qualifier: + //G `static` //G //G type-qualifier-seq: //G type-qualifier @@ -2104,21 +2120,39 @@ class parser //G 'const' //G '*' //G + template auto type_id() -> std::unique_ptr { auto n = std::make_unique(); while ( - (curr().type() == lexeme::Keyword && curr() == "const") || - curr().type() == lexeme::Multiply + (curr().type() == lexeme::Keyword && (curr() == "const" || curr() == "static")) + || curr().type() == lexeme::Multiply ) { - if (curr() == "const" && !n->pc_qualifiers.empty() && *n->pc_qualifiers.back() == "const") { - error("consecutive 'const' not allowed"); - return {}; + if (curr() == "static") { + if constexpr (std::is_same_v) { + error("'static' qualifier not allowed in this context"); + return {}; + } else { + if(!n->pc_qualifiers.empty()) { + error("'static' qualifier has to be the first"); + return {}; + } else if (n->static_qualifier) { + error("more than one 'static' not allowed"); + return {}; + } + n->static_qualifier = &curr(); + next(); + } + } else { + if (curr() == "const" && !n->pc_qualifiers.empty() && *n->pc_qualifiers.back() == "const") { + error("consecutive 'const' not allowed"); + return {}; + } + n->pc_qualifiers.push_back( &curr() ); + next(); } - n->pc_qualifiers.push_back( &curr() ); - next(); } if (auto id = qualified_id()) { @@ -2132,8 +2166,8 @@ class parser assert (n->id.index() == type_id_node::unqualified); } else { - if (!n->pc_qualifiers.empty()) { - error("'*'/'const' type qualifiers must be followed by a type name or '_' wildcard"); + if (n->is_static_qualified() || !n->pc_qualifiers.empty()) { + error("static/'*'/'const' type qualifiers must be followed by a type name or '_' wildcard"); } return {}; } @@ -2859,7 +2893,7 @@ class parser return n; } - else if (auto s = declaration()) { + else if (auto s = declaration()) { n->statement = std::move(s); assert (n->statement.index() == statement_node::declaration); return n; @@ -3222,6 +3256,7 @@ class parser //G 'is' id-expression //G meta-constraints ',' id-expression //G + template auto unnamed_declaration(source_position start, bool semicolon_required = true, bool captures_allowed = false) -> std::unique_ptr { auto deduced_type = false; @@ -3257,7 +3292,7 @@ class parser } // Or just a type, declaring a non-pointer object - else if (auto t = type_id()) { + else if (auto t = type_id()) { if (auto id = t->get_token(); id && *id == "namespace") { error("(temporary alpha limitation) namespaces are not yet supported", false); return {}; @@ -3372,6 +3407,7 @@ class parser //G declaration: //G identifier unnamed-declaration //G + template auto declaration(bool semicolon_required = true) -> std::unique_ptr { if (done()) { return {}; } @@ -3384,7 +3420,7 @@ class parser return {}; } - auto n = unnamed_declaration(start_pos, semicolon_required); + auto n = unnamed_declaration(start_pos, semicolon_required); if (!n) { pos = start_pos; // backtrack return {};