diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-09-09 22:46:08 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-09-09 22:46:08 -0400 |
| commit | bc0a60c7a6e772a40fc19becd46f89f34f502759 (patch) | |
| tree | ea48f9759ed2cb10146c441ef45db289729befe8 | |
| parent | 5fdf3fa1954f8f8f2a4558723078c0b1400b8574 (diff) | |
| download | zig-bc0a60c7a6e772a40fc19becd46f89f34f502759.tar.gz zig-bc0a60c7a6e772a40fc19becd46f89f34f502759.zip | |
more compile errors for non-const variables of things
closes #456
| -rw-r--r-- | src/analyze.cpp | 1 | ||||
| -rw-r--r-- | src/ir.cpp | 123 | ||||
| -rw-r--r-- | test/compile_errors.zig | 50 |
3 files changed, 108 insertions, 66 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index fe705dfce8..eaeb3fa553 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2510,6 +2510,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { IrInstruction *init_value = nullptr; + // TODO more validation for types that can't be used for export/extern variables TypeTableEntry *implicit_type = nullptr; if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) { implicit_type = explicit_type; diff --git a/src/ir.cpp b/src/ir.cpp index a30851d010..5771fd480d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9794,6 +9794,58 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi zig_unreachable(); } +enum VarClassRequired { + VarClassRequiredAny, + VarClassRequiredConst, + VarClassRequiredIllegal, +}; + +static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) { + switch (type_entry->id) { + case TypeTableEntryIdInvalid: + zig_unreachable(); + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdVar: + return VarClassRequiredIllegal; + case TypeTableEntryIdBool: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdVoid: + case TypeTableEntryIdPureError: + case TypeTableEntryIdFn: + case TypeTableEntryIdEnumTag: + return VarClassRequiredAny; + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdBlock: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdOpaque: + case TypeTableEntryIdMetaType: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBoundFn: + case TypeTableEntryIdArgTuple: + return VarClassRequiredConst; + + case TypeTableEntryIdPointer: + return get_var_class_required(type_entry->data.pointer.child_type); + case TypeTableEntryIdArray: + return get_var_class_required(type_entry->data.array.child_type); + case TypeTableEntryIdMaybe: + return get_var_class_required(type_entry->data.maybe.child_type); + case TypeTableEntryIdErrorUnion: + return get_var_class_required(type_entry->data.error.child_type); + + case TypeTableEntryIdStruct: + case TypeTableEntryIdEnum: + case TypeTableEntryIdUnion: + // TODO check the fields of these things and make sure that they don't recursively + // contain any of the other variable classes + return VarClassRequiredAny; + } + zig_unreachable(); +} + static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) { VariableTableEntry *var = decl_var_instruction->var; @@ -9803,10 +9855,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc return var->value->type; } - AstNodeVariableDeclaration *variable_declaration = &var->decl_node->data.variable_declaration; - bool is_export = (variable_declaration->visib_mod == VisibModExport); - bool is_extern = variable_declaration->is_extern; - var->ref_count = 0; TypeTableEntry *explicit_type = nullptr; @@ -9824,59 +9872,30 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc AstNode *source_node = decl_var_instruction->base.source_node; IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, explicit_type); + bool is_comptime_var = ir_get_var_is_comptime(var); + TypeTableEntry *result_type = casted_init_value->value.type; if (type_is_invalid(result_type)) { result_type = ira->codegen->builtin_types.entry_invalid; - } - - bool is_comptime_var = ir_get_var_is_comptime(var); - - switch (result_type->id) { - case TypeTableEntryIdInvalid: - break; // handled above - case TypeTableEntryIdNumLitFloat: - case TypeTableEntryIdNumLitInt: - case TypeTableEntryIdUndefLit: - if (is_export || is_extern || (!var->src_is_const && !is_comptime_var)) { - ir_add_error_node(ira, source_node, buf_sprintf("unable to infer variable type")); - result_type = ira->codegen->builtin_types.entry_invalid; - } - break; - case TypeTableEntryIdUnreachable: - case TypeTableEntryIdVar: - case TypeTableEntryIdBlock: - case TypeTableEntryIdNullLit: - case TypeTableEntryIdOpaque: - ir_add_error_node(ira, source_node, - buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name))); - result_type = ira->codegen->builtin_types.entry_invalid; - break; - case TypeTableEntryIdMetaType: - case TypeTableEntryIdNamespace: - if (casted_init_value->value.special == ConstValSpecialRuntime) { + } else { + switch (get_var_class_required(result_type)) { + case VarClassRequiredIllegal: ir_add_error_node(ira, source_node, - buf_sprintf("variable of type '%s' must be constant", buf_ptr(&result_type->name))); + buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name))); result_type = ira->codegen->builtin_types.entry_invalid; - } - break; - case TypeTableEntryIdVoid: - case TypeTableEntryIdBool: - case TypeTableEntryIdInt: - case TypeTableEntryIdFloat: - case TypeTableEntryIdPointer: - case TypeTableEntryIdArray: - case TypeTableEntryIdStruct: - case TypeTableEntryIdMaybe: - case TypeTableEntryIdErrorUnion: - case TypeTableEntryIdPureError: - case TypeTableEntryIdEnum: - case TypeTableEntryIdUnion: - case TypeTableEntryIdFn: - case TypeTableEntryIdBoundFn: - case TypeTableEntryIdEnumTag: - case TypeTableEntryIdArgTuple: - // OK - break; + break; + case VarClassRequiredConst: + if (!var->src_is_const && !is_comptime_var) { + ir_add_error_node(ira, source_node, + buf_sprintf("variable of type '%s' must be const or comptime", + buf_ptr(&result_type->name))); + result_type = ira->codegen->builtin_types.entry_invalid; + } + break; + case VarClassRequiredAny: + // OK + break; + } } var->value->type = result_type; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 93be0e176e..97df974ab5 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1435,20 +1435,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar() -> %i32 { 0 } , ".tmp_source.zig:2:14: error: expression value is ignored"); - cases.add("integer literal on a non-comptime var", - \\export fn foo() { - \\ var i = 0; - \\ while (i < 10) : (i += 1) { } - \\} - , ".tmp_source.zig:2:5: error: unable to infer variable type"); - - cases.add("undefined literal on a non-comptime var", - \\export fn foo() { - \\ var i = undefined; - \\ i = i32(1); - \\} - , ".tmp_source.zig:2:5: error: unable to infer variable type"); - cases.add("dereference an array", \\var s_buffer: [10]u8 = undefined; \\pub fn pass(in: []u8) -> []u8 { @@ -2090,4 +2076,40 @@ pub fn addCases(cases: &tests.CompileErrorContext) { , ".tmp_source.zig:5:9: error: expected type '&Derp', found '&c_void'"); + cases.add("non-const variables of things that require const variables", + \\const Opaque = @OpaqueType(); + \\ + \\export fn entry(opaque: &Opaque) { + \\ var m2 = &2; + \\ const y: u32 = *m2; + \\ + \\ var a = undefined; + \\ var b = 1; + \\ var c = 1.0; + \\ var d = this; + \\ var e = null; + \\ var f = *opaque; + \\ var g = i32; + \\ var h = @import("std"); + \\ var i = (Foo {}).bar; + \\ + \\ var z: noreturn = return; + \\} + \\ + \\const Foo = struct { + \\ fn bar(self: &const Foo) {} + \\}; + , + ".tmp_source.zig:4:4: error: variable of type '&const (integer literal)' must be const or comptime", + ".tmp_source.zig:7:4: error: variable of type '(undefined)' must be const or comptime", + ".tmp_source.zig:8:4: error: variable of type '(integer literal)' must be const or comptime", + ".tmp_source.zig:9:4: error: variable of type '(float literal)' must be const or comptime", + ".tmp_source.zig:10:4: error: variable of type '(block)' must be const or comptime", + ".tmp_source.zig:11:4: error: variable of type '(null)' must be const or comptime", + ".tmp_source.zig:12:4: error: variable of type 'Opaque' must be const or comptime", + ".tmp_source.zig:13:4: error: variable of type 'type' must be const or comptime", + ".tmp_source.zig:14:4: error: variable of type '(namespace)' must be const or comptime", + ".tmp_source.zig:15:4: error: variable of type '(bound fn(&const Foo))' must be const or comptime", + ".tmp_source.zig:17:4: error: unreachable code"); + } |
