diff --git a/lib/std/c.zig b/lib/std/c.zig index 400feda63c..d98dbf0cde 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -219,7 +219,11 @@ pub extern "c" fn utimes(path: [*:0]const u8, times: *[2]c.timeval) c_int; pub extern "c" fn utimensat(dirfd: c.fd_t, pathname: [*:0]const u8, times: *[2]c.timespec, flags: u32) c_int; pub extern "c" fn futimens(fd: c.fd_t, times: *const [2]c.timespec) c_int; -pub extern "c" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const c.pthread_attr_t, start_routine: fn (?*anyopaque) callconv(.C) ?*anyopaque, noalias arg: ?*anyopaque) c.E; +pub extern "c" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const c.pthread_attr_t, start_routine: PThreadStartFn, noalias arg: ?*anyopaque) c.E; +const PThreadStartFn = if (builtin.zig_backend == .stage1) + fn (?*anyopaque) callconv(.C) ?*anyopaque +else + *const fn (?*anyopaque) callconv(.C) ?*anyopaque; pub extern "c" fn pthread_attr_init(attr: *c.pthread_attr_t) c.E; pub extern "c" fn pthread_attr_setstack(attr: *c.pthread_attr_t, stackaddr: *anyopaque, stacksize: usize) c.E; pub extern "c" fn pthread_attr_setstacksize(attr: *c.pthread_attr_t, stacksize: usize) c.E; @@ -229,10 +233,14 @@ pub extern "c" fn pthread_self() pthread_t; pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*anyopaque) c.E; pub extern "c" fn pthread_detach(thread: pthread_t) c.E; pub extern "c" fn pthread_atfork( - prepare: ?fn () callconv(.C) void, - parent: ?fn () callconv(.C) void, - child: ?fn () callconv(.C) void, + prepare: ?PThreadForkFn, + parent: ?PThreadForkFn, + child: ?PThreadForkFn, ) c_int; +const PThreadForkFn = if (builtin.zig_backend == .stage1) + fn () callconv(.C) void +else + *const fn () callconv(.C) void; pub extern "c" fn pthread_key_create(key: *c.pthread_key_t, destructor: ?fn (value: *anyopaque) callconv(.C) void) c.E; pub extern "c" fn pthread_key_delete(key: c.pthread_key_t) c.E; pub extern "c" fn pthread_getspecific(key: c.pthread_key_t) ?*anyopaque; diff --git a/lib/std/c/tokenizer.zig b/lib/std/c/tokenizer.zig index 97d62d3803..de8b1a429c 100644 --- a/lib/std/c/tokenizer.zig +++ b/lib/std/c/tokenizer.zig @@ -126,7 +126,11 @@ pub const Token = struct { Keyword_error, Keyword_pragma, - pub fn symbol(id: std.meta.Tag(Id)) []const u8 { + pub fn symbol(id: Id) []const u8 { + return symbolName(id); + } + + pub fn symbolName(id: std.meta.Tag(Id)) []const u8 { return switch (id) { .Invalid => "Invalid", .Eof => "Eof", diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index d0639463a0..dfc2020334 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -32,10 +32,8 @@ comptime { @export(wasm_start, .{ .name = "_start", .linkage = .Strong }); } - if (builtin.zig_backend == .stage1) { // TODO remove this condition - if (native_os == .linux) { - @export(clone, .{ .name = "clone" }); - } + if (native_os == .linux) { + @export(clone, .{ .name = "clone" }); } @export(memset, .{ .name = "memset", .linkage = .Strong }); diff --git a/src/AstGen.zig b/src/AstGen.zig index a5351f8769..34b29b28fb 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1807,6 +1807,8 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn .@"break"; if (rhs == 0) { + try genDefers(parent_gz, scope, parent_scope, .normal_only); + _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); return Zir.Inst.Ref.unreachable_value; } @@ -1819,12 +1821,15 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn const prev_rvalue_noresult = parent_gz.rvalue_noresult; parent_gz.rvalue_noresult = .none; const operand = try reachableExpr(parent_gz, parent_scope, block_gz.break_result_loc, rhs, node); + const search_index = @intCast(Zir.Inst.Index, astgen.instructions.len); parent_gz.rvalue_noresult = prev_rvalue_noresult; + try genDefers(parent_gz, scope, parent_scope, .normal_only); + switch (block_gz.break_result_loc) { .block_ptr => { const br = try parent_gz.addBreak(break_tag, block_inst, operand); - try block_gz.labeled_breaks.append(astgen.gpa, br); + try block_gz.labeled_breaks.append(astgen.gpa, .{ .br = br, .search = search_index }); }, .ptr => { // In this case we don't have any mechanism to intercept it; @@ -1843,13 +1848,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn .local_val => scope = scope.cast(Scope.LocalVal).?.parent, .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, .namespace => break, - .defer_normal => { - const defer_scope = scope.cast(Scope.Defer).?; - scope = defer_scope.parent; - const expr_node = node_datas[defer_scope.defer_node].rhs; - try unusedResultDeferExpr(parent_gz, defer_scope, defer_scope.parent, expr_node); - }, - .defer_error => scope = scope.cast(Scope.Defer).?.parent, + .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, .top => unreachable, } } @@ -2030,7 +2029,7 @@ fn labeledBlockExpr( // The code took advantage of the result location as a pointer. // Turn the break instruction operands into void. for (block_scope.labeled_breaks.items) |br| { - zir_datas[br].@"break".operand = .void_value; + zir_datas[br.br].@"break".operand = .void_value; } try block_scope.setBlockBody(block_inst); @@ -2047,17 +2046,17 @@ fn labeledBlockExpr( for (block_scope.labeled_breaks.items) |br| { // We expect the `store_to_block_ptr` to be created between 1-3 instructions // prior to the break. - var search_index = br -| 3; - while (search_index < br) : (search_index += 1) { + var search_index = br.search -| 3; + while (search_index < br.search) : (search_index += 1) { if (zir_tags[search_index] == .store_to_block_ptr and zir_datas[search_index].bin.lhs == block_scope.rl_ptr) { zir_tags[search_index] = .as; zir_datas[search_index].bin = .{ .lhs = block_scope.rl_ty_inst, - .rhs = zir_datas[br].@"break".operand, + .rhs = zir_datas[br.br].@"break".operand, }; - zir_datas[br].@"break".operand = indexToRef(search_index); + zir_datas[br.br].@"break".operand = indexToRef(search_index); break; } } else unreachable; @@ -9719,7 +9718,7 @@ const GenZir = struct { break_count: usize = 0, /// Tracks `break :foo bar` instructions so they can possibly be elided later if /// the labeled block ends up not needing a result location pointer. - labeled_breaks: ArrayListUnmanaged(Zir.Inst.Index) = .{}, + labeled_breaks: ArrayListUnmanaged(struct { br: Zir.Inst.Index, search: Zir.Inst.Index }) = .{}, suspend_node: Ast.Node.Index = 0, nosuspend_node: Ast.Node.Index = 0, diff --git a/src/clang.zig b/src/clang.zig index 4c07c00226..64c7da5091 100644 --- a/src/clang.zig +++ b/src/clang.zig @@ -161,7 +161,12 @@ pub const ASTUnit = opaque { extern fn ZigClangASTUnit_getSourceManager(*ASTUnit) *SourceManager; pub const visitLocalTopLevelDecls = ZigClangASTUnit_visitLocalTopLevelDecls; - extern fn ZigClangASTUnit_visitLocalTopLevelDecls(*ASTUnit, context: ?*anyopaque, Fn: ?fn (?*anyopaque, *const Decl) callconv(.C) bool) bool; + extern fn ZigClangASTUnit_visitLocalTopLevelDecls(*ASTUnit, context: ?*anyopaque, Fn: ?VisitorFn) bool; + + const VisitorFn = if (@import("builtin").zig_backend == .stage1) + fn (?*anyopaque, *const Decl) callconv(.C) bool + else + *const fn (?*anyopaque, *const Decl) callconv(.C) bool; pub const getLocalPreprocessingEntities_begin = ZigClangASTUnit_getLocalPreprocessingEntities_begin; extern fn ZigClangASTUnit_getLocalPreprocessingEntities_begin(*ASTUnit) PreprocessingRecord.iterator; @@ -490,8 +495,8 @@ pub const FloatingLiteral = opaque { pub const getValueAsApproximateDouble = ZigClangFloatingLiteral_getValueAsApproximateDouble; extern fn ZigClangFloatingLiteral_getValueAsApproximateDouble(*const FloatingLiteral) f64; - pub const getBeginLoc = ZigClangIntegerLiteral_getBeginLoc; - extern fn ZigClangIntegerLiteral_getBeginLoc(*const FloatingLiteral) SourceLocation; + pub const getBeginLoc = ZigClangFloatingLiteral_getBeginLoc; + extern fn ZigClangFloatingLiteral_getBeginLoc(*const FloatingLiteral) SourceLocation; pub const getRawSemantics = ZigClangFloatingLiteral_getRawSemantics; extern fn ZigClangFloatingLiteral_getRawSemantics(*const FloatingLiteral) APFloatBaseSemantics; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index a9e1cb160b..364cccf335 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4732,10 +4732,11 @@ pub const FuncGen = struct { var buf: Type.Payload.ElemType = undefined; const payload_ty = optional_ty.optionalChild(&buf); if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { + const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand; if (invert) { - return self.builder.buildNot(operand, ""); + return self.builder.buildNot(loaded, ""); } else { - return operand; + return loaded; } } @@ -4784,12 +4785,16 @@ pub const FuncGen = struct { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const operand = try self.resolveInst(ty_op.operand); const optional_ty = self.air.typeOf(ty_op.operand).childType(); + const result_ty = self.air.getRefType(ty_op.ty); var buf: Type.Payload.ElemType = undefined; const payload_ty = optional_ty.optionalChild(&buf); if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { // We have a pointer to a zero-bit value and we need to return // a pointer to a zero-bit value. - return operand; + + // TODO once we update to LLVM 14 this bitcast won't be necessary. + const res_ptr_ty = try self.dg.llvmType(result_ty); + return self.builder.buildBitCast(operand, res_ptr_ty, ""); } if (optional_ty.isPtrLikeOptional()) { // The payload and the optional are the same value. @@ -4807,13 +4812,17 @@ pub const FuncGen = struct { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const operand = try self.resolveInst(ty_op.operand); const optional_ty = self.air.typeOf(ty_op.operand).childType(); + const result_ty = self.air.getRefType(ty_op.ty); var buf: Type.Payload.ElemType = undefined; const payload_ty = optional_ty.optionalChild(&buf); const non_null_bit = self.context.intType(1).constAllOnes(); if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { // We have a pointer to a i1. We need to set it to 1 and then return the same pointer. _ = self.builder.buildStore(non_null_bit, operand); - return operand; + + // TODO once we update to LLVM 14 this bitcast won't be necessary. + const res_ptr_ty = try self.dg.llvmType(result_ty); + return self.builder.buildBitCast(operand, res_ptr_ty, ""); } if (optional_ty.isPtrLikeOptional()) { // The payload and the optional are the same value. @@ -4872,7 +4881,13 @@ pub const FuncGen = struct { const target = self.dg.module.getTarget(); const offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1; - if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null; + if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { + if (!operand_is_ptr) return null; + + // TODO once we update to LLVM 14 this bitcast won't be necessary. + const res_ptr_ty = try self.dg.llvmType(result_ty); + return self.builder.buildBitCast(operand, res_ptr_ty, ""); + } if (operand_is_ptr or isByRef(payload_ty)) { return self.builder.buildStructGEP(operand, offset, ""); } @@ -7205,7 +7220,7 @@ pub const FuncGen = struct { return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, ""); } - fn getIntrinsic(self: *FuncGen, name: []const u8, types: []*const llvm.Type) *const llvm.Value { + fn getIntrinsic(self: *FuncGen, name: []const u8, types: []const *const llvm.Type) *const llvm.Value { const id = llvm.lookupIntrinsicID(name.ptr, name.len); assert(id != 0); return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len); diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index b799d649b0..3863385a06 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -60,7 +60,7 @@ pub const Context = opaque { Packed: Bool, ) *const Type; - const structCreateNamed = LLVMStructCreateNamed; + pub const structCreateNamed = LLVMStructCreateNamed; extern fn LLVMStructCreateNamed(C: *const Context, Name: [*:0]const u8) *const Type; pub const constString = LLVMConstStringInContext; @@ -320,7 +320,7 @@ pub const Module = opaque { extern fn LLVMGetNamedFunction(*const Module, Name: [*:0]const u8) ?*const Value; pub const getIntrinsicDeclaration = LLVMGetIntrinsicDeclaration; - extern fn LLVMGetIntrinsicDeclaration(Mod: *const Module, ID: c_uint, ParamTypes: ?[*]*const Type, ParamCount: usize) *const Value; + extern fn LLVMGetIntrinsicDeclaration(Mod: *const Module, ID: c_uint, ParamTypes: ?[*]const *const Type, ParamCount: usize) *const Value; pub const printToString = LLVMPrintModuleToString; extern fn LLVMPrintModuleToString(*const Module) [*:0]const u8; diff --git a/src/translate_c.zig b/src/translate_c.zig index 39733dd246..72e0cabaf8 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -368,11 +368,13 @@ pub fn translate( resources_path: [*:0]const u8, zig_is_stage1: bool, ) !std.zig.Ast { + // TODO stage2 bug + var tmp = errors; const ast_unit = clang.LoadFromCommandLine( args_begin, args_end, - &errors.ptr, - &errors.len, + &tmp.ptr, + &tmp.len, resources_path, ) orelse { if (errors.len == 0) return error.ASTUnitFailure; @@ -5325,7 +5327,7 @@ const MacroCtx = struct { try self.fail( c, "unable to translate C expr: expected '{s}' instead got '{s}'", - .{ CToken.Id.symbol(expected_id), next_id.symbol() }, + .{ CToken.Id.symbolName(expected_id), next_id.symbol() }, ); return error.ParseError; } diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 66c2406187..3e30b33abc 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -779,7 +779,7 @@ const TokenTag = std.zig.Token.Tag; const Context = struct { gpa: Allocator, - buf: std.ArrayList(u8) = .{}, + buf: std.ArrayList(u8), nodes: std.zig.Ast.NodeList = .{}, extra_data: std.ArrayListUnmanaged(std.zig.Ast.Node.Index) = .{}, tokens: std.zig.Ast.TokenList = .{}, diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 578548dfd4..ea3f09c8d5 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -2706,6 +2706,11 @@ double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatin return casted->getValueAsApproximateDouble(); } +struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getBeginLoc()); +} + ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self) { auto casted = reinterpret_cast(self); return static_cast(casted->getRawSemantics()); diff --git a/src/zig_clang.h b/src/zig_clang.h index 85a0aa5dbb..12eda66d07 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -1245,6 +1245,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST, unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM); ZIG_EXTERN_C double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *); ZIG_EXTERN_C ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self); ZIG_EXTERN_C enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self); diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 9956c3f3ec..6219a6a5be 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -332,3 +332,42 @@ test "array of optional unaligned types" { i += 1; try expect(Enum.three == values[i].?.Num); } + +test "optional pointer to zero bit optional payload" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const B = struct { + fn foo(_: *@This()) void {} + }; + const A = struct { + b: ?B = .{}, + }; + var a: A = .{}; + var a_ptr = &a; + if (a_ptr.b) |*some| { + some.foo(); + } +} + +test "optional pointer to zero bit error union payload" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + const B = struct { + fn foo(_: *@This()) void {} + }; + const A = struct { + b: anyerror!B = .{}, + }; + var a: A = .{}; + var a_ptr = &a; + if (a_ptr.b) |*some| { + some.foo(); + } else |_| {} +}