Commit ebde525cce

Bogdan Romanyuk <65823030+wrongnull@users.noreply.github.com>
2023-10-16 03:30:39
Sema: fix `@extern` error on function pointer
1 parent fd6b3db
Changed files (2)
src
test
src/Sema.zig
@@ -25277,7 +25277,7 @@ fn zirBuiltinExtern(
     if (!ty.isPtrAtRuntime(mod)) {
         return sema.fail(block, ty_src, "expected (optional) pointer", .{});
     }
-    if (!try sema.validateExternType(ty.childType(mod), .other)) {
+    if (!try sema.validateExternType(ty, .other)) {
         const msg = msg: {
             const msg = try sema.errMsg(block, ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(mod)});
             errdefer msg.destroy(sema.gpa);
@@ -25618,7 +25618,12 @@ fn validateExternType(
         .Float,
         .AnyFrame,
         => return true,
-        .Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)),
+        .Pointer => {
+            if (ty.childType(mod).zigTypeTag(mod) == .Fn) {
+                return ty.isConstPtr(mod) and try sema.validateExternType(ty.childType(mod), .other);
+            }
+            return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty));
+        },
         .Int => switch (ty.intInfo(mod).bits) {
             0, 8, 16, 32, 64, 128 => return true,
             else => return false,
@@ -25687,8 +25692,13 @@ fn explainWhyTypeIsNotExtern(
                 try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
             } else {
                 const pointee_ty = ty.childType(mod);
-                try mod.errNoteNonLazy(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(sema.mod)});
-                try sema.explainWhyTypeIsComptime(msg, src_loc, pointee_ty);
+                if (!ty.isConstPtr(mod) and pointee_ty.zigTypeTag(mod) == .Fn) {
+                    try mod.errNoteNonLazy(src_loc, msg, "pointer to extern function must be 'const'", .{});
+                } else if (try sema.typeRequiresComptime(ty)) {
+                    try mod.errNoteNonLazy(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(sema.mod)});
+                    try sema.explainWhyTypeIsComptime(msg, src_loc, ty);
+                }
+                try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, position);
             }
         },
         .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
test/cases/compile_errors/invalid_type_in_builtin_extern.zig
@@ -1,7 +1,11 @@
 const x = @extern(*comptime_int, .{ .name = "foo" });
+const y = @extern(*fn (u8) u8, .{ .name = "bar" });
 pub export fn entry() void {
     _ = x;
 }
+pub export fn entry2() void {
+    _ = y;
+}
 
 // error
 // backend=stage2
@@ -9,3 +13,6 @@ pub export fn entry() void {
 //
 // :1:19: error: extern symbol cannot have type '*comptime_int'
 // :1:19: note: pointer to comptime-only type 'comptime_int'
+// :2:19: error: extern symbol cannot have type '*fn (u8) u8'
+// :2:19: note: pointer to extern function must be 'const'
+// :2:19: note: extern function must specify calling convention