Commit 2516d8671f

wrongnull <wrongnull@gmail.com>
2023-05-01 07:18:05
correct error note and check type of extern variables
1 parent 2952fb9
src/Sema.zig
@@ -22986,9 +22986,19 @@ fn validateVarType(
     var_ty: Type,
     is_extern: bool,
 ) CompileError!void {
-    if (try sema.validateRunTimeType(var_ty, is_extern)) return;
-
     const mod = sema.mod;
+    if (is_extern and !try sema.validateExternType(var_ty, .other)) {
+        const msg = msg: {
+            const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)});
+            errdefer msg.destroy(sema.gpa);
+            const src_decl = mod.declPtr(block.src_decl);
+            try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), var_ty, .other);
+            break :msg msg;
+        };
+        return sema.failWithOwnedErrorMsg(msg);
+    }
+
+    if (try sema.validateRunTimeType(var_ty, is_extern)) return;
 
     const msg = msg: {
         const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty.fmt(mod)});
@@ -23295,10 +23305,10 @@ fn explainWhyTypeIsNotExtern(
         .Pointer => try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}),
         .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
         .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
-        .Int => if (ty.intInfo(sema.mod.getTarget()).bits > 128) {
-            try mod.errNoteNonLazy(src_loc, msg, "only integers with less than 128 bits are extern compatible", .{});
-        } else {
+        .Int => if (!std.math.isPowerOfTwo(ty.intInfo(sema.mod.getTarget()).bits)) {
             try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{});
+        } else {
+            try mod.errNoteNonLazy(src_loc, msg, "only integers with 8, 16, 32, 64 and 128 bits are extern compatible", .{});
         },
         .Fn => {
             if (position != .other) {
test/cases/compile_errors/exported_enum_without_explicit_integer_tag_type.zig
@@ -14,5 +14,5 @@ comptime {
 // :3:5: error: unable to export type 'type'
 // :7:5: error: unable to export type 'tmp.E'
 // :7:5: note: enum tag type 'u1' is not extern compatible
-// :7:5: note: only integers with power of two bits are extern compatible
+// :7:5: note: only integers with 8, 16, 32, 64 and 128 bits are extern compatible
 // :1:11: note: enum declared here
test/cases/compile_errors/extern_variable_has_non_extern_type.zig
@@ -0,0 +1,11 @@
+extern var foo: u3;
+pub export fn entry() void {
+    _ = foo;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :1:17: error: extern variable cannot have type 'u3'
+// :1:17: note: only integers with power of two bits are extern compatible
test/cases/compile_errors/function_with_non-extern_non-packed_enum_parameter.zig
@@ -7,5 +7,5 @@ export fn entry(foo: Foo) void { _ = foo; }
 //
 // :2:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C'
 // :2:17: note: enum tag type 'u2' is not extern compatible
-// :2:17: note: only integers with power of two bits are extern compatible
+// :2:17: note: only integers with 8, 16, 32, 64 and 128 bits are extern compatible
 // :1:13: note: enum declared here