From 082457c5fb85cf9ad2b04fe37a770ff98fea4147 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 17 May 2025 22:10:03 +0200 Subject: [PATCH] Incorrect parsing of call attributes #2144. --- releasenotes.md | 1 + src/compiler/parse_expr.c | 26 ++++++++++++------- .../attributes/call_attribute_parse.c3 | 11 ++++++++ 3 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 test/test_suite/attributes/call_attribute_parse.c3 diff --git a/releasenotes.md b/releasenotes.md index c41b50c67..52fdaa630 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -30,6 +30,7 @@ - Using a non-const as the end range for a bitstruct would trigger an assert. - Incorrect parsing of ad hoc generic types, like `Foo{int}****` #2140. - $define did not correctly handle generic types #2140. +- Incorrect parsing of call attributes #2144. ### Stdlib changes - Added `String.quick_ztr` and `String.is_zstr` diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index da1dcdba9..c19f004d4 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -982,21 +982,19 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left) PRINT_ERROR_HERE("Expected a macro body here."); return poisoned_expr; } - Attr *attr; int force_inline = -1; - while (1) + while (tok_is(c, TOKEN_AT_IDENT)) { - if (!parse_attribute(c, &attr, true)) return poisoned_expr; - if (!attr) break; - - AttributeType attr_type = attribute_by_name(attr->name); + AttributeType attr_type = attribute_by_name(symstr(c)); + advance(c); int new_inline = attr_type == ATTRIBUTE_INLINE; switch (attr_type) { case ATTRIBUTE_PURE: if (call->call_expr.attr_pure) { - RETURN_PRINT_ERROR_AT(poisoned_expr, attr, "Repeat of the same attribute is not allowed."); + PRINT_ERROR_LAST("Repeat of the same attribute is not allowed."); + return poisoned_expr; } call->call_expr.attr_pure = true; continue; @@ -1004,18 +1002,26 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left) case ATTRIBUTE_NOINLINE: if (force_inline == new_inline) { - RETURN_PRINT_ERROR_AT(poisoned_expr, attr, "Repeat of the same attribute is not allowed."); + PRINT_ERROR_LAST("Repeat of the same attribute is not allowed."); + return poisoned_expr; } if (force_inline != -1) { - RETURN_PRINT_ERROR_AT(poisoned_expr, attr, "@inline and @noinline cannot be combined"); + PRINT_ERROR_LAST("@inline and @noinline cannot be combined"); + return poisoned_expr; } force_inline = new_inline; continue; default: - RETURN_PRINT_ERROR_AT(poisoned_expr, attr, "Only '@pure', '@inline' and '@noinline' are valid attributes for calls."); + PRINT_ERROR_LAST("Only '@pure', '@inline' and '@noinline' are valid attributes for calls."); + return poisoned_expr; } } + if (tok_is(c, TOKEN_AT_TYPE_IDENT)) + { + PRINT_ERROR_HERE("User defined attributes are not allowed, only @pure, @inline and @noinline."); + return poisoned_expr; + } if (force_inline != -1) { call->call_expr.attr_force_inline = force_inline == 1; diff --git a/test/test_suite/attributes/call_attribute_parse.c3 b/test/test_suite/attributes/call_attribute_parse.c3 new file mode 100644 index 000000000..94c74f2c5 --- /dev/null +++ b/test/test_suite/attributes/call_attribute_parse.c3 @@ -0,0 +1,11 @@ +module test; +fn VoidFn foo() +{ + return fn void() {}; +} + +fn void main() +{ + foo() @inline (); + foo() @inline (foo()); // #error: This argument would exceed the number of parameters +}