Commit bc0a60c7a6
Changed files (3)
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;
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;
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");
+
}