diff --git a/regression-tests/pure2-bugfix-for-empty-index.cpp2 b/regression-tests/pure2-bugfix-for-empty-index.cpp2 new file mode 100644 index 0000000000..3b6a4fcf8f --- /dev/null +++ b/regression-tests/pure2-bugfix-for-empty-index.cpp2 @@ -0,0 +1,10 @@ +t: type = { + operator[]: (inout this) -> i32 = 1; + operator[]: (inout this, x: _) -> i32 = 2; + operator[]: (inout this, x: _, y: _) -> i32 = 3; +} +main: () = { + [[assert: t()[] == 1]] + [[assert: t()[1] == 2]] + [[assert: t()[1, 2] == 3]] +} diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-empty-index.cpp.execution b/regression-tests/test-results/gcc-13/pure2-bugfix-for-empty-index.cpp.execution new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-empty-index.cpp.output b/regression-tests/test-results/gcc-13/pure2-bugfix-for-empty-index.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/pure2-bugfix-for-empty-index.cpp b/regression-tests/test-results/pure2-bugfix-for-empty-index.cpp new file mode 100644 index 0000000000..d4dc12abca --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-empty-index.cpp @@ -0,0 +1,42 @@ + +#define CPP2_USE_MODULES Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + +#line 1 "pure2-bugfix-for-empty-index.cpp2" +class t; + + +//=== Cpp2 type definitions and function declarations =========================== + +#line 1 "pure2-bugfix-for-empty-index.cpp2" +class t { + public: [[nodiscard]] auto operator[]() -> cpp2::i32; + public: [[nodiscard]] auto operator[](auto const& x) -> cpp2::i32; + public: [[nodiscard]] auto operator[](auto const& x, auto const& y) -> cpp2::i32; + + public: t() = default; + public: t(t const&) = delete; /* No 'that' constructor, suppress copy */ + public: auto operator=(t const&) -> void = delete; +#line 5 "pure2-bugfix-for-empty-index.cpp2" +}; +auto main() -> int; + + +//=== Cpp2 function definitions ================================================= + + +#line 2 "pure2-bugfix-for-empty-index.cpp2" + [[nodiscard]] auto t::operator[]() -> cpp2::i32 { return 1; } + [[nodiscard]] auto t::operator[](auto const& x) -> cpp2::i32 { return 2; } + [[nodiscard]] auto t::operator[](auto const& x, auto const& y) -> cpp2::i32 { return 3; } + +auto main() -> int{ + cpp2::Default.expects(t()[]==1, ""); + cpp2::Default.expects(cpp2::assert_in_bounds(t(), 1)==2, ""); + cpp2::Default.expects(t()[1, 2]==3, ""); +} + diff --git a/regression-tests/test-results/pure2-bugfix-for-empty-index.cpp2.output b/regression-tests/test-results/pure2-bugfix-for-empty-index.cpp2.output new file mode 100644 index 0000000000..b8cee96ab5 --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-empty-index.cpp2.output @@ -0,0 +1,2 @@ +pure2-bugfix-for-empty-index.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 1bad85a53f..0c12673e5d 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -3029,6 +3029,7 @@ class cppfront if ( flag_safe_subscripts && i->op->type() == lexeme::LeftBracket + && std::ssize(i->expr_list->expressions) == 1 ) { suffix.emplace_back( ")", i->op->position() ); @@ -3065,6 +3066,7 @@ class cppfront if ( flag_safe_subscripts && i->op->type() == lexeme::LeftBracket + && std::ssize(i->expr_list->expressions) == 1 ) { prefix.emplace_back( "cpp2::assert_in_bounds(", i->op->position() ); diff --git a/source/parse.h b/source/parse.h index 3a4e1ae3b1..66a730de71 100644 --- a/source/parse.h +++ b/source/parse.h @@ -4084,7 +4084,7 @@ class parser //G postfix-expression: //G primary-expression //G postfix-expression postfix-operator [Note: without whitespace before the operator] - //G postfix-expression '[' expression-list ']' + //G postfix-expression '[' expression-list? ']' //G postfix-expression '(' expression-list? ')' //G postfix-expression '.' id-expression //G @@ -4161,13 +4161,9 @@ class parser if (term.op->type() == lexeme::LeftBracket) { term.expr_list = expression_list(term.op); - if ( - !term.expr_list - || term.expr_list->expressions.empty() - ) + if (!term.expr_list) { - error("subscript expression [ ] must not be empty (if you were trying to name a C-style array type, use 'std::array' instead)"); - next(); + error("[ is not followed by a valid expression list"); return {}; } if (curr().type() != lexeme::RightBracket)