authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-27 22:09:17-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-27 22:09:17-04:00
log2991e4a454c4d719226fcfc7e8ac8dec44250a7e
tree2d0abcbd613008f7c07aae6bcad1b656bffb1f4f
parentbc72ae5e4e6d8f2253aed1316b053ad1022f9f67
parent648d34d8eacaf2e35e336abd5b0c50c2ab9bfc94
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13288 from Vexu/opt-slice

Optimize size of optional slices (+ some fixes)

17 files changed, 260 insertions(+), 186 deletions(-)

lib/std/mem/Allocator.zig+6-3
...@@ -286,7 +286,8 @@ pub fn allocAdvancedWithRetAddr(...@@ -286,7 +286,8 @@ pub fn allocAdvancedWithRetAddr(
286 } else @alignOf(T);286 } else @alignOf(T);
287287
288 if (n == 0) {288 if (n == 0) {
289 return @as([*]align(a) T, undefined)[0..0];289 const ptr = comptime std.mem.alignBackward(std.math.maxInt(usize), a);
290 return @intToPtr([*]align(a) T, ptr)[0..0];
290 }291 }
291292
292 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;293 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
...@@ -383,7 +384,8 @@ pub fn reallocAdvancedWithRetAddr(...@@ -383,7 +384,8 @@ pub fn reallocAdvancedWithRetAddr(
383 }384 }
384 if (new_n == 0) {385 if (new_n == 0) {
385 self.free(old_mem);386 self.free(old_mem);
386 return @as([*]align(new_alignment) T, undefined)[0..0];387 const ptr = comptime std.mem.alignBackward(std.math.maxInt(usize), new_alignment);
388 return @intToPtr([*]align(new_alignment) T, ptr)[0..0];
387 }389 }
388390
389 const old_byte_slice = mem.sliceAsBytes(old_mem);391 const old_byte_slice = mem.sliceAsBytes(old_mem);
...@@ -462,7 +464,8 @@ pub fn alignedShrinkWithRetAddr(...@@ -462,7 +464,8 @@ pub fn alignedShrinkWithRetAddr(
462 return old_mem;464 return old_mem;
463 if (new_n == 0) {465 if (new_n == 0) {
464 self.free(old_mem);466 self.free(old_mem);
465 return @as([*]align(new_alignment) T, undefined)[0..0];467 const ptr = comptime std.mem.alignBackward(std.math.maxInt(usize), new_alignment);
468 return @intToPtr([*]align(new_alignment) T, ptr)[0..0];
466 }469 }
467470
468 assert(new_n < old_mem.len);471 assert(new_n < old_mem.len);
src/AstGen.zig+8-1
...@@ -9709,7 +9709,7 @@ fn rvalue(...@@ -9709,7 +9709,7 @@ fn rvalue(
9709 const result_index = refToIndex(result) orelse9709 const result_index = refToIndex(result) orelse
9710 return gz.addUnTok(.ref, result, src_token);9710 return gz.addUnTok(.ref, result, src_token);
9711 const zir_tags = gz.astgen.instructions.items(.tag);9711 const zir_tags = gz.astgen.instructions.items(.tag);
9712 if (zir_tags[result_index].isParam())9712 if (zir_tags[result_index].isParam() or astgen.isInferred(result))
9713 return gz.addUnTok(.ref, result, src_token);9713 return gz.addUnTok(.ref, result, src_token);
9714 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index);9714 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index);
9715 if (!gop.found_existing) {9715 if (!gop.found_existing) {
...@@ -12196,6 +12196,13 @@ fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool {...@@ -12196,6 +12196,13 @@ fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool {
12196 .alloc_inferred_comptime_mut,12196 .alloc_inferred_comptime_mut,
12197 => true,12197 => true,
1219812198
12199 .extended => {
12200 const zir_data = astgen.instructions.items(.data);
12201 if (zir_data[inst].extended.opcode != .alloc) return false;
12202 const small = @bitCast(Zir.Inst.AllocExtended.Small, zir_data[inst].extended.small);
12203 return !small.has_type;
12204 },
12205
12199 else => false,12206 else => false,
12200 };12207 };
12201}12208}
src/Sema.zig+45-17
...@@ -5053,6 +5053,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -5053,6 +5053,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
5053 .label = &label,5053 .label = &label,
5054 .inlining = parent_block.inlining,5054 .inlining = parent_block.inlining,
5055 .is_comptime = parent_block.is_comptime,5055 .is_comptime = parent_block.is_comptime,
5056 .is_typeof = parent_block.is_typeof,
5056 .want_safety = parent_block.want_safety,5057 .want_safety = parent_block.want_safety,
5057 .float_mode = parent_block.float_mode,5058 .float_mode = parent_block.float_mode,
5058 .runtime_cond = parent_block.runtime_cond,5059 .runtime_cond = parent_block.runtime_cond,
...@@ -5945,7 +5946,7 @@ fn zirCall(...@@ -5945,7 +5946,7 @@ fn zirCall(
59455946
5946 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;5947 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
5947 if (backend_supports_error_return_tracing and sema.mod.comp.bin_file.options.error_return_tracing and5948 if (backend_supports_error_return_tracing and sema.mod.comp.bin_file.options.error_return_tracing and
5948 !block.is_comptime and (input_is_error or pop_error_return_trace))5949 !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
5949 {5950 {
5950 const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {5951 const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {
5951 break :b try sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);5952 break :b try sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
...@@ -6425,7 +6426,7 @@ fn analyzeCall(...@@ -6425,7 +6426,7 @@ fn analyzeCall(
6425 }6426 }
64266427
6427 const new_func_resolved_ty = try Type.Tag.function.create(sema.arena, new_fn_info);6428 const new_func_resolved_ty = try Type.Tag.function.create(sema.arena, new_fn_info);
6428 if (!is_comptime_call) {6429 if (!is_comptime_call and !block.is_typeof) {
6429 try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin);6430 try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin);
64306431
6431 const zir_tags = sema.code.instructions.items(.tag);6432 const zir_tags = sema.code.instructions.items(.tag);
...@@ -6463,7 +6464,7 @@ fn analyzeCall(...@@ -6463,7 +6464,7 @@ fn analyzeCall(
6463 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);6464 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
6464 };6465 };
64656466
6466 if (!is_comptime_call and sema.typeOf(result).zigTypeTag() != .NoReturn) {6467 if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag() != .NoReturn) {
6467 try sema.emitDbgInline(6468 try sema.emitDbgInline(
6468 block,6469 block,
6469 module_fn,6470 module_fn,
...@@ -6747,6 +6748,8 @@ fn analyzeGenericCallArg(...@@ -6747,6 +6748,8 @@ fn analyzeGenericCallArg(
6747 try sema.queueFullTypeResolution(param_ty);6748 try sema.queueFullTypeResolution(param_ty);
6748 runtime_args[runtime_i.*] = casted_arg;6749 runtime_args[runtime_i.*] = casted_arg;
6749 runtime_i.* += 1;6750 runtime_i.* += 1;
6751 } else if (try sema.typeHasOnePossibleValue(block, arg_src, comptime_arg.ty)) |_| {
6752 _ = try sema.coerce(block, comptime_arg.ty, uncasted_arg, arg_src);
6750 }6753 }
6751}6754}
67526755
...@@ -10220,6 +10223,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10220,6 +10223,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10220 .label = &label,10223 .label = &label,
10221 .inlining = block.inlining,10224 .inlining = block.inlining,
10222 .is_comptime = block.is_comptime,10225 .is_comptime = block.is_comptime,
10226 .is_typeof = block.is_typeof,
10223 .switch_else_err_ty = else_error_ty,10227 .switch_else_err_ty = else_error_ty,
10224 .runtime_cond = block.runtime_cond,10228 .runtime_cond = block.runtime_cond,
10225 .runtime_loop = block.runtime_loop,10229 .runtime_loop = block.runtime_loop,
...@@ -16411,7 +16415,7 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -16411,7 +16415,7 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
16411 if (!ok) return;16415 if (!ok) return;
1641216416
16413 // This is only relevant at runtime.16417 // This is only relevant at runtime.
16414 if (block.is_comptime) return;16418 if (block.is_comptime or block.is_typeof) return;
1641516419
16416 // This is only relevant within functions.16420 // This is only relevant within functions.
16417 if (sema.func == null) return;16421 if (sema.func == null) return;
...@@ -16431,7 +16435,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index)...@@ -16431,7 +16435,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index)
16431 const src = sema.src; // TODO16435 const src = sema.src; // TODO
1643216436
16433 // This is only relevant at runtime.16437 // This is only relevant at runtime.
16434 if (start_block.is_comptime) return;16438 if (start_block.is_comptime or start_block.is_typeof) return;
1643516439
16436 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;16440 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
16437 const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and16441 const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and
...@@ -28357,8 +28361,16 @@ fn resolvePeerTypes(...@@ -28357,8 +28361,16 @@ fn resolvePeerTypes(
28357 const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison();28361 const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison();
28358 const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison();28362 const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison();
2835928363
28360 if (candidate_ty.eql(chosen_ty, sema.mod))28364 // If the candidate can coerce into our chosen type, we're done.
28365 // If the chosen type can coerce into the candidate, use that.
28366 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
28367 continue;
28368 }
28369 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
28370 chosen = candidate;
28371 chosen_i = candidate_i + 1;
28361 continue;28372 continue;
28373 }
2836228374
28363 switch (candidate_ty_tag) {28375 switch (candidate_ty_tag) {
28364 .NoReturn, .Undefined => continue,28376 .NoReturn, .Undefined => continue,
...@@ -28758,17 +28770,6 @@ fn resolvePeerTypes(...@@ -28758,17 +28770,6 @@ fn resolvePeerTypes(
28758 else => {},28770 else => {},
28759 }28771 }
2876028772
28761 // If the candidate can coerce into our chosen type, we're done.
28762 // If the chosen type can coerce into the candidate, use that.
28763 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
28764 continue;
28765 }
28766 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
28767 chosen = candidate;
28768 chosen_i = candidate_i + 1;
28769 continue;
28770 }
28771
28772 // At this point, we hit a compile error. We need to recover28773 // At this point, we hit a compile error. We need to recover
28773 // the source locations.28774 // the source locations.
28774 const chosen_src = candidate_srcs.resolve(28775 const chosen_src = candidate_srcs.resolve(
...@@ -29092,6 +29093,33 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi...@@ -29092,6 +29093,33 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
29092 struct_obj.backing_int_ty = try backing_int_ty.copy(decl_arena_allocator);29093 struct_obj.backing_int_ty = try backing_int_ty.copy(decl_arena_allocator);
29093 try wip_captures.finalize();29094 try wip_captures.finalize();
29094 } else {29095 } else {
29096 if (fields_bit_sum > std.math.maxInt(u16)) {
29097 var sema: Sema = .{
29098 .mod = mod,
29099 .gpa = gpa,
29100 .arena = undefined,
29101 .perm_arena = decl_arena_allocator,
29102 .code = zir,
29103 .owner_decl = decl,
29104 .owner_decl_index = decl_index,
29105 .func = null,
29106 .fn_ret_ty = Type.void,
29107 .owner_func = null,
29108 };
29109 defer sema.deinit();
29110
29111 var block: Block = .{
29112 .parent = null,
29113 .sema = &sema,
29114 .src_decl = decl_index,
29115 .namespace = &struct_obj.namespace,
29116 .wip_capture_scope = undefined,
29117 .instructions = .{},
29118 .inlining = null,
29119 .is_comptime = true,
29120 };
29121 return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});
29122 }
29095 var buf: Type.Payload.Bits = .{29123 var buf: Type.Payload.Bits = .{
29096 .base = .{ .tag = .int_unsigned },29124 .base = .{ .tag = .int_unsigned },
29097 .data = @intCast(u16, fields_bit_sum),29125 .data = @intCast(u16, fields_bit_sum),
src/codegen/c.zig+9-5
...@@ -730,7 +730,11 @@ pub const DeclGen = struct {...@@ -730,7 +730,11 @@ pub const DeclGen = struct {
730 }730 }
731731
732 if (ty.optionalReprIsPayload()) {732 if (ty.optionalReprIsPayload()) {
733 return dg.renderValue(writer, payload_ty, val, location);733 if (val.castTag(.opt_payload)) |payload| {
734 return dg.renderValue(writer, payload_ty, payload.data, location);
735 } else {
736 return dg.renderValue(writer, payload_ty, val, location);
737 }
734 }738 }
735739
736 try writer.writeByte('(');740 try writer.writeByte('(');
...@@ -3267,11 +3271,9 @@ fn airIsNull(...@@ -3267,11 +3271,9 @@ fn airIsNull(
3267 try f.writeCValue(writer, operand);3271 try f.writeCValue(writer, operand);
32683272
3269 const ty = f.air.typeOf(un_op);3273 const ty = f.air.typeOf(un_op);
3274 const opt_ty = if (deref_suffix[0] != 0) ty.childType() else ty;
3270 var opt_buf: Type.Payload.ElemType = undefined;3275 var opt_buf: Type.Payload.ElemType = undefined;
3271 const payload_ty = if (deref_suffix[0] != 0)3276 const payload_ty = opt_ty.optionalChild(&opt_buf);
3272 ty.childType().optionalChild(&opt_buf)
3273 else
3274 ty.optionalChild(&opt_buf);
32753277
3276 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {3278 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3277 try writer.print("){s} {s} true;\n", .{ deref_suffix, operator });3279 try writer.print("){s} {s} true;\n", .{ deref_suffix, operator });
...@@ -3280,6 +3282,8 @@ fn airIsNull(...@@ -3280,6 +3282,8 @@ fn airIsNull(
3280 try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });3282 try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });
3281 } else if (payload_ty.zigTypeTag() == .ErrorSet) {3283 } else if (payload_ty.zigTypeTag() == .ErrorSet) {
3282 try writer.print("){s} {s} 0;\n", .{ deref_suffix, operator });3284 try writer.print("){s} {s} 0;\n", .{ deref_suffix, operator });
3285 } else if (payload_ty.isSlice() and opt_ty.optionalReprIsPayload()) {
3286 try writer.print("){s}.ptr {s} NULL;\n", .{ deref_suffix, operator });
3283 } else {3287 } else {
3284 try writer.print("){s}.is_null {s} true;\n", .{ deref_suffix, operator });3288 try writer.print("){s}.is_null {s} true;\n", .{ deref_suffix, operator });
3285 }3289 }
src/codegen/llvm.zig+22-8
...@@ -1027,7 +1027,9 @@ pub const Object = struct {...@@ -1027,7 +1027,9 @@ pub const Object = struct {
1027 dg.addArgAttr(llvm_func, llvm_arg_i, "noalias");1027 dg.addArgAttr(llvm_func, llvm_arg_i, "noalias");
1028 }1028 }
1029 }1029 }
1030 dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull");1030 if (param_ty.zigTypeTag() != .Optional) {
1031 dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
1032 }
1031 if (!ptr_info.mutable) {1033 if (!ptr_info.mutable) {
1032 dg.addArgAttr(llvm_func, llvm_arg_i, "readonly");1034 dg.addArgAttr(llvm_func, llvm_arg_i, "readonly");
1033 }1035 }
...@@ -1916,7 +1918,7 @@ pub const Object = struct {...@@ -1916,7 +1918,7 @@ pub const Object = struct {
19161918
1917 if (ty.castTag(.@"struct")) |payload| {1919 if (ty.castTag(.@"struct")) |payload| {
1918 const struct_obj = payload.data;1920 const struct_obj = payload.data;
1919 if (struct_obj.layout == .Packed) {1921 if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) {
1920 const info = struct_obj.backing_int_ty.intInfo(target);1922 const info = struct_obj.backing_int_ty.intInfo(target);
1921 const dwarf_encoding: c_uint = switch (info.signedness) {1923 const dwarf_encoding: c_uint = switch (info.signedness) {
1922 .signed => DW.ATE.signed,1924 .signed => DW.ATE.signed,
...@@ -3117,7 +3119,11 @@ pub const DeclGen = struct {...@@ -3117,7 +3119,11 @@ pub const DeclGen = struct {
3117 .slice => {3119 .slice => {
3118 const param_ty = fn_info.param_types[it.zig_index - 1];3120 const param_ty = fn_info.param_types[it.zig_index - 1];
3119 var buf: Type.SlicePtrFieldTypeBuffer = undefined;3121 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
3120 const ptr_ty = param_ty.slicePtrFieldType(&buf);3122 var opt_buf: Type.Payload.ElemType = undefined;
3123 const ptr_ty = if (param_ty.zigTypeTag() == .Optional)
3124 param_ty.optionalChild(&opt_buf).slicePtrFieldType(&buf)
3125 else
3126 param_ty.slicePtrFieldType(&buf);
3121 const ptr_llvm_ty = try dg.lowerType(ptr_ty);3127 const ptr_llvm_ty = try dg.lowerType(ptr_ty);
3122 const len_llvm_ty = try dg.lowerType(Type.usize);3128 const len_llvm_ty = try dg.lowerType(Type.usize);
31233129
...@@ -5438,10 +5444,11 @@ pub const FuncGen = struct {...@@ -5438,10 +5444,11 @@ pub const FuncGen = struct {
5438 const llvm_usize = try self.dg.lowerType(Type.usize);5444 const llvm_usize = try self.dg.lowerType(Type.usize);
5439 const len = llvm_usize.constInt(array_ty.arrayLen(), .False);5445 const len = llvm_usize.constInt(array_ty.arrayLen(), .False);
5440 const slice_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));5446 const slice_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
5447 const operand = try self.resolveInst(ty_op.operand);
5441 if (!array_ty.hasRuntimeBitsIgnoreComptime()) {5448 if (!array_ty.hasRuntimeBitsIgnoreComptime()) {
5442 return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");5449 const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), operand, 0, "");
5450 return self.builder.buildInsertValue(partial, len, 1, "");
5443 }5451 }
5444 const operand = try self.resolveInst(ty_op.operand);
5445 const indices: [2]*llvm.Value = .{5452 const indices: [2]*llvm.Value = .{
5446 llvm_usize.constNull(), llvm_usize.constNull(),5453 llvm_usize.constNull(), llvm_usize.constNull(),
5447 };5454 };
...@@ -6320,18 +6327,24 @@ pub const FuncGen = struct {...@@ -6320,18 +6327,24 @@ pub const FuncGen = struct {
6320 const operand_ty = self.air.typeOf(un_op);6327 const operand_ty = self.air.typeOf(un_op);
6321 const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;6328 const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
6322 const optional_llvm_ty = try self.dg.lowerType(optional_ty);6329 const optional_llvm_ty = try self.dg.lowerType(optional_ty);
6330 var buf: Type.Payload.ElemType = undefined;
6331 const payload_ty = optional_ty.optionalChild(&buf);
6323 if (optional_ty.optionalReprIsPayload()) {6332 if (optional_ty.optionalReprIsPayload()) {
6324 const loaded = if (operand_is_ptr)6333 const loaded = if (operand_is_ptr)
6325 self.builder.buildLoad(optional_llvm_ty, operand, "")6334 self.builder.buildLoad(optional_llvm_ty, operand, "")
6326 else6335 else
6327 operand;6336 operand;
6337 if (payload_ty.isSlice()) {
6338 const slice_ptr = self.builder.buildExtractValue(loaded, 0, "");
6339 var slice_buf: Type.SlicePtrFieldTypeBuffer = undefined;
6340 const ptr_ty = try self.dg.lowerType(payload_ty.slicePtrFieldType(&slice_buf));
6341 return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), "");
6342 }
6328 return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");6343 return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");
6329 }6344 }
63306345
6331 comptime assert(optional_layout_version == 3);6346 comptime assert(optional_layout_version == 3);
63326347
6333 var buf: Type.Payload.ElemType = undefined;
6334 const payload_ty = optional_ty.optionalChild(&buf);
6335 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {6348 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
6336 const loaded = if (operand_is_ptr)6349 const loaded = if (operand_is_ptr)
6337 self.builder.buildLoad(optional_llvm_ty, operand, "")6350 self.builder.buildLoad(optional_llvm_ty, operand, "")
...@@ -10355,7 +10368,8 @@ const ParamTypeIterator = struct {...@@ -10355,7 +10368,8 @@ const ParamTypeIterator = struct {
10355 .Unspecified, .Inline => {10368 .Unspecified, .Inline => {
10356 it.zig_index += 1;10369 it.zig_index += 1;
10357 it.llvm_index += 1;10370 it.llvm_index += 1;
10358 if (ty.isSlice()) {10371 var buf: Type.Payload.ElemType = undefined;
10372 if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) {
10359 return .slice;10373 return .slice;
10360 } else if (isByRef(ty)) {10374 } else if (isByRef(ty)) {
10361 return .byref;10375 return .byref;
src/translate_c.zig+79-110
...@@ -224,8 +224,7 @@ const Scope = struct {...@@ -224,8 +224,7 @@ const Scope = struct {
224 }224 }
225 }225 }
226226
227 fn findBlockReturnType(inner: *Scope, c: *Context) clang.QualType {227 fn findBlockReturnType(inner: *Scope) clang.QualType {
228 _ = c;
229 var scope = inner;228 var scope = inner;
230 while (true) {229 while (true) {
231 switch (scope.id) {230 switch (scope.id) {
...@@ -833,7 +832,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co...@@ -833,7 +832,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
833 if (has_init) trans_init: {832 if (has_init) trans_init: {
834 if (decl_init) |expr| {833 if (decl_init) |expr| {
835 const node_or_error = if (expr.getStmtClass() == .StringLiteralClass)834 const node_or_error = if (expr.getStmtClass() == .StringLiteralClass)
836 transStringLiteralInitializer(c, scope, @ptrCast(*const clang.StringLiteral, expr), type_node)835 transStringLiteralInitializer(c, @ptrCast(*const clang.StringLiteral, expr), type_node)
837 else836 else
838 transExprCoercing(c, scope, expr, .used);837 transExprCoercing(c, scope, expr, .used);
839 init_node = node_or_error catch |err| switch (err) {838 init_node = node_or_error catch |err| switch (err) {
...@@ -1319,10 +1318,10 @@ fn transStmt(...@@ -1319,10 +1318,10 @@ fn transStmt(
1319 .StringLiteralClass => return transStringLiteral(c, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used),1318 .StringLiteralClass => return transStringLiteral(c, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used),
1320 .ParenExprClass => {1319 .ParenExprClass => {
1321 const expr = try transExpr(c, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used);1320 const expr = try transExpr(c, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used);
1322 return maybeSuppressResult(c, scope, result_used, expr);1321 return maybeSuppressResult(c, result_used, expr);
1323 },1322 },
1324 .InitListExprClass => return transInitListExpr(c, scope, @ptrCast(*const clang.InitListExpr, stmt), result_used),1323 .InitListExprClass => return transInitListExpr(c, scope, @ptrCast(*const clang.InitListExpr, stmt), result_used),
1325 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(c, scope, @ptrCast(*const clang.Expr, stmt), result_used),1324 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(c, scope, @ptrCast(*const clang.Expr, stmt)),
1326 .IfStmtClass => return transIfStmt(c, scope, @ptrCast(*const clang.IfStmt, stmt)),1325 .IfStmtClass => return transIfStmt(c, scope, @ptrCast(*const clang.IfStmt, stmt)),
1327 .WhileStmtClass => return transWhileLoop(c, scope, @ptrCast(*const clang.WhileStmt, stmt)),1326 .WhileStmtClass => return transWhileLoop(c, scope, @ptrCast(*const clang.WhileStmt, stmt)),
1328 .DoStmtClass => return transDoWhileLoop(c, scope, @ptrCast(*const clang.DoStmt, stmt)),1327 .DoStmtClass => return transDoWhileLoop(c, scope, @ptrCast(*const clang.DoStmt, stmt)),
...@@ -1332,7 +1331,7 @@ fn transStmt(...@@ -1332,7 +1331,7 @@ fn transStmt(
1332 .ContinueStmtClass => return Tag.@"continue".init(),1331 .ContinueStmtClass => return Tag.@"continue".init(),
1333 .BreakStmtClass => return Tag.@"break".init(),1332 .BreakStmtClass => return Tag.@"break".init(),
1334 .ForStmtClass => return transForLoop(c, scope, @ptrCast(*const clang.ForStmt, stmt)),1333 .ForStmtClass => return transForLoop(c, scope, @ptrCast(*const clang.ForStmt, stmt)),
1335 .FloatingLiteralClass => return transFloatingLiteral(c, scope, @ptrCast(*const clang.FloatingLiteral, stmt), result_used),1334 .FloatingLiteralClass => return transFloatingLiteral(c, @ptrCast(*const clang.FloatingLiteral, stmt), result_used),
1336 .ConditionalOperatorClass => {1335 .ConditionalOperatorClass => {
1337 return transConditionalOperator(c, scope, @ptrCast(*const clang.ConditionalOperator, stmt), result_used);1336 return transConditionalOperator(c, scope, @ptrCast(*const clang.ConditionalOperator, stmt), result_used);
1338 },1337 },
...@@ -1356,9 +1355,9 @@ fn transStmt(...@@ -1356,9 +1355,9 @@ fn transStmt(
1356 .OpaqueValueExprClass => {1355 .OpaqueValueExprClass => {
1357 const source_expr = @ptrCast(*const clang.OpaqueValueExpr, stmt).getSourceExpr().?;1356 const source_expr = @ptrCast(*const clang.OpaqueValueExpr, stmt).getSourceExpr().?;
1358 const expr = try transExpr(c, scope, source_expr, .used);1357 const expr = try transExpr(c, scope, source_expr, .used);
1359 return maybeSuppressResult(c, scope, result_used, expr);1358 return maybeSuppressResult(c, result_used, expr);
1360 },1359 },
1361 .OffsetOfExprClass => return transOffsetOfExpr(c, scope, @ptrCast(*const clang.OffsetOfExpr, stmt), result_used),1360 .OffsetOfExprClass => return transOffsetOfExpr(c, @ptrCast(*const clang.OffsetOfExpr, stmt), result_used),
1362 .CompoundLiteralExprClass => {1361 .CompoundLiteralExprClass => {
1363 const compound_literal = @ptrCast(*const clang.CompoundLiteralExpr, stmt);1362 const compound_literal = @ptrCast(*const clang.CompoundLiteralExpr, stmt);
1364 return transExpr(c, scope, compound_literal.getInitializer(), result_used);1363 return transExpr(c, scope, compound_literal.getInitializer(), result_used);
...@@ -1369,13 +1368,13 @@ fn transStmt(...@@ -1369,13 +1368,13 @@ fn transStmt(
1369 },1368 },
1370 .ConvertVectorExprClass => {1369 .ConvertVectorExprClass => {
1371 const conv_vec = @ptrCast(*const clang.ConvertVectorExpr, stmt);1370 const conv_vec = @ptrCast(*const clang.ConvertVectorExpr, stmt);
1372 const conv_vec_node = try transConvertVectorExpr(c, scope, stmt.getBeginLoc(), conv_vec);1371 const conv_vec_node = try transConvertVectorExpr(c, scope, conv_vec);
1373 return maybeSuppressResult(c, scope, result_used, conv_vec_node);1372 return maybeSuppressResult(c, result_used, conv_vec_node);
1374 },1373 },
1375 .ShuffleVectorExprClass => {1374 .ShuffleVectorExprClass => {
1376 const shuffle_vec_expr = @ptrCast(*const clang.ShuffleVectorExpr, stmt);1375 const shuffle_vec_expr = @ptrCast(*const clang.ShuffleVectorExpr, stmt);
1377 const shuffle_vec_node = try transShuffleVectorExpr(c, scope, shuffle_vec_expr);1376 const shuffle_vec_node = try transShuffleVectorExpr(c, scope, shuffle_vec_expr);
1378 return maybeSuppressResult(c, scope, result_used, shuffle_vec_node);1377 return maybeSuppressResult(c, result_used, shuffle_vec_node);
1379 },1378 },
1380 .ChooseExprClass => {1379 .ChooseExprClass => {
1381 const choose_expr = @ptrCast(*const clang.ChooseExpr, stmt);1380 const choose_expr = @ptrCast(*const clang.ChooseExpr, stmt);
...@@ -1402,10 +1401,8 @@ fn transStmt(...@@ -1402,10 +1401,8 @@ fn transStmt(
1402fn transConvertVectorExpr(1401fn transConvertVectorExpr(
1403 c: *Context,1402 c: *Context,
1404 scope: *Scope,1403 scope: *Scope,
1405 source_loc: clang.SourceLocation,
1406 expr: *const clang.ConvertVectorExpr,1404 expr: *const clang.ConvertVectorExpr,
1407) TransError!Node {1405) TransError!Node {
1408 _ = source_loc;
1409 const base_stmt = @ptrCast(*const clang.Stmt, expr);1406 const base_stmt = @ptrCast(*const clang.Stmt, expr);
14101407
1411 var block_scope = try Scope.Block.init(c, scope, true);1408 var block_scope = try Scope.Block.init(c, scope, true);
...@@ -1521,12 +1518,7 @@ fn transShuffleVectorExpr(...@@ -1521,12 +1518,7 @@ fn transShuffleVectorExpr(
15211518
1522/// Translate a "simple" offsetof expression containing exactly one component,1519/// Translate a "simple" offsetof expression containing exactly one component,
1523/// when that component is of kind .Field - e.g. offsetof(mytype, myfield)1520/// when that component is of kind .Field - e.g. offsetof(mytype, myfield)
1524fn transSimpleOffsetOfExpr(1521fn transSimpleOffsetOfExpr(c: *Context, expr: *const clang.OffsetOfExpr) TransError!Node {
1525 c: *Context,
1526 scope: *Scope,
1527 expr: *const clang.OffsetOfExpr,
1528) TransError!Node {
1529 _ = scope;
1530 assert(expr.getNumComponents() == 1);1522 assert(expr.getNumComponents() == 1);
1531 const component = expr.getComponent(0);1523 const component = expr.getComponent(0);
1532 if (component.getKind() == .Field) {1524 if (component.getKind() == .Field) {
...@@ -1551,13 +1543,12 @@ fn transSimpleOffsetOfExpr(...@@ -1551,13 +1543,12 @@ fn transSimpleOffsetOfExpr(
15511543
1552fn transOffsetOfExpr(1544fn transOffsetOfExpr(
1553 c: *Context,1545 c: *Context,
1554 scope: *Scope,
1555 expr: *const clang.OffsetOfExpr,1546 expr: *const clang.OffsetOfExpr,
1556 result_used: ResultUsed,1547 result_used: ResultUsed,
1557) TransError!Node {1548) TransError!Node {
1558 if (expr.getNumComponents() == 1) {1549 if (expr.getNumComponents() == 1) {
1559 const offsetof_expr = try transSimpleOffsetOfExpr(c, scope, expr);1550 const offsetof_expr = try transSimpleOffsetOfExpr(c, expr);
1560 return maybeSuppressResult(c, scope, result_used, offsetof_expr);1551 return maybeSuppressResult(c, result_used, offsetof_expr);
1561 }1552 }
15621553
1563 // TODO implement OffsetOfExpr with more than 1 component1554 // TODO implement OffsetOfExpr with more than 1 component
...@@ -1613,7 +1604,6 @@ fn transCreatePointerArithmeticSignedOp(...@@ -1613,7 +1604,6 @@ fn transCreatePointerArithmeticSignedOp(
16131604
1614 return transCreateNodeInfixOp(1605 return transCreateNodeInfixOp(
1615 c,1606 c,
1616 scope,
1617 if (is_add) .add else .sub,1607 if (is_add) .add else .sub,
1618 lhs_node,1608 lhs_node,
1619 bitcast_node,1609 bitcast_node,
...@@ -1629,7 +1619,7 @@ fn transBinaryOperator(...@@ -1629,7 +1619,7 @@ fn transBinaryOperator(
1629) TransError!Node {1619) TransError!Node {
1630 const op = stmt.getOpcode();1620 const op = stmt.getOpcode();
1631 const qt = stmt.getType();1621 const qt = stmt.getType();
1632 const isPointerDiffExpr = cIsPointerDiffExpr(c, stmt);1622 const isPointerDiffExpr = cIsPointerDiffExpr(stmt);
1633 switch (op) {1623 switch (op) {
1634 .Assign => return try transCreateNodeAssign(c, scope, result_used, stmt.getLHS(), stmt.getRHS()),1624 .Assign => return try transCreateNodeAssign(c, scope, result_used, stmt.getLHS(), stmt.getRHS()),
1635 .Comma => {1625 .Comma => {
...@@ -1646,7 +1636,7 @@ fn transBinaryOperator(...@@ -1646,7 +1636,7 @@ fn transBinaryOperator(
1646 });1636 });
1647 try block_scope.statements.append(break_node);1637 try block_scope.statements.append(break_node);
1648 const block_node = try block_scope.complete(c);1638 const block_node = try block_scope.complete(c);
1649 return maybeSuppressResult(c, scope, result_used, block_node);1639 return maybeSuppressResult(c, result_used, block_node);
1650 },1640 },
1651 .Div => {1641 .Div => {
1652 if (cIsSignedInteger(qt)) {1642 if (cIsSignedInteger(qt)) {
...@@ -1654,7 +1644,7 @@ fn transBinaryOperator(...@@ -1654,7 +1644,7 @@ fn transBinaryOperator(
1654 const lhs = try transExpr(c, scope, stmt.getLHS(), .used);1644 const lhs = try transExpr(c, scope, stmt.getLHS(), .used);
1655 const rhs = try transExpr(c, scope, stmt.getRHS(), .used);1645 const rhs = try transExpr(c, scope, stmt.getRHS(), .used);
1656 const div_trunc = try Tag.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs });1646 const div_trunc = try Tag.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
1657 return maybeSuppressResult(c, scope, result_used, div_trunc);1647 return maybeSuppressResult(c, result_used, div_trunc);
1658 }1648 }
1659 },1649 },
1660 .Rem => {1650 .Rem => {
...@@ -1663,7 +1653,7 @@ fn transBinaryOperator(...@@ -1663,7 +1653,7 @@ fn transBinaryOperator(
1663 const lhs = try transExpr(c, scope, stmt.getLHS(), .used);1653 const lhs = try transExpr(c, scope, stmt.getLHS(), .used);
1664 const rhs = try transExpr(c, scope, stmt.getRHS(), .used);1654 const rhs = try transExpr(c, scope, stmt.getRHS(), .used);
1665 const rem = try Tag.signed_remainder.create(c.arena, .{ .lhs = lhs, .rhs = rhs });1655 const rem = try Tag.signed_remainder.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
1666 return maybeSuppressResult(c, scope, result_used, rem);1656 return maybeSuppressResult(c, result_used, rem);
1667 }1657 }
1668 },1658 },
1669 .Shl => {1659 .Shl => {
...@@ -1764,7 +1754,7 @@ fn transBinaryOperator(...@@ -1764,7 +1754,7 @@ fn transBinaryOperator(
1764 else1754 else
1765 rhs_uncasted;1755 rhs_uncasted;
17661756
1767 const infixOpNode = try transCreateNodeInfixOp(c, scope, op_id, lhs, rhs, result_used);1757 const infixOpNode = try transCreateNodeInfixOp(c, op_id, lhs, rhs, result_used);
1768 if (isPointerDiffExpr) {1758 if (isPointerDiffExpr) {
1769 // @divExact(@bitCast(<platform-ptrdiff_t>, @ptrToInt(lhs) -% @ptrToInt(rhs)), @sizeOf(<lhs target type>))1759 // @divExact(@bitCast(<platform-ptrdiff_t>, @ptrToInt(lhs) -% @ptrToInt(rhs)), @sizeOf(<lhs target type>))
1770 const ptrdiff_type = try transQualTypeIntWidthOf(c, qt, true);1760 const ptrdiff_type = try transQualTypeIntWidthOf(c, qt, true);
...@@ -1843,7 +1833,7 @@ fn transCStyleCastExprClass(...@@ -1843,7 +1833,7 @@ fn transCStyleCastExprClass(
1843 src_type,1833 src_type,
1844 sub_expr_node,1834 sub_expr_node,
1845 ));1835 ));
1846 return maybeSuppressResult(c, scope, result_used, cast_node);1836 return maybeSuppressResult(c, result_used, cast_node);
1847}1837}
18481838
1849/// The alignment of a variable or field1839/// The alignment of a variable or field
...@@ -1933,7 +1923,7 @@ fn transDeclStmtOne(...@@ -1933,7 +1923,7 @@ fn transDeclStmtOne(
19331923
1934 var init_node = if (decl_init) |expr|1924 var init_node = if (decl_init) |expr|
1935 if (expr.getStmtClass() == .StringLiteralClass)1925 if (expr.getStmtClass() == .StringLiteralClass)
1936 try transStringLiteralInitializer(c, scope, @ptrCast(*const clang.StringLiteral, expr), type_node)1926 try transStringLiteralInitializer(c, @ptrCast(*const clang.StringLiteral, expr), type_node)
1937 else1927 else
1938 try transExprCoercing(c, scope, expr, .used)1928 try transExprCoercing(c, scope, expr, .used)
1939 else if (is_static_local)1929 else if (is_static_local)
...@@ -2051,21 +2041,21 @@ fn transImplicitCastExpr(...@@ -2051,21 +2041,21 @@ fn transImplicitCastExpr(
2051 .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => {2041 .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => {
2052 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);2042 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
2053 const casted = try transCCast(c, scope, expr.getBeginLoc(), dest_type, src_type, sub_expr_node);2043 const casted = try transCCast(c, scope, expr.getBeginLoc(), dest_type, src_type, sub_expr_node);
2054 return maybeSuppressResult(c, scope, result_used, casted);2044 return maybeSuppressResult(c, result_used, casted);
2055 },2045 },
2056 .LValueToRValue, .NoOp, .FunctionToPointerDecay => {2046 .LValueToRValue, .NoOp, .FunctionToPointerDecay => {
2057 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);2047 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
2058 return maybeSuppressResult(c, scope, result_used, sub_expr_node);2048 return maybeSuppressResult(c, result_used, sub_expr_node);
2059 },2049 },
2060 .ArrayToPointerDecay => {2050 .ArrayToPointerDecay => {
2061 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);2051 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
2062 if (exprIsNarrowStringLiteral(sub_expr) or exprIsFlexibleArrayRef(c, sub_expr)) {2052 if (exprIsNarrowStringLiteral(sub_expr) or exprIsFlexibleArrayRef(c, sub_expr)) {
2063 return maybeSuppressResult(c, scope, result_used, sub_expr_node);2053 return maybeSuppressResult(c, result_used, sub_expr_node);
2064 }2054 }
20652055
2066 const addr = try Tag.address_of.create(c.arena, sub_expr_node);2056 const addr = try Tag.address_of.create(c.arena, sub_expr_node);
2067 const casted = try transCPtrCast(c, scope, expr.getBeginLoc(), dest_type, src_type, addr);2057 const casted = try transCPtrCast(c, scope, expr.getBeginLoc(), dest_type, src_type, addr);
2068 return maybeSuppressResult(c, scope, result_used, casted);2058 return maybeSuppressResult(c, result_used, casted);
2069 },2059 },
2070 .NullToPointer => {2060 .NullToPointer => {
2071 return Tag.null_literal.init();2061 return Tag.null_literal.init();
...@@ -2076,18 +2066,18 @@ fn transImplicitCastExpr(...@@ -2076,18 +2066,18 @@ fn transImplicitCastExpr(
2076 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, ptr_node);2066 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, ptr_node);
20772067
2078 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() });2068 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() });
2079 return maybeSuppressResult(c, scope, result_used, ne);2069 return maybeSuppressResult(c, result_used, ne);
2080 },2070 },
2081 .IntegralToBoolean, .FloatingToBoolean => {2071 .IntegralToBoolean, .FloatingToBoolean => {
2082 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);2072 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
20832073
2084 // The expression is already a boolean one, return it as-is2074 // The expression is already a boolean one, return it as-is
2085 if (isBoolRes(sub_expr_node))2075 if (isBoolRes(sub_expr_node))
2086 return maybeSuppressResult(c, scope, result_used, sub_expr_node);2076 return maybeSuppressResult(c, result_used, sub_expr_node);
20872077
2088 // val != 02078 // val != 0
2089 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = sub_expr_node, .rhs = Tag.zero_literal.init() });2079 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = sub_expr_node, .rhs = Tag.zero_literal.init() });
2090 return maybeSuppressResult(c, scope, result_used, ne);2080 return maybeSuppressResult(c, result_used, ne);
2091 },2081 },
2092 .BuiltinFnToFnPtr => {2082 .BuiltinFnToFnPtr => {
2093 return transBuiltinFnExpr(c, scope, sub_expr, result_used);2083 return transBuiltinFnExpr(c, scope, sub_expr, result_used);
...@@ -2140,13 +2130,13 @@ fn transBoolExpr(...@@ -2140,13 +2130,13 @@ fn transBoolExpr(
21402130
2141 var res = try transExpr(c, scope, expr, used);2131 var res = try transExpr(c, scope, expr, used);
2142 if (isBoolRes(res)) {2132 if (isBoolRes(res)) {
2143 return maybeSuppressResult(c, scope, used, res);2133 return maybeSuppressResult(c, used, res);
2144 }2134 }
21452135
2146 const ty = getExprQualType(c, expr).getTypePtr();2136 const ty = getExprQualType(c, expr).getTypePtr();
2147 const node = try finishBoolExpr(c, scope, expr.getBeginLoc(), ty, res, used);2137 const node = try finishBoolExpr(c, scope, expr.getBeginLoc(), ty, res, used);
21482138
2149 return maybeSuppressResult(c, scope, used, node);2139 return maybeSuppressResult(c, used, node);
2150}2140}
21512141
2152fn exprIsBooleanType(expr: *const clang.Expr) bool {2142fn exprIsBooleanType(expr: *const clang.Expr) bool {
...@@ -2299,7 +2289,7 @@ fn transIntegerLiteral(...@@ -2299,7 +2289,7 @@ fn transIntegerLiteral(
22992289
2300 if (suppress_as == .no_as) {2290 if (suppress_as == .no_as) {
2301 const int_lit_node = try transCreateNodeAPInt(c, eval_result.Val.getInt());2291 const int_lit_node = try transCreateNodeAPInt(c, eval_result.Val.getInt());
2302 return maybeSuppressResult(c, scope, result_used, int_lit_node);2292 return maybeSuppressResult(c, result_used, int_lit_node);
2303 }2293 }
23042294
2305 // Integer literals in C have types, and this can matter for several reasons.2295 // Integer literals in C have types, and this can matter for several reasons.
...@@ -2317,7 +2307,7 @@ fn transIntegerLiteral(...@@ -2317,7 +2307,7 @@ fn transIntegerLiteral(
2317 const ty_node = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc());2307 const ty_node = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc());
2318 const rhs = try transCreateNodeAPInt(c, eval_result.Val.getInt());2308 const rhs = try transCreateNodeAPInt(c, eval_result.Val.getInt());
2319 const as = try Tag.as.create(c.arena, .{ .lhs = ty_node, .rhs = rhs });2309 const as = try Tag.as.create(c.arena, .{ .lhs = ty_node, .rhs = rhs });
2320 return maybeSuppressResult(c, scope, result_used, as);2310 return maybeSuppressResult(c, result_used, as);
2321}2311}
23222312
2323fn transReturnStmt(2313fn transReturnStmt(
...@@ -2329,7 +2319,7 @@ fn transReturnStmt(...@@ -2329,7 +2319,7 @@ fn transReturnStmt(
2329 return Tag.return_void.init();2319 return Tag.return_void.init();
23302320
2331 var rhs = try transExprCoercing(c, scope, val_expr, .used);2321 var rhs = try transExprCoercing(c, scope, val_expr, .used);
2332 const return_qt = scope.findBlockReturnType(c);2322 const return_qt = scope.findBlockReturnType();
2333 if (isBoolRes(rhs) and !qualTypeIsBoolean(return_qt)) {2323 if (isBoolRes(rhs) and !qualTypeIsBoolean(return_qt)) {
2334 rhs = try Tag.bool_to_int.create(c.arena, rhs);2324 rhs = try Tag.bool_to_int.create(c.arena, rhs);
2335 }2325 }
...@@ -2338,7 +2328,6 @@ fn transReturnStmt(...@@ -2338,7 +2328,6 @@ fn transReturnStmt(
23382328
2339fn transNarrowStringLiteral(2329fn transNarrowStringLiteral(
2340 c: *Context,2330 c: *Context,
2341 scope: *Scope,
2342 stmt: *const clang.StringLiteral,2331 stmt: *const clang.StringLiteral,
2343 result_used: ResultUsed,2332 result_used: ResultUsed,
2344) TransError!Node {2333) TransError!Node {
...@@ -2347,7 +2336,7 @@ fn transNarrowStringLiteral(...@@ -2347,7 +2336,7 @@ fn transNarrowStringLiteral(
23472336
2348 const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])});2337 const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])});
2349 const node = try Tag.string_literal.create(c.arena, str);2338 const node = try Tag.string_literal.create(c.arena, str);
2350 return maybeSuppressResult(c, scope, result_used, node);2339 return maybeSuppressResult(c, result_used, node);
2351}2340}
23522341
2353fn transStringLiteral(2342fn transStringLiteral(
...@@ -2358,18 +2347,18 @@ fn transStringLiteral(...@@ -2358,18 +2347,18 @@ fn transStringLiteral(
2358) TransError!Node {2347) TransError!Node {
2359 const kind = stmt.getKind();2348 const kind = stmt.getKind();
2360 switch (kind) {2349 switch (kind) {
2361 .Ascii, .UTF8 => return transNarrowStringLiteral(c, scope, stmt, result_used),2350 .Ascii, .UTF8 => return transNarrowStringLiteral(c, stmt, result_used),
2362 .UTF16, .UTF32, .Wide => {2351 .UTF16, .UTF32, .Wide => {
2363 const str_type = @tagName(stmt.getKind());2352 const str_type = @tagName(stmt.getKind());
2364 const name = try std.fmt.allocPrint(c.arena, "zig.{s}_string_{d}", .{ str_type, c.getMangle() });2353 const name = try std.fmt.allocPrint(c.arena, "zig.{s}_string_{d}", .{ str_type, c.getMangle() });
23652354
2366 const expr_base = @ptrCast(*const clang.Expr, stmt);2355 const expr_base = @ptrCast(*const clang.Expr, stmt);
2367 const array_type = try transQualTypeInitialized(c, scope, expr_base.getType(), expr_base, expr_base.getBeginLoc());2356 const array_type = try transQualTypeInitialized(c, scope, expr_base.getType(), expr_base, expr_base.getBeginLoc());
2368 const lit_array = try transStringLiteralInitializer(c, scope, stmt, array_type);2357 const lit_array = try transStringLiteralInitializer(c, stmt, array_type);
2369 const decl = try Tag.var_simple.create(c.arena, .{ .name = name, .init = lit_array });2358 const decl = try Tag.var_simple.create(c.arena, .{ .name = name, .init = lit_array });
2370 try scope.appendNode(decl);2359 try scope.appendNode(decl);
2371 const node = try Tag.identifier.create(c.arena, name);2360 const node = try Tag.identifier.create(c.arena, name);
2372 return maybeSuppressResult(c, scope, result_used, node);2361 return maybeSuppressResult(c, result_used, node);
2373 },2362 },
2374 }2363 }
2375}2364}
...@@ -2384,7 +2373,6 @@ fn getArrayPayload(array_type: Node) ast.Payload.Array.ArrayTypeInfo {...@@ -2384,7 +2373,6 @@ fn getArrayPayload(array_type: Node) ast.Payload.Array.ArrayTypeInfo {
2384/// the appropriate length, if necessary.2373/// the appropriate length, if necessary.
2385fn transStringLiteralInitializer(2374fn transStringLiteralInitializer(
2386 c: *Context,2375 c: *Context,
2387 scope: *Scope,
2388 stmt: *const clang.StringLiteral,2376 stmt: *const clang.StringLiteral,
2389 array_type: Node,2377 array_type: Node,
2390) TransError!Node {2378) TransError!Node {
...@@ -2403,7 +2391,7 @@ fn transStringLiteralInitializer(...@@ -2403,7 +2391,7 @@ fn transStringLiteralInitializer(
2403 const init_node = if (num_inits > 0) blk: {2391 const init_node = if (num_inits > 0) blk: {
2404 if (is_narrow) {2392 if (is_narrow) {
2405 // "string literal".* or string literal"[0..num_inits].*2393 // "string literal".* or string literal"[0..num_inits].*
2406 var str = try transNarrowStringLiteral(c, scope, stmt, .used);2394 var str = try transNarrowStringLiteral(c, stmt, .used);
2407 if (str_length != array_size) str = try Tag.string_slice.create(c.arena, .{ .string = str, .end = num_inits });2395 if (str_length != array_size) str = try Tag.string_slice.create(c.arena, .{ .string = str, .end = num_inits });
2408 break :blk try Tag.deref.create(c.arena, str);2396 break :blk try Tag.deref.create(c.arena, str);
2409 } else {2397 } else {
...@@ -2440,8 +2428,7 @@ fn transStringLiteralInitializer(...@@ -2440,8 +2428,7 @@ fn transStringLiteralInitializer(
2440/// determine whether `stmt` is a "pointer subtraction expression" - a subtraction where2428/// determine whether `stmt` is a "pointer subtraction expression" - a subtraction where
2441/// both operands resolve to addresses. The C standard requires that both operands2429/// both operands resolve to addresses. The C standard requires that both operands
2442/// point to elements of the same array object, but we do not verify that here.2430/// point to elements of the same array object, but we do not verify that here.
2443fn cIsPointerDiffExpr(c: *Context, stmt: *const clang.BinaryOperator) bool {2431fn cIsPointerDiffExpr(stmt: *const clang.BinaryOperator) bool {
2444 _ = c;
2445 const lhs = @ptrCast(*const clang.Stmt, stmt.getLHS());2432 const lhs = @ptrCast(*const clang.Stmt, stmt.getLHS());
2446 const rhs = @ptrCast(*const clang.Stmt, stmt.getRHS());2433 const rhs = @ptrCast(*const clang.Stmt, stmt.getRHS());
2447 return stmt.getOpcode() == .Sub and2434 return stmt.getOpcode() == .Sub and
...@@ -2748,9 +2735,7 @@ fn transInitListExprVector(...@@ -2748,9 +2735,7 @@ fn transInitListExprVector(
2748 scope: *Scope,2735 scope: *Scope,
2749 loc: clang.SourceLocation,2736 loc: clang.SourceLocation,
2750 expr: *const clang.InitListExpr,2737 expr: *const clang.InitListExpr,
2751 ty: *const clang.Type,
2752) TransError!Node {2738) TransError!Node {
2753 _ = ty;
2754 const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr));2739 const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr));
2755 const vector_ty = @ptrCast(*const clang.VectorType, qualTypeCanon(qt));2740 const vector_ty = @ptrCast(*const clang.VectorType, qualTypeCanon(qt));
27562741
...@@ -2829,7 +2814,7 @@ fn transInitListExpr(...@@ -2829,7 +2814,7 @@ fn transInitListExpr(
2829 }2814 }
28302815
2831 if (qual_type.isRecordType()) {2816 if (qual_type.isRecordType()) {
2832 return maybeSuppressResult(c, scope, used, try transInitListExprRecord(2817 return maybeSuppressResult(c, used, try transInitListExprRecord(
2833 c,2818 c,
2834 scope,2819 scope,
2835 source_loc,2820 source_loc,
...@@ -2837,7 +2822,7 @@ fn transInitListExpr(...@@ -2837,7 +2822,7 @@ fn transInitListExpr(
2837 qual_type,2822 qual_type,
2838 ));2823 ));
2839 } else if (qual_type.isArrayType()) {2824 } else if (qual_type.isArrayType()) {
2840 return maybeSuppressResult(c, scope, used, try transInitListExprArray(2825 return maybeSuppressResult(c, used, try transInitListExprArray(
2841 c,2826 c,
2842 scope,2827 scope,
2843 source_loc,2828 source_loc,
...@@ -2845,13 +2830,7 @@ fn transInitListExpr(...@@ -2845,13 +2830,7 @@ fn transInitListExpr(
2845 qual_type,2830 qual_type,
2846 ));2831 ));
2847 } else if (qual_type.isVectorType()) {2832 } else if (qual_type.isVectorType()) {
2848 return maybeSuppressResult(c, scope, used, try transInitListExprVector(2833 return maybeSuppressResult(c, used, try transInitListExprVector(c, scope, source_loc, expr));
2849 c,
2850 scope,
2851 source_loc,
2852 expr,
2853 qual_type,
2854 ));
2855 } else {2834 } else {
2856 const type_name = try c.str(qual_type.getTypeClassName());2835 const type_name = try c.str(qual_type.getTypeClassName());
2857 return fail(c, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name});2836 return fail(c, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name});
...@@ -2912,9 +2891,7 @@ fn transImplicitValueInitExpr(...@@ -2912,9 +2891,7 @@ fn transImplicitValueInitExpr(
2912 c: *Context,2891 c: *Context,
2913 scope: *Scope,2892 scope: *Scope,
2914 expr: *const clang.Expr,2893 expr: *const clang.Expr,
2915 used: ResultUsed,
2916) TransError!Node {2894) TransError!Node {
2917 _ = used;
2918 const source_loc = expr.getBeginLoc();2895 const source_loc = expr.getBeginLoc();
2919 const qt = getExprQualType(c, expr);2896 const qt = getExprQualType(c, expr);
2920 const ty = qt.getTypePtr();2897 const ty = qt.getTypePtr();
...@@ -3354,7 +3331,7 @@ fn transConstantExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used:...@@ -3354,7 +3331,7 @@ fn transConstantExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used:
3354 .lhs = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc()),3331 .lhs = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc()),
3355 .rhs = try transCreateNodeAPInt(c, result.Val.getInt()),3332 .rhs = try transCreateNodeAPInt(c, result.Val.getInt()),
3356 });3333 });
3357 return maybeSuppressResult(c, scope, used, as_node);3334 return maybeSuppressResult(c, used, as_node);
3358 },3335 },
3359 else => |kind| {3336 else => |kind| {
3360 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "unsupported constant expression kind '{}'", .{kind});3337 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "unsupported constant expression kind '{}'", .{kind});
...@@ -3391,7 +3368,7 @@ fn transCharLiteral(...@@ -3391,7 +3368,7 @@ fn transCharLiteral(
3391 try transCreateCharLitNode(c, narrow, val);3368 try transCreateCharLitNode(c, narrow, val);
33923369
3393 if (suppress_as == .no_as) {3370 if (suppress_as == .no_as) {
3394 return maybeSuppressResult(c, scope, result_used, int_lit_node);3371 return maybeSuppressResult(c, result_used, int_lit_node);
3395 }3372 }
3396 // See comment in `transIntegerLiteral` for why this code is here.3373 // See comment in `transIntegerLiteral` for why this code is here.
3397 // @as(T, x)3374 // @as(T, x)
...@@ -3400,7 +3377,7 @@ fn transCharLiteral(...@@ -3400,7 +3377,7 @@ fn transCharLiteral(
3400 .lhs = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc()),3377 .lhs = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc()),
3401 .rhs = int_lit_node,3378 .rhs = int_lit_node,
3402 });3379 });
3403 return maybeSuppressResult(c, scope, result_used, as_node);3380 return maybeSuppressResult(c, result_used, as_node);
3404}3381}
34053382
3406fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used: ResultUsed) TransError!Node {3383fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used: ResultUsed) TransError!Node {
...@@ -3426,7 +3403,7 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used:...@@ -3426,7 +3403,7 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used:
3426 });3403 });
3427 try block_scope.statements.append(break_node);3404 try block_scope.statements.append(break_node);
3428 const res = try block_scope.complete(c);3405 const res = try block_scope.complete(c);
3429 return maybeSuppressResult(c, scope, used, res);3406 return maybeSuppressResult(c, used, res);
3430}3407}
34313408
3432fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!Node {3409fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!Node {
...@@ -3455,7 +3432,7 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re...@@ -3455,7 +3432,7 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re
3455 if (exprIsFlexibleArrayRef(c, @ptrCast(*const clang.Expr, stmt))) {3432 if (exprIsFlexibleArrayRef(c, @ptrCast(*const clang.Expr, stmt))) {
3456 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &.{} });3433 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &.{} });
3457 }3434 }
3458 return maybeSuppressResult(c, scope, result_used, node);3435 return maybeSuppressResult(c, result_used, node);
3459}3436}
34603437
3461/// ptr[subscr] (`subscr` is a signed integer expression, `ptr` a pointer) becomes:3438/// ptr[subscr] (`subscr` is a signed integer expression, `ptr` a pointer) becomes:
...@@ -3533,7 +3510,7 @@ fn transSignedArrayAccess(...@@ -3533,7 +3510,7 @@ fn transSignedArrayAccess(
35333510
3534 const derefed = try Tag.deref.create(c.arena, block_node);3511 const derefed = try Tag.deref.create(c.arena, block_node);
35353512
3536 return maybeSuppressResult(c, &block_scope.base, result_used, derefed);3513 return maybeSuppressResult(c, result_used, derefed);
3537}3514}
35383515
3539fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscriptExpr, result_used: ResultUsed) TransError!Node {3516fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscriptExpr, result_used: ResultUsed) TransError!Node {
...@@ -3574,7 +3551,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip...@@ -3574,7 +3551,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip
3574 .lhs = container_node,3551 .lhs = container_node,
3575 .rhs = rhs,3552 .rhs = rhs,
3576 });3553 });
3577 return maybeSuppressResult(c, scope, result_used, node);3554 return maybeSuppressResult(c, result_used, node);
3578}3555}
35793556
3580/// Check if an expression is ultimately a reference to a function declaration3557/// Check if an expression is ultimately a reference to a function declaration
...@@ -3665,7 +3642,7 @@ fn transCallExpr(c: *Context, scope: *Scope, stmt: *const clang.CallExpr, result...@@ -3665,7 +3642,7 @@ fn transCallExpr(c: *Context, scope: *Scope, stmt: *const clang.CallExpr, result
3665 }3642 }
3666 }3643 }
36673644
3668 return maybeSuppressResult(c, scope, result_used, node);3645 return maybeSuppressResult(c, result_used, node);
3669}3646}
36703647
3671const ClangFunctionType = union(enum) {3648const ClangFunctionType = union(enum) {
...@@ -3705,14 +3682,13 @@ fn transUnaryExprOrTypeTraitExpr(...@@ -3705,14 +3682,13 @@ fn transUnaryExprOrTypeTraitExpr(
3705 stmt: *const clang.UnaryExprOrTypeTraitExpr,3682 stmt: *const clang.UnaryExprOrTypeTraitExpr,
3706 result_used: ResultUsed,3683 result_used: ResultUsed,
3707) TransError!Node {3684) TransError!Node {
3708 _ = result_used;
3709 const loc = stmt.getBeginLoc();3685 const loc = stmt.getBeginLoc();
3710 const type_node = try transQualType(c, scope, stmt.getTypeOfArgument(), loc);3686 const type_node = try transQualType(c, scope, stmt.getTypeOfArgument(), loc);
37113687
3712 const kind = stmt.getKind();3688 const kind = stmt.getKind();
3713 switch (kind) {3689 const node = switch (kind) {
3714 .SizeOf => return Tag.sizeof.create(c.arena, type_node),3690 .SizeOf => try Tag.sizeof.create(c.arena, type_node),
3715 .AlignOf => return Tag.alignof.create(c.arena, type_node),3691 .AlignOf => try Tag.alignof.create(c.arena, type_node),
3716 .PreferredAlignOf,3692 .PreferredAlignOf,
3717 .VecStep,3693 .VecStep,
3718 .OpenMPRequiredSimdAlign,3694 .OpenMPRequiredSimdAlign,
...@@ -3723,7 +3699,8 @@ fn transUnaryExprOrTypeTraitExpr(...@@ -3723,7 +3699,8 @@ fn transUnaryExprOrTypeTraitExpr(
3723 "unsupported type trait kind {}",3699 "unsupported type trait kind {}",
3724 .{kind},3700 .{kind},
3725 ),3701 ),
3726 }3702 };
3703 return maybeSuppressResult(c, result_used, node);
3727}3704}
37283705
3729fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {3706fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {
...@@ -3812,7 +3789,7 @@ fn transCreatePreCrement(...@@ -3812,7 +3789,7 @@ fn transCreatePreCrement(
3812 // zig: expr += 13789 // zig: expr += 1
3813 const lhs = try transExpr(c, scope, op_expr, .used);3790 const lhs = try transExpr(c, scope, op_expr, .used);
3814 const rhs = Tag.one_literal.init();3791 const rhs = Tag.one_literal.init();
3815 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used);3792 return transCreateNodeInfixOp(c, op, lhs, rhs, .used);
3816 }3793 }
3817 // worst case3794 // worst case
3818 // c: ++expr3795 // c: ++expr
...@@ -3832,7 +3809,7 @@ fn transCreatePreCrement(...@@ -3832,7 +3809,7 @@ fn transCreatePreCrement(
38323809
3833 const lhs_node = try Tag.identifier.create(c.arena, ref);3810 const lhs_node = try Tag.identifier.create(c.arena, ref);
3834 const ref_node = try Tag.deref.create(c.arena, lhs_node);3811 const ref_node = try Tag.deref.create(c.arena, lhs_node);
3835 const node = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, Tag.one_literal.init(), .used);3812 const node = try transCreateNodeInfixOp(c, op, ref_node, Tag.one_literal.init(), .used);
3836 try block_scope.statements.append(node);3813 try block_scope.statements.append(node);
38373814
3838 const break_node = try Tag.break_val.create(c.arena, .{3815 const break_node = try Tag.break_val.create(c.arena, .{
...@@ -3858,7 +3835,7 @@ fn transCreatePostCrement(...@@ -3858,7 +3835,7 @@ fn transCreatePostCrement(
3858 // zig: expr += 13835 // zig: expr += 1
3859 const lhs = try transExpr(c, scope, op_expr, .used);3836 const lhs = try transExpr(c, scope, op_expr, .used);
3860 const rhs = Tag.one_literal.init();3837 const rhs = Tag.one_literal.init();
3861 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used);3838 return transCreateNodeInfixOp(c, op, lhs, rhs, .used);
3862 }3839 }
3863 // worst case3840 // worst case
3864 // c: expr++3841 // c: expr++
...@@ -3884,7 +3861,7 @@ fn transCreatePostCrement(...@@ -3884,7 +3861,7 @@ fn transCreatePostCrement(
3884 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node });3861 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node });
3885 try block_scope.statements.append(tmp_decl);3862 try block_scope.statements.append(tmp_decl);
38863863
3887 const node = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, Tag.one_literal.init(), .used);3864 const node = try transCreateNodeInfixOp(c, op, ref_node, Tag.one_literal.init(), .used);
3888 try block_scope.statements.append(node);3865 try block_scope.statements.append(node);
38893866
3890 const break_node = try Tag.break_val.create(c.arena, .{3867 const break_node = try Tag.break_val.create(c.arena, .{
...@@ -3965,7 +3942,7 @@ fn transCreateCompoundAssign(...@@ -3965,7 +3942,7 @@ fn transCreateCompoundAssign(
3965 else3942 else
3966 try Tag.div_trunc.create(c.arena, operands);3943 try Tag.div_trunc.create(c.arena, operands);
39673944
3968 return transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used);3945 return transCreateNodeInfixOp(c, .assign, lhs_node, builtin, .used);
3969 }3946 }
39703947
3971 if (is_shift) {3948 if (is_shift) {
...@@ -3974,7 +3951,7 @@ fn transCreateCompoundAssign(...@@ -3974,7 +3951,7 @@ fn transCreateCompoundAssign(
3974 } else if (requires_int_cast) {3951 } else if (requires_int_cast) {
3975 rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node);3952 rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node);
3976 }3953 }
3977 return transCreateNodeInfixOp(c, scope, op, lhs_node, rhs_node, .used);3954 return transCreateNodeInfixOp(c, op, lhs_node, rhs_node, .used);
3978 }3955 }
3979 // worst case3956 // worst case
3980 // c: lhs += rhs3957 // c: lhs += rhs
...@@ -4005,7 +3982,7 @@ fn transCreateCompoundAssign(...@@ -4005,7 +3982,7 @@ fn transCreateCompoundAssign(
4005 else3982 else
4006 try Tag.div_trunc.create(c.arena, operands);3983 try Tag.div_trunc.create(c.arena, operands);
40073984
4008 const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, ref_node, builtin, .used);3985 const assign = try transCreateNodeInfixOp(c, .assign, ref_node, builtin, .used);
4009 try block_scope.statements.append(assign);3986 try block_scope.statements.append(assign);
4010 } else {3987 } else {
4011 if (is_shift) {3988 if (is_shift) {
...@@ -4015,7 +3992,7 @@ fn transCreateCompoundAssign(...@@ -4015,7 +3992,7 @@ fn transCreateCompoundAssign(
4015 rhs_node = try transCCast(c, &block_scope.base, loc, lhs_qt, rhs_qt, rhs_node);3992 rhs_node = try transCCast(c, &block_scope.base, loc, lhs_qt, rhs_qt, rhs_node);
4016 }3993 }
40173994
4018 const assign = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, rhs_node, .used);3995 const assign = try transCreateNodeInfixOp(c, op, ref_node, rhs_node, .used);
4019 try block_scope.statements.append(assign);3996 try block_scope.statements.append(assign);
4020 }3997 }
40213998
...@@ -4071,7 +4048,7 @@ fn transCPtrCast(...@@ -4071,7 +4048,7 @@ fn transCPtrCast(
4071 }4048 }
4072}4049}
40734050
4074fn transFloatingLiteral(c: *Context, scope: *Scope, expr: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {4051fn transFloatingLiteral(c: *Context, expr: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {
4075 switch (expr.getRawSemantics()) {4052 switch (expr.getRawSemantics()) {
4076 .IEEEhalf, // f164053 .IEEEhalf, // f16
4077 .IEEEsingle, // f324054 .IEEEsingle, // f32
...@@ -4095,7 +4072,7 @@ fn transFloatingLiteral(c: *Context, scope: *Scope, expr: *const clang.FloatingL...@@ -4095,7 +4072,7 @@ fn transFloatingLiteral(c: *Context, scope: *Scope, expr: *const clang.FloatingL
4095 try std.fmt.allocPrint(c.arena, "{d}", .{dbl});4072 try std.fmt.allocPrint(c.arena, "{d}", .{dbl});
4096 var node = try Tag.float_literal.create(c.arena, str);4073 var node = try Tag.float_literal.create(c.arena, str);
4097 if (is_negative) node = try Tag.negate.create(c.arena, node);4074 if (is_negative) node = try Tag.negate.create(c.arena, node);
4098 return maybeSuppressResult(c, scope, used, node);4075 return maybeSuppressResult(c, used, node);
4099}4076}
41004077
4101fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.BinaryConditionalOperator, used: ResultUsed) TransError!Node {4078fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.BinaryConditionalOperator, used: ResultUsed) TransError!Node {
...@@ -4151,7 +4128,7 @@ fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang...@@ -4151,7 +4128,7 @@ fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang
4151 });4128 });
4152 try block_scope.statements.append(break_node);4129 try block_scope.statements.append(break_node);
4153 const res = try block_scope.complete(c);4130 const res = try block_scope.complete(c);
4154 return maybeSuppressResult(c, scope, used, res);4131 return maybeSuppressResult(c, used, res);
4155}4132}
41564133
4157fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.ConditionalOperator, used: ResultUsed) TransError!Node {4134fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.ConditionalOperator, used: ResultUsed) TransError!Node {
...@@ -4191,13 +4168,7 @@ fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.Condi...@@ -4191,13 +4168,7 @@ fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.Condi
4191 return if_node;4168 return if_node;
4192}4169}
41934170
4194fn maybeSuppressResult(4171fn maybeSuppressResult(c: *Context, used: ResultUsed, result: Node) TransError!Node {
4195 c: *Context,
4196 scope: *Scope,
4197 used: ResultUsed,
4198 result: Node,
4199) TransError!Node {
4200 _ = scope;
4201 if (used == .used) return result;4172 if (used == .used) return result;
4202 return Tag.discard.create(c.arena, .{ .should_skip = false, .value = result });4173 return Tag.discard.create(c.arena, .{ .should_skip = false, .value = result });
4203}4174}
...@@ -4551,7 +4522,7 @@ fn transCreateNodeAssign(...@@ -4551,7 +4522,7 @@ fn transCreateNodeAssign(
4551 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {4522 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
4552 rhs_node = try Tag.bool_to_int.create(c.arena, rhs_node);4523 rhs_node = try Tag.bool_to_int.create(c.arena, rhs_node);
4553 }4524 }
4554 return transCreateNodeInfixOp(c, scope, .assign, lhs_node, rhs_node, .used);4525 return transCreateNodeInfixOp(c, .assign, lhs_node, rhs_node, .used);
4555 }4526 }
45564527
4557 // worst case4528 // worst case
...@@ -4571,7 +4542,7 @@ fn transCreateNodeAssign(...@@ -4571,7 +4542,7 @@ fn transCreateNodeAssign(
45714542
4572 const lhs_node = try transExpr(c, &block_scope.base, lhs, .used);4543 const lhs_node = try transExpr(c, &block_scope.base, lhs, .used);
4573 const tmp_ident = try Tag.identifier.create(c.arena, tmp);4544 const tmp_ident = try Tag.identifier.create(c.arena, tmp);
4574 const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, lhs_node, tmp_ident, .used);4545 const assign = try transCreateNodeInfixOp(c, .assign, lhs_node, tmp_ident, .used);
4575 try block_scope.statements.append(assign);4546 try block_scope.statements.append(assign);
45764547
4577 const break_node = try Tag.break_val.create(c.arena, .{4548 const break_node = try Tag.break_val.create(c.arena, .{
...@@ -4584,7 +4555,6 @@ fn transCreateNodeAssign(...@@ -4584,7 +4555,6 @@ fn transCreateNodeAssign(
45844555
4585fn transCreateNodeInfixOp(4556fn transCreateNodeInfixOp(
4586 c: *Context,4557 c: *Context,
4587 scope: *Scope,
4588 op: Tag,4558 op: Tag,
4589 lhs: Node,4559 lhs: Node,
4590 rhs: Node,4560 rhs: Node,
...@@ -4598,7 +4568,7 @@ fn transCreateNodeInfixOp(...@@ -4598,7 +4568,7 @@ fn transCreateNodeInfixOp(
4598 .rhs = rhs,4568 .rhs = rhs,
4599 },4569 },
4600 };4570 };
4601 return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base));4571 return maybeSuppressResult(c, used, Node.initPayload(&payload.base));
4602}4572}
46034573
4604fn transCreateNodeBoolInfixOp(4574fn transCreateNodeBoolInfixOp(
...@@ -4613,7 +4583,7 @@ fn transCreateNodeBoolInfixOp(...@@ -4613,7 +4583,7 @@ fn transCreateNodeBoolInfixOp(
4613 const lhs = try transBoolExpr(c, scope, stmt.getLHS(), .used);4583 const lhs = try transBoolExpr(c, scope, stmt.getLHS(), .used);
4614 const rhs = try transBoolExpr(c, scope, stmt.getRHS(), .used);4584 const rhs = try transBoolExpr(c, scope, stmt.getRHS(), .used);
46154585
4616 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, used);4586 return transCreateNodeInfixOp(c, op, lhs, rhs, used);
4617}4587}
46184588
4619fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {4589fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
...@@ -4730,7 +4700,7 @@ fn transCreateNodeShiftOp(...@@ -4730,7 +4700,7 @@ fn transCreateNodeShiftOp(
4730 const rhs = try transExprCoercing(c, scope, rhs_expr, .used);4700 const rhs = try transExprCoercing(c, scope, rhs_expr, .used);
4731 const rhs_casted = try Tag.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs });4701 const rhs_casted = try Tag.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs });
47324702
4733 return transCreateNodeInfixOp(c, scope, op, lhs, rhs_casted, used);4703 return transCreateNodeInfixOp(c, op, lhs, rhs_casted, used);
4734}4704}
47354705
4736fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Node {4706fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Node {
...@@ -5681,13 +5651,14 @@ const ParseError = Error || error{ParseError};...@@ -5681,13 +5651,14 @@ const ParseError = Error || error{ParseError};
56815651
5682fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {5652fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5683 // TODO parseCAssignExpr here5653 // TODO parseCAssignExpr here
5684 const node = try parseCCondExpr(c, m, scope);5654 var block_scope = try Scope.Block.init(c, scope, true);
5655 defer block_scope.deinit();
5656
5657 const node = try parseCCondExpr(c, m, &block_scope.base);
5685 if (m.next().? != .Comma) {5658 if (m.next().? != .Comma) {
5686 m.i -= 1;5659 m.i -= 1;
5687 return node;5660 return node;
5688 }5661 }
5689 var block_scope = try Scope.Block.init(c, scope, true);
5690 defer block_scope.deinit();
56915662
5692 var last = node;5663 var last = node;
5693 while (true) {5664 while (true) {
...@@ -6298,7 +6269,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6298,7 +6269,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6298// allow_fail is set when unsure if we are parsing a type-name6269// allow_fail is set when unsure if we are parsing a type-name
6299fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node {6270fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node {
6300 if (try parseCSpecifierQualifierList(c, m, scope, allow_fail)) |node| {6271 if (try parseCSpecifierQualifierList(c, m, scope, allow_fail)) |node| {
6301 return try parseCAbstractDeclarator(c, m, scope, node);6272 return try parseCAbstractDeclarator(c, m, node);
6302 } else {6273 } else {
6303 return null;6274 return null;
6304 }6275 }
...@@ -6327,7 +6298,7 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_...@@ -6327,7 +6298,7 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_
6327 .Keyword_complex,6298 .Keyword_complex,
6328 => {6299 => {
6329 m.i -= 1;6300 m.i -= 1;
6330 return try parseCNumericType(c, m, scope);6301 return try parseCNumericType(c, m);
6331 },6302 },
6332 .Keyword_enum, .Keyword_struct, .Keyword_union => {6303 .Keyword_enum, .Keyword_struct, .Keyword_union => {
6333 // struct Foo will be declared as struct_Foo by transRecordDecl6304 // struct Foo will be declared as struct_Foo by transRecordDecl
...@@ -6349,8 +6320,7 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_...@@ -6349,8 +6320,7 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_
6349 }6320 }
6350}6321}
63516322
6352fn parseCNumericType(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6323fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {
6353 _ = scope;
6354 const KwCounter = struct {6324 const KwCounter = struct {
6355 double: u8 = 0,6325 double: u8 = 0,
6356 long: u8 = 0,6326 long: u8 = 0,
...@@ -6451,8 +6421,7 @@ fn parseCNumericType(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6451,8 +6421,7 @@ fn parseCNumericType(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6451 return error.ParseError;6421 return error.ParseError;
6452}6422}
64536423
6454fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, scope: *Scope, node: Node) ParseError!Node {6424fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, node: Node) ParseError!Node {
6455 _ = scope;
6456 switch (m.next().?) {6425 switch (m.next().?) {
6457 .Asterisk => {6426 .Asterisk => {
6458 // last token of `node`6427 // last token of `node`
src/type.zig+8-38
...@@ -3434,20 +3434,8 @@ pub const Type = extern union {...@@ -3434,20 +3434,8 @@ pub const Type = extern union {
34343434
3435 if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 };3435 if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 };
34363436
3437 switch (child_type.zigTypeTag()) {3437 if (ty.optionalReprIsPayload()) {
3438 .Pointer => {3438 return abiSizeAdvanced(child_type, target, strat);
3439 const ptr_info = child_type.ptrInfo().data;
3440 const has_null = switch (ptr_info.size) {
3441 .Slice, .C => true,
3442 else => ptr_info.@"allowzero",
3443 };
3444 if (!has_null) {
3445 const ptr_size_bytes = @divExact(target.cpu.arch.ptrBitWidth(), 8);
3446 return AbiSizeAdvanced{ .scalar = ptr_size_bytes };
3447 }
3448 },
3449 .ErrorSet => return abiSizeAdvanced(Type.anyerror, target, strat),
3450 else => {},
3451 }3439 }
34523440
3453 const payload_size = switch (try child_type.abiSizeAdvanced(target, strat)) {3441 const payload_size = switch (try child_type.abiSizeAdvanced(target, strat)) {
...@@ -3712,28 +3700,10 @@ pub const Type = extern union {...@@ -3712,28 +3700,10 @@ pub const Type = extern union {
37123700
3713 .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data,3701 .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data,
37143702
3715 .optional => {3703 .optional, .error_union => {
3716 var buf: Payload.ElemType = undefined;3704 // Optionals and error unions are not packed so their bitsize
3717 const child_type = ty.optionalChild(&buf);3705 // includes padding bits.
3718 if (!child_type.hasRuntimeBits()) return 8;3706 return (try abiSizeAdvanced(ty, target, if (sema_kit) |sk| .{ .sema_kit = sk } else .eager)).scalar * 8;
3719
3720 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
3721 return target.cpu.arch.ptrBitWidth();
3722
3723 // Optional types are represented as a struct with the child type as the first
3724 // field and a boolean as the second. Since the child type's abi alignment is
3725 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
3726 // to the child type's ABI alignment.
3727 const child_bit_size = try bitSizeAdvanced(child_type, target, sema_kit);
3728 return child_bit_size + 1;
3729 },
3730
3731 .error_union => {
3732 const payload = ty.castTag(.error_union).?.data;
3733 if (!payload.payload.hasRuntimeBits()) {
3734 return payload.error_set.bitSizeAdvanced(target, sema_kit);
3735 }
3736 @panic("TODO bitSize error union");
3737 },3707 },
37383708
3739 .atomic_order,3709 .atomic_order,
...@@ -4010,8 +3980,8 @@ pub const Type = extern union {...@@ -4010,8 +3980,8 @@ pub const Type = extern union {
4010 .Pointer => {3980 .Pointer => {
4011 const info = child_ty.ptrInfo().data;3981 const info = child_ty.ptrInfo().data;
4012 switch (info.size) {3982 switch (info.size) {
4013 .Slice, .C => return false,3983 .C => return false,
4014 .Many, .One => return !info.@"allowzero",3984 .Slice, .Many, .One => return !info.@"allowzero",
4015 }3985 }
4016 },3986 },
4017 .ErrorSet => return true,3987 .ErrorSet => return true,
test/behavior.zig+2
...@@ -108,7 +108,9 @@ test {...@@ -108,7 +108,9 @@ test {
108 _ = @import("behavior/bugs/13112.zig");108 _ = @import("behavior/bugs/13112.zig");
109 _ = @import("behavior/bugs/13128.zig");109 _ = @import("behavior/bugs/13128.zig");
110 _ = @import("behavior/bugs/13164.zig");110 _ = @import("behavior/bugs/13164.zig");
111 _ = @import("behavior/bugs/13159.zig");
111 _ = @import("behavior/bugs/13171.zig");112 _ = @import("behavior/bugs/13171.zig");
113 _ = @import("behavior/bugs/13285.zig");
112 _ = @import("behavior/byteswap.zig");114 _ = @import("behavior/byteswap.zig");
113 _ = @import("behavior/byval_arg_var.zig");115 _ = @import("behavior/byval_arg_var.zig");
114 _ = @import("behavior/call.zig");116 _ = @import("behavior/call.zig");
test/behavior/bugs/13159.zig created+14
...@@ -0,0 +1,14 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4const Bar = packed struct {
5 const Baz = enum {
6 fizz,
7 buzz,
8 };
9};
10
11test {
12 var foo = Bar.Baz.fizz;
13 try expect(foo == .fizz);
14}
test/behavior/bugs/13285.zig created+11
...@@ -0,0 +1,11 @@
1const Crasher = struct {
2 lets_crash: u64 = 0,
3};
4
5test {
6 var a: Crasher = undefined;
7 var crasher_ptr = &a;
8 var crasher_local = crasher_ptr.*;
9 const crasher_local_ptr = &crasher_local;
10 crasher_local_ptr.lets_crash = 1;
11}
test/behavior/cast.zig+11
...@@ -1170,6 +1170,7 @@ test "implicitly cast from [N]T to ?[]const T" {...@@ -1170,6 +1170,7 @@ test "implicitly cast from [N]T to ?[]const T" {
1170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1171 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1171 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1173 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11731174
1174 try expect(mem.eql(u8, castToOptionalSlice().?, "hi"));1175 try expect(mem.eql(u8, castToOptionalSlice().?, "hi"));
1175 comptime try expect(mem.eql(u8, castToOptionalSlice().?, "hi"));1176 comptime try expect(mem.eql(u8, castToOptionalSlice().?, "hi"));
...@@ -1256,6 +1257,7 @@ test "*const [N]null u8 to ?[]const u8" {...@@ -1256,6 +1257,7 @@ test "*const [N]null u8 to ?[]const u8" {
1256 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1257 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1257 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1258 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1259 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1260 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
12591261
1260 const S = struct {1262 const S = struct {
1261 fn doTheTest() !void {1263 fn doTheTest() !void {
...@@ -1394,6 +1396,8 @@ test "cast i8 fn call peers to i32 result" {...@@ -1394,6 +1396,8 @@ test "cast i8 fn call peers to i32 result" {
1394test "cast compatible optional types" {1396test "cast compatible optional types" {
1395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1398 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1399 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1400 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
13971401
1398 var a: ?[:0]const u8 = null;1402 var a: ?[:0]const u8 = null;
1399 var b: ?[]const u8 = a;1403 var b: ?[]const u8 = a;
...@@ -1440,3 +1444,10 @@ test "coerce between pointers of compatible differently-named floats" {...@@ -1440,3 +1444,10 @@ test "coerce between pointers of compatible differently-named floats" {
1440 f2.* += 1;1444 f2.* += 1;
1441 try expect(f1 == @as(F, 12.34) + 1);1445 try expect(f1 == @as(F, 12.34) + 1);
1442}1446}
1447
1448test "peer type resolution of const and non-const pointer to array" {
1449 const a = @intToPtr(*[1024]u8, 42);
1450 const b = @intToPtr(*const [1024]u8, 42);
1451 try std.testing.expect(@TypeOf(a, b) == *const [1024]u8);
1452 try std.testing.expect(a == b);
1453}
test/behavior/optional.zig+16
...@@ -3,6 +3,7 @@ const std = @import("std");...@@ -3,6 +3,7 @@ const std = @import("std");
3const testing = std.testing;3const testing = std.testing;
4const expect = testing.expect;4const expect = testing.expect;
5const expectEqual = testing.expectEqual;5const expectEqual = testing.expectEqual;
6const expectEqualStrings = std.testing.expectEqualStrings;
67
7test "passing an optional integer as a parameter" {8test "passing an optional integer as a parameter" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
...@@ -428,3 +429,18 @@ test "alignment of wrapping an optional payload" {...@@ -428,3 +429,18 @@ test "alignment of wrapping an optional payload" {
428 };429 };
429 try expect(S.foo().?.x == 1234);430 try expect(S.foo().?.x == 1234);
430}431}
432
433test "Optional slice size is optimized" {
434 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
435 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
436 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
437 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
438 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
439 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
440
441 try expect(@sizeOf(?[]u8) == @sizeOf([]u8));
442 var a: ?[]const u8 = null;
443 try expect(a == null);
444 a = "hello";
445 try expectEqualStrings(a.?, "hello");
446}
test/behavior/translate_c_macros.h+1
...@@ -40,6 +40,7 @@ union U {...@@ -40,6 +40,7 @@ union U {
40#define CAST_OR_CALL_WITH_PARENS(type_or_fn, val) ((type_or_fn)(val))40#define CAST_OR_CALL_WITH_PARENS(type_or_fn, val) ((type_or_fn)(val))
4141
42#define NESTED_COMMA_OPERATOR (1, (2, 3))42#define NESTED_COMMA_OPERATOR (1, (2, 3))
43#define NESTED_COMMA_OPERATOR_LHS (1, 2), 3
4344
44#include <stdint.h>45#include <stdint.h>
45#if !defined(__UINTPTR_MAX__)46#if !defined(__UINTPTR_MAX__)
test/behavior/translate_c_macros.zig+1
...@@ -100,6 +100,7 @@ test "nested comma operator" {...@@ -100,6 +100,7 @@ test "nested comma operator" {
100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
101101
102 try expectEqual(@as(c_int, 3), h.NESTED_COMMA_OPERATOR);102 try expectEqual(@as(c_int, 3), h.NESTED_COMMA_OPERATOR);
103 try expectEqual(@as(c_int, 3), h.NESTED_COMMA_OPERATOR_LHS);
103}104}
104105
105test "cast functions" {106test "cast functions" {
test/cases/compile_errors/too_big_packed_struct.zig created+13
...@@ -0,0 +1,13 @@
1pub export fn entry() void {
2 const T = packed struct {
3 a: u65535,
4 b: u65535,
5 };
6 @compileLog(@sizeOf(T));
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :2:22: error: size of packed struct '131070' exceeds maximum bit width of 65535
test/cases/compile_errors/zero-bit_generic_args_are_coerced_to_param_type.zig created+10
...@@ -0,0 +1,10 @@
1fn bar(a: anytype, _: @TypeOf(a)) void {}
2pub export fn entry() void {
3 bar(@as(u0, 0), "fooo");
4}
5
6// error
7// backend=stage2
8// target=native
9//
10// :3:21: error: expected type 'u0', found '*const [4:0]u8'
test/translate_c.zig+4-4
...@@ -499,20 +499,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -499,20 +499,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
499 \\int baz(int x, int y) { return 0; }499 \\int baz(int x, int y) { return 0; }
500 \\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2))500 \\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2))
501 , &[_][]const u8{501 , &[_][]const u8{
502 \\pub const foo = blk: {502 \\pub const foo = blk_1: {
503 \\ _ = @TypeOf(foo);503 \\ _ = @TypeOf(foo);
504 \\ break :blk bar;504 \\ break :blk_1 bar;
505 \\};505 \\};
506 ,506 ,
507 \\pub inline fn bar(x: anytype) @TypeOf(baz(@as(c_int, 1), @as(c_int, 2))) {507 \\pub inline fn bar(x: anytype) @TypeOf(baz(@as(c_int, 1), @as(c_int, 2))) {
508 \\ return blk: {508 \\ return blk_1: {
509 \\ _ = &x;509 \\ _ = &x;
510 \\ _ = @as(c_int, 3);510 \\ _ = @as(c_int, 3);
511 \\ _ = @as(c_int, 4) == @as(c_int, 4);511 \\ _ = @as(c_int, 4) == @as(c_int, 4);
512 \\ _ = @as(c_int, 5) * @as(c_int, 6);512 \\ _ = @as(c_int, 5) * @as(c_int, 6);
513 \\ _ = baz(@as(c_int, 1), @as(c_int, 2));513 \\ _ = baz(@as(c_int, 1), @as(c_int, 2));
514 \\ _ = @as(c_int, 2) % @as(c_int, 2);514 \\ _ = @as(c_int, 2) % @as(c_int, 2);
515 \\ break :blk baz(@as(c_int, 1), @as(c_int, 2));515 \\ break :blk_1 baz(@as(c_int, 1), @as(c_int, 2));
516 \\ };516 \\ };
517 \\}517 \\}
518 });518 });