mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-07 22:34:28 +00:00
Merge pull request #6103 from Vexu/extern
Disallow extern variables with initializers.
This commit is contained in:
commit
9cfcd0c296
13 changed files with 121 additions and 32 deletions
|
|
@ -46,10 +46,11 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
|
||||||
/// on this operating system. However when building object files or libraries,
|
/// on this operating system. However when building object files or libraries,
|
||||||
/// the system libc won't be linked until the final executable. So we
|
/// 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.
|
/// export a weak symbol here, to be overridden by the real one.
|
||||||
pub extern "c" var _mh_execute_header: mach_hdr = undefined;
|
var dummy_execute_header: mach_hdr = undefined;
|
||||||
|
pub extern var _mh_execute_header: mach_hdr;
|
||||||
comptime {
|
comptime {
|
||||||
if (std.Target.current.isDarwin()) {
|
if (std.Target.current.isDarwin()) {
|
||||||
@export(_mh_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak });
|
@export(dummy_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -226,9 +226,19 @@ pub fn zeroes(comptime T: type) T {
|
||||||
.Vector => |info| {
|
.Vector => |info| {
|
||||||
return @splat(info.len, zeroes(info.child));
|
return @splat(info.len, zeroes(info.child));
|
||||||
},
|
},
|
||||||
|
.Union => |info| {
|
||||||
|
if (comptime meta.containerLayout(T) == .Extern) {
|
||||||
|
// The C language specification states that (global) unions
|
||||||
|
// should be zero initialized to the first named member.
|
||||||
|
var item: T = undefined;
|
||||||
|
@field(item, info.fields[0].name) = zeroes(@TypeOf(@field(item, info.fields[0].name)));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@compileError("Can't set a " ++ @typeName(T) ++ " to zero.");
|
||||||
|
},
|
||||||
.ErrorUnion,
|
.ErrorUnion,
|
||||||
.ErrorSet,
|
.ErrorSet,
|
||||||
.Union,
|
|
||||||
.Fn,
|
.Fn,
|
||||||
.BoundFn,
|
.BoundFn,
|
||||||
.Type,
|
.Type,
|
||||||
|
|
@ -317,6 +327,14 @@ test "mem.zeroes" {
|
||||||
for (b.sentinel) |e| {
|
for (b.sentinel) |e| {
|
||||||
testing.expectEqual(@as(u8, 0), e);
|
testing.expectEqual(@as(u8, 0), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const C_union = extern union {
|
||||||
|
a: u8,
|
||||||
|
b: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
var c = zeroes(C_union);
|
||||||
|
testing.expectEqual(@as(u8, 0), c.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a slice to zeroes.
|
/// Sets a slice to zeroes.
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,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;
|
extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
|
||||||
fn wasm_start() callconv(.C) void {
|
fn wasm_start() callconv(.C) void {
|
||||||
|
|
|
||||||
|
|
@ -340,7 +340,7 @@ fn __stack_chk_fail() callconv(.C) noreturn {
|
||||||
@panic("stack smashing detected");
|
@panic("stack smashing detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern var __stack_chk_guard: usize = blk: {
|
var __stack_chk_guard: usize = blk: {
|
||||||
var buf = [1]u8{0} ** @sizeOf(usize);
|
var buf = [1]u8{0} ** @sizeOf(usize);
|
||||||
buf[@sizeOf(usize) - 1] = 255;
|
buf[@sizeOf(usize) - 1] = 255;
|
||||||
buf[@sizeOf(usize) - 2] = '\n';
|
buf[@sizeOf(usize) - 2] = '\n';
|
||||||
|
|
|
||||||
|
|
@ -324,10 +324,10 @@ pub const Fn = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Var = struct {
|
pub const Var = struct {
|
||||||
|
/// if is_extern == true this is undefined
|
||||||
init: Value,
|
init: Value,
|
||||||
owner_decl: *Decl,
|
owner_decl: *Decl,
|
||||||
|
|
||||||
has_init: bool,
|
|
||||||
is_extern: bool,
|
is_extern: bool,
|
||||||
is_mutable: bool,
|
is_mutable: bool,
|
||||||
is_threadlocal: bool,
|
is_threadlocal: bool,
|
||||||
|
|
@ -1456,7 +1456,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
||||||
const is_extern = blk: {
|
const is_extern = blk: {
|
||||||
const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse
|
const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse
|
||||||
break :blk false;
|
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| {
|
if (var_decl.getTrailer("lib_name")) |lib_name| {
|
||||||
assert(is_extern);
|
assert(is_extern);
|
||||||
|
|
@ -1569,7 +1573,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
||||||
new_variable.* = .{
|
new_variable.* = .{
|
||||||
.owner_decl = decl,
|
.owner_decl = decl,
|
||||||
.init = value orelse undefined,
|
.init = value orelse undefined,
|
||||||
.has_init = value != null,
|
|
||||||
.is_extern = is_extern,
|
.is_extern = is_extern,
|
||||||
.is_mutable = is_mutable,
|
.is_mutable = is_mutable,
|
||||||
.is_threadlocal = is_threadlocal,
|
.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 variable = tv.val.cast(Value.Payload.Variable).?.variable;
|
||||||
|
|
||||||
const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty);
|
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);
|
const val_payload = try scope.arena().create(Value.Payload.RefVal);
|
||||||
val_payload.* = .{ .val = variable.init };
|
val_payload.* = .{ .val = variable.init };
|
||||||
return self.constInst(scope, src, .{
|
return self.constInst(scope, src, .{
|
||||||
|
|
|
||||||
|
|
@ -498,7 +498,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
|
||||||
_ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
|
_ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
|
||||||
},
|
},
|
||||||
.Var => {
|
.Var => {
|
||||||
return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl));
|
return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl), null);
|
||||||
},
|
},
|
||||||
.Empty => {
|
.Empty => {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
|
@ -679,12 +679,13 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
|
||||||
return addTopLevelDecl(c, fn_name, &proto_node.base);
|
return addTopLevelDecl(c, fn_name, &proto_node.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
|
/// if mangled_name is not null, this var decl was declared in a block scope.
|
||||||
const var_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl)));
|
fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl, mangled_name: ?[]const u8) Error!void {
|
||||||
|
const var_name = mangled_name orelse try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl)));
|
||||||
if (c.global_scope.sym_table.contains(var_name))
|
if (c.global_scope.sym_table.contains(var_name))
|
||||||
return; // Avoid processing this decl twice
|
return; // Avoid processing this decl twice
|
||||||
const rp = makeRestorePoint(c);
|
const rp = makeRestorePoint(c);
|
||||||
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
|
const visib_tok = if (mangled_name) |_| null else try appendToken(c, .Keyword_pub, "pub");
|
||||||
|
|
||||||
const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
|
const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
|
||||||
null
|
null
|
||||||
|
|
@ -701,8 +702,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
|
||||||
const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
|
const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
|
||||||
const storage_class = ZigClangVarDecl_getStorageClass(var_decl);
|
const storage_class = ZigClangVarDecl_getStorageClass(var_decl);
|
||||||
const is_const = ZigClangQualType_isConstQualified(qual_type);
|
const is_const = ZigClangQualType_isConstQualified(qual_type);
|
||||||
|
const has_init = ZigClangVarDecl_hasInit(var_decl);
|
||||||
|
|
||||||
const extern_tok = if (storage_class == .Extern)
|
// In C extern variables with initializers behave like Zig exports.
|
||||||
|
// extern int foo = 2;
|
||||||
|
// does the same as:
|
||||||
|
// extern int foo;
|
||||||
|
// int foo = 2;
|
||||||
|
const extern_tok = if (storage_class == .Extern and !has_init)
|
||||||
try appendToken(c, .Keyword_extern, "extern")
|
try appendToken(c, .Keyword_extern, "extern")
|
||||||
else if (storage_class != .Static)
|
else if (storage_class != .Static)
|
||||||
try appendToken(c, .Keyword_export, "export")
|
try appendToken(c, .Keyword_export, "export")
|
||||||
|
|
@ -730,7 +737,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
|
||||||
// If the initialization expression is not present, initialize with undefined.
|
// If the initialization expression is not present, initialize with undefined.
|
||||||
// If it is an integer literal, we can skip the @as since it will be redundant
|
// If it is an integer literal, we can skip the @as since it will be redundant
|
||||||
// with the variable type.
|
// with the variable type.
|
||||||
if (ZigClangVarDecl_hasInit(var_decl)) {
|
if (has_init) {
|
||||||
eq_tok = try appendToken(c, .Equal, "=");
|
eq_tok = try appendToken(c, .Equal, "=");
|
||||||
init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
|
init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
|
||||||
transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {
|
transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {
|
||||||
|
|
@ -745,7 +752,22 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
|
||||||
try transCreateNodeUndefinedLiteral(c);
|
try transCreateNodeUndefinedLiteral(c);
|
||||||
} else if (storage_class != .Extern) {
|
} else if (storage_class != .Extern) {
|
||||||
eq_tok = try appendToken(c, .Equal, "=");
|
eq_tok = try appendToken(c, .Equal, "=");
|
||||||
init_node = try transCreateNodeIdentifierUnchecked(c, "undefined");
|
// The C language specification states that variables with static or threadlocal
|
||||||
|
// storage without an initializer are initialized to a zero value.
|
||||||
|
|
||||||
|
// @import("std").mem.zeroes(T)
|
||||||
|
const import_fn_call = try c.createBuiltinCall("@import", 1);
|
||||||
|
const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
|
||||||
|
import_fn_call.params()[0] = std_node;
|
||||||
|
import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
|
||||||
|
const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem");
|
||||||
|
const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroes");
|
||||||
|
|
||||||
|
const zero_init_call = try c.createCall(outer_field_access, 1);
|
||||||
|
zero_init_call.params()[0] = type_node;
|
||||||
|
zero_init_call.rtoken = try appendToken(c, .RParen, ")");
|
||||||
|
|
||||||
|
init_node = &zero_init_call.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
const linksection_expr = blk: {
|
const linksection_expr = blk: {
|
||||||
|
|
@ -1561,15 +1583,22 @@ fn transDeclStmtOne(
|
||||||
.Var => {
|
.Var => {
|
||||||
const var_decl = @ptrCast(*const ZigClangVarDecl, decl);
|
const var_decl = @ptrCast(*const ZigClangVarDecl, decl);
|
||||||
|
|
||||||
const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
|
|
||||||
null
|
|
||||||
else
|
|
||||||
try appendToken(c, .Keyword_threadlocal, "threadlocal");
|
|
||||||
const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
|
const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
|
||||||
const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(
|
const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(
|
||||||
@ptrCast(*const ZigClangNamedDecl, var_decl),
|
@ptrCast(*const ZigClangNamedDecl, var_decl),
|
||||||
));
|
));
|
||||||
const mangled_name = try block_scope.makeMangledName(c, name);
|
const mangled_name = try block_scope.makeMangledName(c, name);
|
||||||
|
|
||||||
|
switch (ZigClangVarDecl_getStorageClass(var_decl)) {
|
||||||
|
.Extern, .Static => {
|
||||||
|
// This is actually a global variable, put it in the global scope and reference it.
|
||||||
|
// `_ = mangled_name;`
|
||||||
|
try visitVarDecl(rp.c, var_decl, mangled_name);
|
||||||
|
return try maybeSuppressResult(rp, scope, .unused, try transCreateNodeIdentifier(rp.c, mangled_name));
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
const mut_tok = if (ZigClangQualType_isConstQualified(qual_type))
|
const mut_tok = if (ZigClangQualType_isConstQualified(qual_type))
|
||||||
try appendToken(c, .Keyword_const, "const")
|
try appendToken(c, .Keyword_const, "const")
|
||||||
else
|
else
|
||||||
|
|
@ -1597,7 +1626,6 @@ fn transDeclStmtOne(
|
||||||
.mut_token = mut_tok,
|
.mut_token = mut_tok,
|
||||||
.semicolon_token = semicolon_token,
|
.semicolon_token = semicolon_token,
|
||||||
}, .{
|
}, .{
|
||||||
.thread_local_token = thread_local_token,
|
|
||||||
.eq_token = eq_token,
|
.eq_token = eq_token,
|
||||||
.type_node = type_node,
|
.type_node = type_node,
|
||||||
.init_node = init_node,
|
.init_node = init_node,
|
||||||
|
|
|
||||||
|
|
@ -292,13 +292,14 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
|
static LLVMLinkage to_llvm_linkage(GlobalLinkageId id, bool is_extern) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case GlobalLinkageIdInternal:
|
case GlobalLinkageIdInternal:
|
||||||
return LLVMInternalLinkage;
|
return LLVMInternalLinkage;
|
||||||
case GlobalLinkageIdStrong:
|
case GlobalLinkageIdStrong:
|
||||||
return LLVMExternalLinkage;
|
return LLVMExternalLinkage;
|
||||||
case GlobalLinkageIdWeak:
|
case GlobalLinkageIdWeak:
|
||||||
|
if (is_extern) return LLVMExternalWeakLinkage;
|
||||||
return LLVMWeakODRLinkage;
|
return LLVMWeakODRLinkage;
|
||||||
case GlobalLinkageIdLinkOnce:
|
case GlobalLinkageIdLinkOnce:
|
||||||
return LLVMLinkOnceODRLinkage;
|
return LLVMLinkOnceODRLinkage;
|
||||||
|
|
@ -521,7 +522,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage));
|
LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage, fn->body_node == nullptr));
|
||||||
|
|
||||||
if (linkage == GlobalLinkageIdInternal) {
|
if (linkage == GlobalLinkageIdInternal) {
|
||||||
LLVMSetUnnamedAddr(llvm_fn, true);
|
LLVMSetUnnamedAddr(llvm_fn, true);
|
||||||
|
|
@ -7962,7 +7963,7 @@ static void do_code_gen(CodeGen *g) {
|
||||||
global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name);
|
global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name);
|
||||||
// TODO debug info for the extern variable
|
// TODO debug info for the extern variable
|
||||||
|
|
||||||
LLVMSetLinkage(global_value, to_llvm_linkage(linkage));
|
LLVMSetLinkage(global_value, to_llvm_linkage(linkage, true));
|
||||||
maybe_import_dll(g, global_value, GlobalLinkageIdStrong);
|
maybe_import_dll(g, global_value, GlobalLinkageIdStrong);
|
||||||
LLVMSetAlignment(global_value, var->align_bytes);
|
LLVMSetAlignment(global_value, var->align_bytes);
|
||||||
LLVMSetGlobalConstant(global_value, var->gen_is_const);
|
LLVMSetGlobalConstant(global_value, var->gen_is_const);
|
||||||
|
|
@ -7975,7 +7976,7 @@ static void do_code_gen(CodeGen *g) {
|
||||||
global_value = var->const_value->llvm_global;
|
global_value = var->const_value->llvm_global;
|
||||||
|
|
||||||
if (exported) {
|
if (exported) {
|
||||||
LLVMSetLinkage(global_value, to_llvm_linkage(linkage));
|
LLVMSetLinkage(global_value, to_llvm_linkage(linkage, false));
|
||||||
maybe_export_dll(g, global_value, GlobalLinkageIdStrong);
|
maybe_export_dll(g, global_value, GlobalLinkageIdStrong);
|
||||||
}
|
}
|
||||||
if (var->section_name) {
|
if (var->section_name) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
AstNode *var_decl = ast_parse_var_decl(pc);
|
||||||
if (var_decl != nullptr) {
|
if (var_decl != nullptr) {
|
||||||
assert(var_decl->type == NodeTypeVariableDeclaration);
|
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->line = first->start_line;
|
||||||
var_decl->column = first->start_column;
|
var_decl->column = first->start_column;
|
||||||
var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw;
|
var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@ const tests = @import("tests.zig");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
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",
|
cases.addTest("duplicate/unused labels",
|
||||||
\\comptime {
|
\\comptime {
|
||||||
\\ blk: { blk: while (false) {} }
|
\\ blk: { blk: while (false) {} }
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,20 @@ const tests = @import("tests.zig");
|
||||||
const nl = std.cstr.line_sep;
|
const nl = std.cstr.line_sep;
|
||||||
|
|
||||||
pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||||
|
cases.add("static variable in block scope",
|
||||||
|
\\#include <stdlib.h>
|
||||||
|
\\int foo() {
|
||||||
|
\\ static int bar;
|
||||||
|
\\ bar += 1;
|
||||||
|
\\ return bar;
|
||||||
|
\\}
|
||||||
|
\\int main() {
|
||||||
|
\\ foo();
|
||||||
|
\\ foo();
|
||||||
|
\\ if (foo() != 3) abort();
|
||||||
|
\\}
|
||||||
|
, "");
|
||||||
|
|
||||||
cases.add("array initializer",
|
cases.add("array initializer",
|
||||||
\\#include <stdlib.h>
|
\\#include <stdlib.h>
|
||||||
\\int main(int argc, char **argv) {
|
\\int main(int argc, char **argv) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
extern var internal_integer: usize = 1;
|
var internal_integer: usize = 1;
|
||||||
extern var obj1_integer: usize = 421;
|
var obj1_integer: usize = 421;
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
@export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
|
@export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
extern var internal_integer: usize = 2;
|
var internal_integer: usize = 2;
|
||||||
extern var obj2_integer: usize = 422;
|
var obj2_integer: usize = 422;
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
@export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
|
@export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,20 @@ const std = @import("std");
|
||||||
const CrossTarget = std.zig.CrossTarget;
|
const CrossTarget = std.zig.CrossTarget;
|
||||||
|
|
||||||
pub fn addCases(cases: *tests.TranslateCContext) void {
|
pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||||
|
cases.add("extern variable in block scope",
|
||||||
|
\\float bar;
|
||||||
|
\\int foo() {
|
||||||
|
\\ _Thread_local static int bar = 2;
|
||||||
|
\\}
|
||||||
|
, &[_][]const u8{
|
||||||
|
\\pub export var bar: f32 = @import("std").mem.zeroes(f32);
|
||||||
|
\\threadlocal var bar_1: c_int = 2;
|
||||||
|
\\pub export fn foo() c_int {
|
||||||
|
\\ _ = bar_1;
|
||||||
|
\\ return 0;
|
||||||
|
\\}
|
||||||
|
});
|
||||||
|
|
||||||
cases.add("missing return stmt",
|
cases.add("missing return stmt",
|
||||||
\\int foo() {}
|
\\int foo() {}
|
||||||
\\int bar() {
|
\\int bar() {
|
||||||
|
|
@ -466,7 +480,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||||
, &[_][]const u8{
|
, &[_][]const u8{
|
||||||
\\pub extern var extern_var: c_int;
|
\\pub extern var extern_var: c_int;
|
||||||
\\pub const int_var: c_int = 13;
|
\\pub const int_var: c_int = 13;
|
||||||
\\pub export var foo: c_int = undefined;
|
\\pub export var foo: c_int = @import("std").mem.zeroes(c_int);
|
||||||
});
|
});
|
||||||
|
|
||||||
cases.add("const ptr initializer",
|
cases.add("const ptr initializer",
|
||||||
|
|
@ -480,8 +494,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||||
\\ static const char v2[] = "2.2.2";
|
\\ static const char v2[] = "2.2.2";
|
||||||
\\}
|
\\}
|
||||||
, &[_][]const u8{
|
, &[_][]const u8{
|
||||||
\\pub export fn foo() void {
|
|
||||||
\\const v2: [*c]const u8 = "2.2.2";
|
\\const v2: [*c]const u8 = "2.2.2";
|
||||||
|
\\pub export fn foo() void {
|
||||||
|
\\ _ = v2;
|
||||||
\\}
|
\\}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1327,7 +1342,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||||
\\static char arr1[] = "hello";
|
\\static char arr1[] = "hello";
|
||||||
\\char arr2[] = "hello";
|
\\char arr2[] = "hello";
|
||||||
, &[_][]const u8{
|
, &[_][]const u8{
|
||||||
\\pub extern var arr0: [*c]u8 = "hello";
|
\\pub export var arr0: [*c]u8 = "hello";
|
||||||
\\pub var arr1: [*c]u8 = "hello";
|
\\pub var arr1: [*c]u8 = "hello";
|
||||||
\\pub export var arr2: [*c]u8 = "hello";
|
\\pub export var arr2: [*c]u8 = "hello";
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue