Commit d25674a51e

Vexu <git@vexu.eu>
2020-08-20 10:04:42
disallow extern variables with initializers
1 parent a553947
Changed files (8)
lib
src
src-self-hosted
test
standalone
global_linkage
lib/std/c/darwin.zig
@@ -41,7 +41,7 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
 /// on this operating system. However when building object files or libraries,
 /// the system libc won't be linked until the final executable. So we
 /// export a weak symbol here, to be overridden by the real one.
-pub extern "c" var _mh_execute_header: mach_hdr = undefined;
+pub extern "c" var _mh_execute_header: mach_hdr;
 comptime {
     if (std.Target.current.isDarwin()) {
         @export(_mh_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak });
lib/std/special/c.zig
@@ -35,7 +35,7 @@ comptime {
     }
 }
 
-extern var _fltused: c_int = 1;
+var _fltused: c_int = 1;
 
 extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
 fn wasm_start() callconv(.C) void {
lib/std/special/compiler_rt.zig
@@ -335,7 +335,7 @@ fn __stack_chk_fail() callconv(.C) noreturn {
     @panic("stack smashing detected");
 }
 
-extern var __stack_chk_guard: usize = blk: {
+var __stack_chk_guard: usize = blk: {
     var buf = [1]u8{0} ** @sizeOf(usize);
     buf[@sizeOf(usize) - 1] = 255;
     buf[@sizeOf(usize) - 2] = '\n';
src/parser.cpp
@@ -680,6 +680,9 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
             AstNode *var_decl = ast_parse_var_decl(pc);
             if (var_decl != nullptr) {
                 assert(var_decl->type == NodeTypeVariableDeclaration);
+                if (first->id == TokenIdKeywordExtern && var_decl->data.variable_declaration.expr != nullptr) {
+                    ast_error(pc, first, "extern variables have no initializers");
+                }
                 var_decl->line = first->start_line;
                 var_decl->column = first->start_column;
                 var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw;
src-self-hosted/Module.zig
@@ -324,10 +324,10 @@ pub const Fn = struct {
 };
 
 pub const Var = struct {
+    /// if is_extern == true this is undefined
     init: Value,
     owner_decl: *Decl,
 
-    has_init: bool,
     is_extern: bool,
     is_mutable: bool,
     is_threadlocal: bool,
@@ -1456,7 +1456,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
             const is_extern = blk: {
                 const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse
                     break :blk false;
-                break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern;
+                if (tree.token_ids[maybe_extern_token] != .Keyword_extern) break :blk false;
+                if (var_decl.getTrailer("init_node")) |some| {
+                    return self.failNode(&block_scope.base, some, "extern variables have no initializers", .{});
+                }
+                break :blk true;
             };
             if (var_decl.getTrailer("lib_name")) |lib_name| {
                 assert(is_extern);
@@ -1569,7 +1573,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
             new_variable.* = .{
                 .owner_decl = decl,
                 .init = value orelse undefined,
-                .has_init = value != null,
                 .is_extern = is_extern,
                 .is_mutable = is_mutable,
                 .is_threadlocal = is_threadlocal,
@@ -2440,7 +2443,7 @@ fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) Inner
     const variable = tv.val.cast(Value.Payload.Variable).?.variable;
 
     const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty);
-    if (!variable.is_mutable and !variable.is_extern and variable.has_init) {
+    if (!variable.is_mutable and !variable.is_extern) {
         const val_payload = try scope.arena().create(Value.Payload.RefVal);
         val_payload.* = .{ .val = variable.init };
         return self.constInst(scope, src, .{
test/standalone/global_linkage/obj1.zig
@@ -1,5 +1,5 @@
-extern var internal_integer: usize = 1;
-extern var obj1_integer: usize = 421;
+var internal_integer: usize = 1;
+var obj1_integer: usize = 421;
 
 comptime {
     @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
test/standalone/global_linkage/obj2.zig
@@ -1,5 +1,5 @@
-extern var internal_integer: usize = 2;
-extern var obj2_integer: usize = 422;
+var internal_integer: usize = 2;
+var obj2_integer: usize = 422;
 
 comptime {
     @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
test/compile_errors.zig
@@ -2,6 +2,12 @@ const tests = @import("tests.zig");
 const std = @import("std");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.addTest("reject extern variables with initializers",
+        \\extern var foo: int = 2;
+    , &[_][]const u8{
+        "tmp.zig:1:1: error: extern variables have no initializers",
+    });
+
     cases.addTest("duplicate/unused labels",
         \\comptime {
         \\    blk: { blk: while (false) {} }