diff --git a/releasenotes.md b/releasenotes.md index d76dd2cb4..d9f5d7833 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -5,6 +5,7 @@ ### Changes / improvements - Const vector -> const slice implicit conversion. - Slicing arrays, slices and bytes at compile time #1466. +- Better error for `int a[4] = ...`. #1518 ### Fixes - `Unsupported int[*] $x = { 1, 2, 3, 4 }` #1489. diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 0d3e3e52a..593e45e71 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -1158,11 +1158,21 @@ static inline Decl *parse_global_declaration(ParseContext *c) } if (!parse_decl_initializer(c, decl)) return poisoned_decl; } - else if (!decl->attributes && tok_is(c, TOKEN_LPAREN) && !threadlocal) + else if (!decl->attributes) { - // Guess we forgot `fn`? -> improve error reporting. - print_error_at(type->span, "This looks like the beginning of a function declaration but it's missing the initial `fn`. Did you forget it?"); - return poisoned_decl; + if (tok_is(c, TOKEN_LPAREN) && !threadlocal) + { + // Guess we forgot `fn`? -> improve error reporting. + print_error_at(type->span, "This looks like the beginning of a function declaration but it's missing the initial `fn`. Did you forget it?"); + return poisoned_decl; + } + else if (tok_is(c, TOKEN_LBRACKET)) + { + // Maybe we were doing int foo[4] = ... + PRINT_ERROR_HERE("This looks like a declaration of the format 'int foo[4]' " + "which is c-style array declaration. In C3, you need to use something like 'int[4] foo' instead."); + return poisoned_decl; + } } CONSUME_EOS_OR_RET(poisoned_decl); Attr **attributes = decl->attributes; diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 60ba8c505..de50bb60f 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -16,13 +16,32 @@ static Ast *parse_decl_stmt_after_type(ParseContext *c, TypeInfo *type) ast->ast_kind = AST_DECLARE_STMT; ASSIGN_DECL_OR_RET(ast->declare_stmt, parse_local_decl_after_type(c, type), poisoned_ast); Decl *decl = ast->declare_stmt; - if (tok_is(c, TOKEN_LBRACE) && decl->var.init_expr && decl->var.init_expr->expr_kind == EXPR_IDENTIFIER) + switch (c->tok) { - print_error_at(decl->var.init_expr->span, "An identifier would not usually be followed by a '{'. Did you intend write the name of a type here?"); - return poisoned_ast; + case TOKEN_LBRACE: + if (decl->var.init_expr && decl->var.init_expr->expr_kind == EXPR_IDENTIFIER) + { + print_error_at(decl->var.init_expr->span, + "An identifier would not usually be followed by a '{'. Did you intend write the name of a type here?"); + return poisoned_ast; + } + break; + case TOKEN_LBRACKET: + if (!decl->var.init_expr) + { + SourceSpan span = extend_span_with_token(type->span, c->span); + print_error_at(span, "This looks like the beginning of a declaration with the format 'int %s[4]' " + "which is a c-style array declaration. In C3, you need to use something like 'int[4] %s' instead.", + decl->name, decl->name); + return poisoned_ast; + } + break; + case TOKEN_EOS: + return ast; + default: + break; } - if (tok_is(c, TOKEN_EOS)) return ast; if (decl->attributes || decl->var.init_expr) { if (tok_is(c, TOKEN_COMMA) && peek(c) == TOKEN_IDENT) diff --git a/test/unit/stdlib/crypto/rc4.c3 b/test/unit/stdlib/crypto/rc4.c3 index 91a619960..29a482ee5 100644 --- a/test/unit/stdlib/crypto/rc4.c3 +++ b/test/unit/stdlib/crypto/rc4.c3 @@ -8,9 +8,9 @@ fn void! rc_crypt() @test char[200] x; String text = "The quick brown fox jumps over the lazy dog."; rc.crypt(text, &x); - char[*] res = x"2ac2fecdd8fbb84638e3a4 + char[*] res = x`2ac2fecdd8fbb84638e3a4 820eb205cc8e29c28b9d5d 6b2ef974f311964971c90e - 8b9ca16467ef2dc6fc3520"; + 8b9ca16467ef2dc6fc3520`; assert(res[:text.len] == x[:text.len]); } \ No newline at end of file