| author | |
| committer | |
| log | f30aa25cbf9c9a415963b4ea69d7efa09237a704 |
| tree | f0150470b35bb7b55450c54dbb4553e3cc11b29f |
| parent | cfae70ec8e736af3fcd465c78bd80e160968eea8 |
* stage2 AstGen: add missing compile error for declaring a local
that shadows a primitive. Even with `@""` syntax, it may not have
the same name as a primitive.
* stage2 AstGen: add a compile error for a global declaration
whose name matches a primitive. However it is allowed when using
`@""` syntax.
* stage1: delete all "declaration shadows primitive" compile errors
because they are now handled by stage2 AstGen.
* stage1/stage2 AstGen: notice when using `@""` syntax and:
- treat `_` as a regular identifier
- skip checking if an identifire is a primitive
Check the new test cases for clarifications on semantics.
closes #60628 files changed, 157 insertions(+), 86 deletions(-)
src/AstGen.zig+67-33| ... | @@ -2891,7 +2891,7 @@ fn fnDecl( | ... | @@ -2891,7 +2891,7 @@ fn fnDecl( |
| 2891 | }; | 2891 | }; |
| 2892 | const fn_name_str_index = try astgen.identAsString(fn_name_token); | 2892 | const fn_name_str_index = try astgen.identAsString(fn_name_token); |
| 2893 | 2893 | ||
| 2894 | try astgen.declareNewName(scope, fn_name_str_index, decl_node); | 2894 | try astgen.declareNewName(scope, fn_name_str_index, decl_node, fn_name_token); |
| 2895 | 2895 | ||
| 2896 | // We insert this at the beginning so that its instruction index marks the | 2896 | // We insert this at the beginning so that its instruction index marks the |
| 2897 | // start of the top level declaration. | 2897 | // start of the top level declaration. |
| ... | @@ -3160,7 +3160,7 @@ fn globalVarDecl( | ... | @@ -3160,7 +3160,7 @@ fn globalVarDecl( |
| 3160 | const name_token = var_decl.ast.mut_token + 1; | 3160 | const name_token = var_decl.ast.mut_token + 1; |
| 3161 | const name_str_index = try astgen.identAsString(name_token); | 3161 | const name_str_index = try astgen.identAsString(name_token); |
| 3162 | 3162 | ||
| 3163 | try astgen.declareNewName(scope, name_str_index, node); | 3163 | try astgen.declareNewName(scope, name_str_index, node, name_token); |
| 3164 | 3164 | ||
| 3165 | var block_scope: GenZir = .{ | 3165 | var block_scope: GenZir = .{ |
| 3166 | .parent = scope, | 3166 | .parent = scope, |
| ... | @@ -6319,34 +6319,36 @@ fn identifier( | ... | @@ -6319,34 +6319,36 @@ fn identifier( |
| 6319 | } | 6319 | } |
| 6320 | const ident_name = try astgen.identifierTokenString(ident_token); | 6320 | const ident_name = try astgen.identifierTokenString(ident_token); |
| 6321 | 6321 | ||
| 6322 | if (simple_types.get(ident_name)) |zir_const_ref| { | 6322 | if (ident_name_raw[0] != '@') { |
| 6323 | return rvalue(gz, rl, zir_const_ref, ident); | 6323 | if (simple_types.get(ident_name)) |zir_const_ref| { |
| 6324 | } | 6324 | return rvalue(gz, rl, zir_const_ref, ident); |
| 6325 | } | ||
| 6325 | 6326 | ||
| 6326 | if (ident_name.len >= 2) integer: { | 6327 | if (ident_name.len >= 2) integer: { |
| 6327 | const first_c = ident_name[0]; | 6328 | const first_c = ident_name[0]; |
| 6328 | if (first_c == 'i' or first_c == 'u') { | 6329 | if (first_c == 'i' or first_c == 'u') { |
| 6329 | const signedness: std.builtin.Signedness = switch (first_c == 'i') { | 6330 | const signedness: std.builtin.Signedness = switch (first_c == 'i') { |
| 6330 | true => .signed, | 6331 | true => .signed, |
| 6331 | false => .unsigned, | 6332 | false => .unsigned, |
| 6332 | }; | 6333 | }; |
| 6333 | const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) { | 6334 | const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) { |
| 6334 | error.Overflow => return astgen.failNode( | 6335 | error.Overflow => return astgen.failNode( |
| 6335 | ident, | 6336 | ident, |
| 6336 | "primitive integer type '{s}' exceeds maximum bit width of 65535", | 6337 | "primitive integer type '{s}' exceeds maximum bit width of 65535", |
| 6337 | .{ident_name}, | 6338 | .{ident_name}, |
| 6338 | ), | 6339 | ), |
| 6339 | error.InvalidCharacter => break :integer, | 6340 | error.InvalidCharacter => break :integer, |
| 6340 | }; | 6341 | }; |
| 6341 | const result = try gz.add(.{ | 6342 | const result = try gz.add(.{ |
| 6342 | .tag = .int_type, | 6343 | .tag = .int_type, |
| 6343 | .data = .{ .int_type = .{ | 6344 | .data = .{ .int_type = .{ |
| 6344 | .src_node = gz.nodeIndexToRelative(ident), | 6345 | .src_node = gz.nodeIndexToRelative(ident), |
| 6345 | .signedness = signedness, | 6346 | .signedness = signedness, |
| 6346 | .bit_count = bit_count, | 6347 | .bit_count = bit_count, |
| 6347 | } }, | 6348 | } }, |
| 6348 | }); | 6349 | }); |
| 6349 | return rvalue(gz, rl, result, ident); | 6350 | return rvalue(gz, rl, result, ident); |
| 6351 | } | ||
| 6350 | } | 6352 | } |
| 6351 | } | 6353 | } |
| 6352 | 6354 | ||
| ... | @@ -10031,8 +10033,21 @@ fn declareNewName( | ... | @@ -10031,8 +10033,21 @@ fn declareNewName( |
| 10031 | start_scope: *Scope, | 10033 | start_scope: *Scope, |
| 10032 | name_index: u32, | 10034 | name_index: u32, |
| 10033 | node: ast.Node.Index, | 10035 | node: ast.Node.Index, |
| 10036 | name_token: ast.TokenIndex, | ||
| 10034 | ) !void { | 10037 | ) !void { |
| 10035 | const gpa = astgen.gpa; | 10038 | const gpa = astgen.gpa; |
| 10039 | |||
| 10040 | const token_bytes = astgen.tree.tokenSlice(name_token); | ||
| 10041 | if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { | ||
| 10042 | return astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ | ||
| 10043 | token_bytes, | ||
| 10044 | }, &[_]u32{ | ||
| 10045 | try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ | ||
| 10046 | token_bytes, | ||
| 10047 | }), | ||
| 10048 | }); | ||
| 10049 | } | ||
| 10050 | |||
| 10036 | var scope = start_scope; | 10051 | var scope = start_scope; |
| 10037 | while (true) { | 10052 | while (true) { |
| 10038 | switch (scope.tag) { | 10053 | switch (scope.tag) { |
| ... | @@ -10060,7 +10075,20 @@ fn declareNewName( | ... | @@ -10060,7 +10075,20 @@ fn declareNewName( |
| 10060 | } | 10075 | } |
| 10061 | } | 10076 | } |
| 10062 | 10077 | ||
| 10063 | /// Local variables shadowing detection, including function parameters. | 10078 | fn isPrimitive(name: []const u8) bool { |
| 10079 | if (simple_types.get(name) != null) return true; | ||
| 10080 | if (name.len < 2) return false; | ||
| 10081 | const first_c = name[0]; | ||
| 10082 | if (first_c != 'i' and first_c != 'u') return false; | ||
| 10083 | if (std.fmt.parseInt(u16, name[1..], 10)) |_| { | ||
| 10084 | return true; | ||
| 10085 | } else |err| switch (err) { | ||
| 10086 | error.Overflow => return true, | ||
| 10087 | error.InvalidCharacter => return false, | ||
| 10088 | } | ||
| 10089 | } | ||
| 10090 | |||
| 10091 | /// Local variables shadowing detection, including function parameters and primitives. | ||
| 10064 | fn detectLocalShadowing( | 10092 | fn detectLocalShadowing( |
| 10065 | astgen: *AstGen, | 10093 | astgen: *AstGen, |
| 10066 | scope: *Scope, | 10094 | scope: *Scope, |
| ... | @@ -10068,13 +10096,19 @@ fn detectLocalShadowing( | ... | @@ -10068,13 +10096,19 @@ fn detectLocalShadowing( |
| 10068 | name_token: ast.TokenIndex, | 10096 | name_token: ast.TokenIndex, |
| 10069 | ) !void { | 10097 | ) !void { |
| 10070 | const gpa = astgen.gpa; | 10098 | const gpa = astgen.gpa; |
| 10099 | const name_slice = mem.spanZ(astgen.nullTerminatedString(ident_name)); | ||
| 10100 | if (isPrimitive(name_slice)) { | ||
| 10101 | const name = try gpa.dupe(u8, name_slice); | ||
| 10102 | defer gpa.free(name); | ||
| 10103 | return astgen.failTok(name_token, "local shadows primitive '{s}'", .{name}); | ||
| 10104 | } | ||
| 10071 | 10105 | ||
| 10072 | var s = scope; | 10106 | var s = scope; |
| 10073 | while (true) switch (s.tag) { | 10107 | while (true) switch (s.tag) { |
| 10074 | .local_val => { | 10108 | .local_val => { |
| 10075 | const local_val = s.cast(Scope.LocalVal).?; | 10109 | const local_val = s.cast(Scope.LocalVal).?; |
| 10076 | if (local_val.name == ident_name) { | 10110 | if (local_val.name == ident_name) { |
| 10077 | const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name))); | 10111 | const name = try gpa.dupe(u8, name_slice); |
| 10078 | defer gpa.free(name); | 10112 | defer gpa.free(name); |
| 10079 | return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ | 10113 | return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ |
| 10080 | @tagName(local_val.id_cat), name, | 10114 | @tagName(local_val.id_cat), name, |
| ... | @@ -10091,7 +10125,7 @@ fn detectLocalShadowing( | ... | @@ -10091,7 +10125,7 @@ fn detectLocalShadowing( |
| 10091 | .local_ptr => { | 10125 | .local_ptr => { |
| 10092 | const local_ptr = s.cast(Scope.LocalPtr).?; | 10126 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 10093 | if (local_ptr.name == ident_name) { | 10127 | if (local_ptr.name == ident_name) { |
| 10094 | const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name))); | 10128 | const name = try gpa.dupe(u8, name_slice); |
| 10095 | defer gpa.free(name); | 10129 | defer gpa.free(name); |
| 10096 | return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ | 10130 | return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ |
| 10097 | @tagName(local_ptr.id_cat), name, | 10131 | @tagName(local_ptr.id_cat), name, |
| ... | @@ -10111,7 +10145,7 @@ fn detectLocalShadowing( | ... | @@ -10111,7 +10145,7 @@ fn detectLocalShadowing( |
| 10111 | s = ns.parent; | 10145 | s = ns.parent; |
| 10112 | continue; | 10146 | continue; |
| 10113 | }; | 10147 | }; |
| 10114 | const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name))); | 10148 | const name = try gpa.dupe(u8, name_slice); |
| 10115 | defer gpa.free(name); | 10149 | defer gpa.free(name); |
| 10116 | return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{ | 10150 | return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{ |
| 10117 | name, | 10151 | name, |
src/stage1/all_types.hpp+1| ... | @@ -1125,6 +1125,7 @@ struct AstNodeContainerInitExpr { | ... | @@ -1125,6 +1125,7 @@ struct AstNodeContainerInitExpr { |
| 1125 | 1125 | ||
| 1126 | struct AstNodeIdentifier { | 1126 | struct AstNodeIdentifier { |
| 1127 | Buf *name; | 1127 | Buf *name; |
| 1128 | bool is_at_syntax; | ||
| 1128 | }; | 1129 | }; |
| 1129 | 1130 | ||
| 1130 | struct AstNodeEnumLiteral { | 1131 | struct AstNodeEnumLiteral { |
src/stage1/analyze.cpp-13| ... | @@ -3918,12 +3918,6 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { | ... | @@ -3918,12 +3918,6 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { |
| 3918 | add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition here")); | 3918 | add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition here")); |
| 3919 | return; | 3919 | return; |
| 3920 | } | 3920 | } |
| 3921 | |||
| 3922 | ZigType *type; | ||
| 3923 | if (get_primitive_type(g, tld->name, &type) != ErrorPrimitiveTypeNotFound) { | ||
| 3924 | add_node_error(g, tld->source_node, | ||
| 3925 | buf_sprintf("declaration shadows primitive type '%s'", buf_ptr(tld->name))); | ||
| 3926 | } | ||
| 3927 | } | 3921 | } |
| 3928 | } | 3922 | } |
| 3929 | 3923 | ||
| ... | @@ -4170,13 +4164,6 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf | ... | @@ -4170,13 +4164,6 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf |
| 4170 | variable_entry->var_type = g->builtin_types.entry_invalid; | 4164 | variable_entry->var_type = g->builtin_types.entry_invalid; |
| 4171 | } else { | 4165 | } else { |
| 4172 | variable_entry->align_bytes = get_abi_alignment(g, var_type); | 4166 | variable_entry->align_bytes = get_abi_alignment(g, var_type); |
| 4173 | |||
| 4174 | ZigType *type; | ||
| 4175 | if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) { | ||
| 4176 | add_node_error(g, source_node, | ||
| 4177 | buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); | ||
| 4178 | variable_entry->var_type = g->builtin_types.entry_invalid; | ||
| 4179 | } | ||
| 4180 | } | 4167 | } |
| 4181 | 4168 | ||
| 4182 | Scope *child_scope; | 4169 | Scope *child_scope; |
src/stage1/astgen.cpp+29-33| ... | @@ -3194,13 +3194,6 @@ ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, | ... | @@ -3194,13 +3194,6 @@ ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, |
| 3194 | add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration here")); | 3194 | add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration here")); |
| 3195 | } | 3195 | } |
| 3196 | variable_entry->var_type = codegen->builtin_types.entry_invalid; | 3196 | variable_entry->var_type = codegen->builtin_types.entry_invalid; |
| 3197 | } else { | ||
| 3198 | ZigType *type; | ||
| 3199 | if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) { | ||
| 3200 | add_node_error(codegen, node, | ||
| 3201 | buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); | ||
| 3202 | variable_entry->var_type = codegen->builtin_types.entry_invalid; | ||
| 3203 | } | ||
| 3204 | } | 3197 | } |
| 3205 | } | 3198 | } |
| 3206 | } else { | 3199 | } else { |
| ... | @@ -3815,35 +3808,38 @@ static Stage1ZirInst *astgen_identifier(Stage1AstGen *ag, Scope *scope, AstNode | ... | @@ -3815,35 +3808,38 @@ static Stage1ZirInst *astgen_identifier(Stage1AstGen *ag, Scope *scope, AstNode |
| 3815 | Error err; | 3808 | Error err; |
| 3816 | assert(node->type == NodeTypeIdentifier); | 3809 | assert(node->type == NodeTypeIdentifier); |
| 3817 | 3810 | ||
| 3818 | Buf *variable_name = node_identifier_buf(node); | 3811 | bool is_at_syntax; |
| 3819 | 3812 | Buf *variable_name = node_identifier_buf2(node, &is_at_syntax); | |
| 3820 | if (buf_eql_str(variable_name, "_")) { | 3813 | |
| 3821 | if (lval == LValAssign) { | 3814 | if (!is_at_syntax) { |
| 3822 | Stage1ZirInstConst *const_instruction = ir_build_instruction<Stage1ZirInstConst>(ag, scope, node); | 3815 | if (buf_eql_str(variable_name, "_")) { |
| 3823 | const_instruction->value = ag->codegen->pass1_arena->create<ZigValue>(); | 3816 | if (lval == LValAssign) { |
| 3824 | const_instruction->value->type = get_pointer_to_type(ag->codegen, | 3817 | Stage1ZirInstConst *const_instruction = ir_build_instruction<Stage1ZirInstConst>(ag, scope, node); |
| 3825 | ag->codegen->builtin_types.entry_void, false); | 3818 | const_instruction->value = ag->codegen->pass1_arena->create<ZigValue>(); |
| 3826 | const_instruction->value->special = ConstValSpecialStatic; | 3819 | const_instruction->value->type = get_pointer_to_type(ag->codegen, |
| 3827 | const_instruction->value->data.x_ptr.special = ConstPtrSpecialDiscard; | 3820 | ag->codegen->builtin_types.entry_void, false); |
| 3828 | return &const_instruction->base; | 3821 | const_instruction->value->special = ConstValSpecialStatic; |
| 3822 | const_instruction->value->data.x_ptr.special = ConstPtrSpecialDiscard; | ||
| 3823 | return &const_instruction->base; | ||
| 3824 | } | ||
| 3829 | } | 3825 | } |
| 3830 | } | ||
| 3831 | 3826 | ||
| 3832 | ZigType *primitive_type; | 3827 | ZigType *primitive_type; |
| 3833 | if ((err = get_primitive_type(ag->codegen, variable_name, &primitive_type))) { | 3828 | if ((err = get_primitive_type(ag->codegen, variable_name, &primitive_type))) { |
| 3834 | if (err == ErrorOverflow) { | 3829 | if (err == ErrorOverflow) { |
| 3835 | add_node_error(ag->codegen, node, | 3830 | add_node_error(ag->codegen, node, |
| 3836 | buf_sprintf("primitive integer type '%s' exceeds maximum bit width of 65535", | 3831 | buf_sprintf("primitive integer type '%s' exceeds maximum bit width of 65535", |
| 3837 | buf_ptr(variable_name))); | 3832 | buf_ptr(variable_name))); |
| 3838 | return ag->codegen->invalid_inst_src; | 3833 | return ag->codegen->invalid_inst_src; |
| 3839 | } | 3834 | } |
| 3840 | assert(err == ErrorPrimitiveTypeNotFound); | 3835 | assert(err == ErrorPrimitiveTypeNotFound); |
| 3841 | } else { | ||
| 3842 | Stage1ZirInst *value = ir_build_const_type(ag, scope, node, primitive_type); | ||
| 3843 | if (lval == LValPtr || lval == LValAssign) { | ||
| 3844 | return ir_build_ref_src(ag, scope, node, value); | ||
| 3845 | } else { | 3836 | } else { |
| 3846 | return ir_expr_wrap(ag, scope, value, result_loc); | 3837 | Stage1ZirInst *value = ir_build_const_type(ag, scope, node, primitive_type); |
| 3838 | if (lval == LValPtr || lval == LValAssign) { | ||
| 3839 | return ir_build_ref_src(ag, scope, node, value); | ||
| 3840 | } else { | ||
| 3841 | return ir_expr_wrap(ag, scope, value, result_loc); | ||
| 3842 | } | ||
| 3847 | } | 3843 | } |
| 3848 | } | 3844 | } |
| 3849 | 3845 |
src/stage1/parser.cpp+16-3| ... | @@ -3482,8 +3482,7 @@ Error source_char_literal(const char *source, uint32_t *result, size_t *bad_inde | ... | @@ -3482,8 +3482,7 @@ Error source_char_literal(const char *source, uint32_t *result, size_t *bad_inde |
| 3482 | } | 3482 | } |
| 3483 | } | 3483 | } |
| 3484 | 3484 | ||
| 3485 | 3485 | static Buf *token_identifier_buf2(RootStruct *root_struct, TokenIndex token, bool *is_at_syntax) { | |
| 3486 | Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { | ||
| 3487 | Error err; | 3486 | Error err; |
| 3488 | const char *source = buf_ptr(root_struct->source_code); | 3487 | const char *source = buf_ptr(root_struct->source_code); |
| 3489 | size_t byte_offset = root_struct->token_locs[token].offset; | 3488 | size_t byte_offset = root_struct->token_locs[token].offset; |
| ... | @@ -3495,6 +3494,7 @@ Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { | ... | @@ -3495,6 +3494,7 @@ Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { |
| 3495 | assert(source[byte_offset] != '.'); // wrong token index | 3494 | assert(source[byte_offset] != '.'); // wrong token index |
| 3496 | 3495 | ||
| 3497 | if (source[byte_offset] == '@') { | 3496 | if (source[byte_offset] == '@') { |
| 3497 | *is_at_syntax = true; | ||
| 3498 | size_t bad_index; | 3498 | size_t bad_index; |
| 3499 | Buf *str = buf_alloc(); | 3499 | Buf *str = buf_alloc(); |
| 3500 | if ((err = source_string_literal_buf(source + byte_offset + 1, str, &bad_index))) { | 3500 | if ((err = source_string_literal_buf(source + byte_offset + 1, str, &bad_index))) { |
| ... | @@ -3503,6 +3503,7 @@ Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { | ... | @@ -3503,6 +3503,7 @@ Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { |
| 3503 | } | 3503 | } |
| 3504 | return str; | 3504 | return str; |
| 3505 | } else { | 3505 | } else { |
| 3506 | *is_at_syntax = false; | ||
| 3506 | size_t start = byte_offset; | 3507 | size_t start = byte_offset; |
| 3507 | for (;; byte_offset += 1) { | 3508 | for (;; byte_offset += 1) { |
| 3508 | if (source[byte_offset] == 0) break; | 3509 | if (source[byte_offset] == 0) break; |
| ... | @@ -3519,7 +3520,17 @@ Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { | ... | @@ -3519,7 +3520,17 @@ Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { |
| 3519 | } | 3520 | } |
| 3520 | } | 3521 | } |
| 3521 | 3522 | ||
| 3523 | Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { | ||
| 3524 | bool trash; | ||
| 3525 | return token_identifier_buf2(root_struct, token, &trash); | ||
| 3526 | } | ||
| 3527 | |||
| 3522 | Buf *node_identifier_buf(AstNode *node) { | 3528 | Buf *node_identifier_buf(AstNode *node) { |
| 3529 | bool trash; | ||
| 3530 | return node_identifier_buf2(node, &trash); | ||
| 3531 | } | ||
| 3532 | |||
| 3533 | Buf *node_identifier_buf2(AstNode *node, bool *is_at_syntax) { | ||
| 3523 | assert(node->type == NodeTypeIdentifier); | 3534 | assert(node->type == NodeTypeIdentifier); |
| 3524 | // Currently, stage1 runs astgen for every comptime function call, | 3535 | // Currently, stage1 runs astgen for every comptime function call, |
| 3525 | // resulting the allocation here wasting memory. As a workaround until | 3536 | // resulting the allocation here wasting memory. As a workaround until |
| ... | @@ -3527,8 +3538,10 @@ Buf *node_identifier_buf(AstNode *node) { | ... | @@ -3527,8 +3538,10 @@ Buf *node_identifier_buf(AstNode *node) { |
| 3527 | // we memoize the result into the AST here. | 3538 | // we memoize the result into the AST here. |
| 3528 | if (node->data.identifier.name == nullptr) { | 3539 | if (node->data.identifier.name == nullptr) { |
| 3529 | RootStruct *root_struct = node->owner->data.structure.root_struct; | 3540 | RootStruct *root_struct = node->owner->data.structure.root_struct; |
| 3530 | node->data.identifier.name = token_identifier_buf(root_struct, node->main_token); | 3541 | node->data.identifier.name = token_identifier_buf2(root_struct, node->main_token, |
| 3542 | &node->data.identifier.is_at_syntax); | ||
| 3531 | } | 3543 | } |
| 3544 | *is_at_syntax = node->data.identifier.is_at_syntax; | ||
| 3532 | return node->data.identifier.name; | 3545 | return node->data.identifier.name; |
| 3533 | } | 3546 | } |
| 3534 | 3547 |
src/stage1/parser.hpp+1| ... | @@ -19,6 +19,7 @@ void ast_print(AstNode *node, int indent); | ... | @@ -19,6 +19,7 @@ void ast_print(AstNode *node, int indent); |
| 19 | void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context); | 19 | void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context); |
| 20 | 20 | ||
| 21 | Buf *node_identifier_buf(AstNode *node); | 21 | Buf *node_identifier_buf(AstNode *node); |
| 22 | Buf *node_identifier_buf2(AstNode *node, bool *is_at_syntax); | ||
| 22 | 23 | ||
| 23 | Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token); | 24 | Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token); |
| 24 | 25 |
test/behavior/misc.zig+12| ... | @@ -522,3 +522,15 @@ fn A() type { | ... | @@ -522,3 +522,15 @@ fn A() type { |
| 522 | test "non-ambiguous reference of shadowed decls" { | 522 | test "non-ambiguous reference of shadowed decls" { |
| 523 | try expect(A().B().Self != A().Self); | 523 | try expect(A().B().Self != A().Self); |
| 524 | } | 524 | } |
| 525 | |||
| 526 | test "use of declaration with same name as primitive" { | ||
| 527 | const S = struct { | ||
| 528 | const @"u8" = u16; | ||
| 529 | const alias = @"u8"; | ||
| 530 | }; | ||
| 531 | const a: S.u8 = 300; | ||
| 532 | try expect(a == 300); | ||
| 533 | |||
| 534 | const b: S.alias = 300; | ||
| 535 | try expect(b == 300); | ||
| 536 | } |
test/compile_errors.zig+31-4| ... | @@ -7258,14 +7258,41 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -7258,14 +7258,41 @@ pub fn addCases(ctx: *TestContext) !void { |
| 7258 | "tmp.zig:2:17: error: expected type 'u3', found 'u8'", | 7258 | "tmp.zig:2:17: error: expected type 'u3', found 'u8'", |
| 7259 | }); | 7259 | }); |
| 7260 | 7260 | ||
| 7261 | ctx.objErrStage1("globally shadowing a primitive type", | 7261 | ctx.objErrStage1("locally shadowing a primitive type", |
| 7262 | \\const u16 = u8; | 7262 | \\export fn foo() void { |
| 7263 | \\ const u8 = u16; | ||
| 7264 | \\ const a: u8 = 300; | ||
| 7265 | \\ _ = a; | ||
| 7266 | \\} | ||
| 7267 | \\export fn bar() void { | ||
| 7268 | \\ const @"u8" = u16; | ||
| 7269 | \\ const a: @"u8" = 300; | ||
| 7270 | \\ _ = a; | ||
| 7271 | \\} | ||
| 7272 | , &[_][]const u8{ | ||
| 7273 | "tmp.zig:2:11: error: local shadows primitive 'u8'", | ||
| 7274 | "tmp.zig:7:11: error: local shadows primitive 'u8'", | ||
| 7275 | }); | ||
| 7276 | |||
| 7277 | ctx.objErrStage1("primitives take precedence over declarations", | ||
| 7278 | \\const @"u8" = u16; | ||
| 7279 | \\export fn entry() void { | ||
| 7280 | \\ const a: u8 = 300; | ||
| 7281 | \\ _ = a; | ||
| 7282 | \\} | ||
| 7283 | , &[_][]const u8{ | ||
| 7284 | "tmp.zig:3:19: error: integer value 300 cannot be coerced to type 'u8'", | ||
| 7285 | }); | ||
| 7286 | |||
| 7287 | ctx.objErrStage1("declaration with same name as primitive must use special syntax", | ||
| 7288 | \\const u8 = u16; | ||
| 7263 | \\export fn entry() void { | 7289 | \\export fn entry() void { |
| 7264 | \\ const a: u16 = 300; | 7290 | \\ const a: u8 = 300; |
| 7265 | \\ _ = a; | 7291 | \\ _ = a; |
| 7266 | \\} | 7292 | \\} |
| 7267 | , &[_][]const u8{ | 7293 | , &[_][]const u8{ |
| 7268 | "tmp.zig:1:1: error: declaration shadows primitive type 'u16'", | 7294 | "tmp.zig:1:7: error: name shadows primitive 'u8'", |
| 7295 | "tmp.zig:1:7: note: consider using @\"u8\" to disambiguate", | ||
| 7269 | }); | 7296 | }); |
| 7270 | 7297 | ||
| 7271 | ctx.objErrStage1("implicitly increasing pointer alignment", | 7298 | ctx.objErrStage1("implicitly increasing pointer alignment", |