| ... | ... | @@ -1167,6 +1167,7 @@ fn analyzeBodyInner( |
| 1167 | 1167 | .array_mul => try sema.zirArrayMul(block, inst), |
| 1168 | 1168 | .array_type => try sema.zirArrayType(block, inst), |
| 1169 | 1169 | .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst), |
| 1170 | .reify_int => try sema.zirReifyInt(block, inst), |
| 1170 | 1171 | .vector_type => try sema.zirVectorType(block, inst), |
| 1171 | 1172 | .as_node => try sema.zirAsNode(block, inst), |
| 1172 | 1173 | .as_shift_operand => try sema.zirAsShiftOperand(block, inst), |
| ... | ... | @@ -1411,7 +1412,6 @@ fn analyzeBodyInner( |
| 1411 | 1412 | .select => try sema.zirSelect( block, extended), |
| 1412 | 1413 | .int_from_error => try sema.zirIntFromError( block, extended), |
| 1413 | 1414 | .error_from_int => try sema.zirErrorFromInt( block, extended), |
| 1414 | | .reify => try sema.zirReify( block, extended, inst), |
| 1415 | 1415 | .cmpxchg => try sema.zirCmpxchg( block, extended), |
| 1416 | 1416 | .c_va_arg => try sema.zirCVaArg( block, extended), |
| 1417 | 1417 | .c_va_copy => try sema.zirCVaCopy( block, extended), |
| ... | ... | @@ -1424,6 +1424,16 @@ fn analyzeBodyInner( |
| 1424 | 1424 | .work_group_id => try sema.zirWorkItem( block, extended, extended.opcode), |
| 1425 | 1425 | .in_comptime => try sema.zirInComptime( block), |
| 1426 | 1426 | .closure_get => try sema.zirClosureGet( block, extended), |
| 1427 | |
| 1428 | .reify_slice_arg_ty => try sema.zirReifySliceArgTy( block, extended), |
| 1429 | .reify_enum_value_slice_ty => try sema.zirReifyEnumValueSliceTy(block, extended), |
| 1430 | .reify_pointer_sentinel_ty => try sema.zirReifyPointerSentinelTy(block, extended), |
| 1431 | .reify_tuple => try sema.zirReifyTuple( block, extended), |
| 1432 | .reify_pointer => try sema.zirReifyPointer( block, extended), |
| 1433 | .reify_fn => try sema.zirReifyFn( block, extended), |
| 1434 | .reify_struct => try sema.zirReifyStruct( block, extended, inst), |
| 1435 | .reify_union => try sema.zirReifyUnion( block, extended, inst), |
| 1436 | .reify_enum => try sema.zirReifyEnum( block, extended, inst), |
| 1427 | 1437 | // zig fmt: on |
| 1428 | 1438 | |
| 1429 | 1439 | .set_float_mode => { |
| ... | ... | @@ -3517,10 +3527,8 @@ fn zirOpaqueDecl( |
| 3517 | 3527 | extra_index += captures_len * 2; |
| 3518 | 3528 | |
| 3519 | 3529 | const opaque_init: InternPool.OpaqueTypeInit = .{ |
| 3520 | | .key = .{ .declared = .{ |
| 3521 | | .zir_index = tracked_inst, |
| 3522 | | .captures = captures, |
| 3523 | | } }, |
| 3530 | .zir_index = tracked_inst, |
| 3531 | .captures = captures, |
| 3524 | 3532 | }; |
| 3525 | 3533 | const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) { |
| 3526 | 3534 | .existing => |ty| { |
| ... | ... | @@ -7386,7 +7394,7 @@ fn analyzeCall( |
| 7386 | 7394 | const body = sema.code.bodySlice(extra.end, extra.data.type.body_len); |
| 7387 | 7395 | |
| 7388 | 7396 | generic_block.comptime_reason = .{ .reason = .{ |
| 7389 | | .r = .{ .simple = .function_parameters }, |
| 7397 | .r = .{ .simple = .fn_param_types }, |
| 7390 | 7398 | .src = param_src, |
| 7391 | 7399 | } }; |
| 7392 | 7400 | |
| ... | ... | @@ -7470,7 +7478,7 @@ fn analyzeCall( |
| 7470 | 7478 | sema.inst_map = generic_inst_map; |
| 7471 | 7479 | |
| 7472 | 7480 | generic_block.comptime_reason = .{ .reason = .{ |
| 7473 | | .r = .{ .simple = .function_ret_ty }, |
| 7481 | .r = .{ .simple = .fn_ret_ty }, |
| 7474 | 7482 | .src = func_ret_ty_src, |
| 7475 | 7483 | } }; |
| 7476 | 7484 | |
| ... | ... | @@ -8927,7 +8935,7 @@ fn zirFunc( |
| 8927 | 8935 | const ret_ty_body = sema.code.bodySlice(extra_index, extra.data.ret_ty.body_len); |
| 8928 | 8936 | extra_index += ret_ty_body.len; |
| 8929 | 8937 | |
| 8930 | | const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, .type, .{ .simple = .function_ret_ty }); |
| 8938 | const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, .type, .{ .simple = .fn_ret_ty }); |
| 8931 | 8939 | break :blk ret_ty_val.toType(); |
| 8932 | 8940 | }, |
| 8933 | 8941 | }; |
| ... | ... | @@ -9171,6 +9179,181 @@ fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc: |
| 9171 | 9179 | } |
| 9172 | 9180 | } |
| 9173 | 9181 | |
| 9182 | fn checkParamTypeCommon( |
| 9183 | sema: *Sema, |
| 9184 | block: *Block, |
| 9185 | param_idx: u32, |
| 9186 | param_ty: Type, |
| 9187 | param_is_noalias: bool, |
| 9188 | param_src: LazySrcLoc, |
| 9189 | cc: std.builtin.CallingConvention, |
| 9190 | ) CompileError!void { |
| 9191 | const pt = sema.pt; |
| 9192 | const zcu = pt.zcu; |
| 9193 | const target = zcu.getTarget(); |
| 9194 | |
| 9195 | if (!param_ty.isValidParamType(zcu)) { |
| 9196 | const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; |
| 9197 | return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{ |
| 9198 | opaque_str, param_ty.fmt(pt), |
| 9199 | }); |
| 9200 | } |
| 9201 | if (!param_ty.isGenericPoison() and |
| 9202 | !target_util.fnCallConvAllowsZigTypes(cc) and |
| 9203 | !try sema.validateExternType(param_ty, .param_ty)) |
| 9204 | { |
| 9205 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 9206 | const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{ |
| 9207 | param_ty.fmt(pt), @tagName(cc), |
| 9208 | }); |
| 9209 | errdefer msg.destroy(sema.gpa); |
| 9210 | |
| 9211 | try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty); |
| 9212 | |
| 9213 | try sema.addDeclaredHereNote(msg, param_ty); |
| 9214 | break :msg msg; |
| 9215 | }); |
| 9216 | } |
| 9217 | switch (cc) { |
| 9218 | .x86_64_interrupt, .x86_interrupt => { |
| 9219 | const err_code_size = target.ptrBitWidth(); |
| 9220 | switch (param_idx) { |
| 9221 | 0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{s}' calling convention must be a pointer type", .{@tagName(cc)}), |
| 9222 | 1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{s}' calling convention must be a {d}-bit integer", .{ @tagName(cc), err_code_size }), |
| 9223 | else => return sema.fail(block, param_src, "'{s}' calling convention supports up to 2 parameters, found {d}", .{ @tagName(cc), param_idx + 1 }), |
| 9224 | } |
| 9225 | }, |
| 9226 | .arc_interrupt, |
| 9227 | .arm_interrupt, |
| 9228 | .microblaze_interrupt, |
| 9229 | .mips64_interrupt, |
| 9230 | .mips_interrupt, |
| 9231 | .riscv64_interrupt, |
| 9232 | .riscv32_interrupt, |
| 9233 | .sh_interrupt, |
| 9234 | .avr_interrupt, |
| 9235 | .csky_interrupt, |
| 9236 | .m68k_interrupt, |
| 9237 | .msp430_interrupt, |
| 9238 | .avr_signal, |
| 9239 | => return sema.fail(block, param_src, "parameters are not allowed with '{s}' calling convention", .{@tagName(cc)}), |
| 9240 | else => {}, |
| 9241 | } |
| 9242 | if (param_is_noalias and !param_ty.isGenericPoison() and !param_ty.isPtrAtRuntime(zcu) and !param_ty.isSliceAtRuntime(zcu)) { |
| 9243 | return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{}); |
| 9244 | } |
| 9245 | } |
| 9246 | |
| 9247 | fn checkReturnTypeAndCallConvCommon( |
| 9248 | sema: *Sema, |
| 9249 | block: *Block, |
| 9250 | bare_ret_ty: Type, |
| 9251 | ret_ty_src: LazySrcLoc, |
| 9252 | @"callconv": std.builtin.CallingConvention, |
| 9253 | callconv_src: LazySrcLoc, |
| 9254 | /// non-`null` only if the function is varargs. |
| 9255 | opt_varargs_src: ?LazySrcLoc, |
| 9256 | inferred_error_set: bool, |
| 9257 | is_noinline: bool, |
| 9258 | ) CompileError!void { |
| 9259 | const pt = sema.pt; |
| 9260 | const zcu = pt.zcu; |
| 9261 | const gpa = zcu.gpa; |
| 9262 | if (opt_varargs_src) |varargs_src| { |
| 9263 | try sema.checkCallConvSupportsVarArgs(block, varargs_src, @"callconv"); |
| 9264 | } |
| 9265 | if (inferred_error_set and !bare_ret_ty.isGenericPoison()) { |
| 9266 | try sema.validateErrorUnionPayloadType(block, bare_ret_ty, ret_ty_src); |
| 9267 | } |
| 9268 | const ies_ret_ty_prefix: []const u8 = if (inferred_error_set) "!" else ""; |
| 9269 | if (!bare_ret_ty.isValidReturnType(zcu)) { |
| 9270 | const opaque_str = if (bare_ret_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; |
| 9271 | return sema.fail(block, ret_ty_src, "{s}return type '{s}{f}' not allowed", .{ |
| 9272 | opaque_str, ies_ret_ty_prefix, bare_ret_ty.fmt(pt), |
| 9273 | }); |
| 9274 | } |
| 9275 | if (!bare_ret_ty.isGenericPoison() and |
| 9276 | !target_util.fnCallConvAllowsZigTypes(@"callconv") and |
| 9277 | (inferred_error_set or !try sema.validateExternType(bare_ret_ty, .ret_ty))) |
| 9278 | { |
| 9279 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 9280 | const msg = try sema.errMsg(ret_ty_src, "return type '{s}{f}' not allowed in function with calling convention '{s}'", .{ |
| 9281 | ies_ret_ty_prefix, bare_ret_ty.fmt(pt), @tagName(@"callconv"), |
| 9282 | }); |
| 9283 | errdefer msg.destroy(gpa); |
| 9284 | if (!inferred_error_set) { |
| 9285 | try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, bare_ret_ty, .ret_ty); |
| 9286 | try sema.addDeclaredHereNote(msg, bare_ret_ty); |
| 9287 | } |
| 9288 | break :msg msg; |
| 9289 | }); |
| 9290 | } |
| 9291 | validate_incoming_stack_align: { |
| 9292 | const a: u64 = switch (@"callconv") { |
| 9293 | inline else => |payload| if (@TypeOf(payload) != void and @hasField(@TypeOf(payload), "incoming_stack_alignment")) |
| 9294 | payload.incoming_stack_alignment orelse break :validate_incoming_stack_align |
| 9295 | else |
| 9296 | break :validate_incoming_stack_align, |
| 9297 | }; |
| 9298 | if (!std.math.isPowerOfTwo(a)) { |
| 9299 | return sema.fail(block, callconv_src, "calling convention incoming stack alignment '{d}' is not a power of two", .{a}); |
| 9300 | } |
| 9301 | } |
| 9302 | switch (@"callconv") { |
| 9303 | .x86_64_interrupt, |
| 9304 | .x86_interrupt, |
| 9305 | .arm_interrupt, |
| 9306 | .mips64_interrupt, |
| 9307 | .mips_interrupt, |
| 9308 | .riscv64_interrupt, |
| 9309 | .riscv32_interrupt, |
| 9310 | .sh_interrupt, |
| 9311 | .arc_interrupt, |
| 9312 | .avr_interrupt, |
| 9313 | .csky_interrupt, |
| 9314 | .m68k_interrupt, |
| 9315 | .microblaze_interrupt, |
| 9316 | .msp430_interrupt, |
| 9317 | .avr_signal, |
| 9318 | => { |
| 9319 | const ret_ok = !inferred_error_set and switch (bare_ret_ty.toIntern()) { |
| 9320 | .void_type, .noreturn_type => true, |
| 9321 | else => false, |
| 9322 | }; |
| 9323 | if (!ret_ok) { |
| 9324 | return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(@"callconv")}); |
| 9325 | } |
| 9326 | }, |
| 9327 | .@"inline" => if (is_noinline) { |
| 9328 | return sema.fail(block, callconv_src, "'noinline' function cannot have calling convention 'inline'", .{}); |
| 9329 | }, |
| 9330 | else => {}, |
| 9331 | } |
| 9332 | switch (zcu.callconvSupported(@"callconv")) { |
| 9333 | .ok => {}, |
| 9334 | .bad_arch => |allowed_archs| { |
| 9335 | const ArchListFormatter = struct { |
| 9336 | archs: []const std.Target.Cpu.Arch, |
| 9337 | pub fn format(formatter: @This(), w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 9338 | for (formatter.archs, 0..) |arch, i| { |
| 9339 | if (i != 0) |
| 9340 | try w.writeAll(", "); |
| 9341 | try w.print("'{s}'", .{@tagName(arch)}); |
| 9342 | } |
| 9343 | } |
| 9344 | }; |
| 9345 | return sema.fail(block, callconv_src, "calling convention '{s}' only available on architectures {f}", .{ |
| 9346 | @tagName(@"callconv"), |
| 9347 | ArchListFormatter{ .archs = allowed_archs }, |
| 9348 | }); |
| 9349 | }, |
| 9350 | .bad_backend => |bad_backend| return sema.fail(block, callconv_src, "calling convention '{s}' not supported by compiler backend '{s}'", .{ |
| 9351 | @tagName(@"callconv"), |
| 9352 | @tagName(bad_backend), |
| 9353 | }), |
| 9354 | } |
| 9355 | } |
| 9356 | |
| 9174 | 9357 | fn callConvIsCallable(cc: std.builtin.CallingConvention.Tag) bool { |
| 9175 | 9358 | return switch (cc) { |
| 9176 | 9359 | .naked, |
| ... | ... | @@ -9259,7 +9442,6 @@ fn funcCommon( |
| 9259 | 9442 | const pt = sema.pt; |
| 9260 | 9443 | const zcu = pt.zcu; |
| 9261 | 9444 | const gpa = sema.gpa; |
| 9262 | | const target = zcu.getTarget(); |
| 9263 | 9445 | const ip = &zcu.intern_pool; |
| 9264 | 9446 | const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset }); |
| 9265 | 9447 | const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset }); |
| ... | ... | @@ -9293,26 +9475,14 @@ fn funcCommon( |
| 9293 | 9475 | if (param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc)) { |
| 9294 | 9476 | return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); |
| 9295 | 9477 | } |
| 9296 | | if (!param_ty.isValidParamType(zcu)) { |
| 9297 | | const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; |
| 9298 | | return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{ |
| 9299 | | opaque_str, param_ty.fmt(pt), |
| 9300 | | }); |
| 9301 | | } |
| 9302 | | if (!param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc) and !try sema.validateExternType(param_ty, .param_ty)) { |
| 9303 | | const msg = msg: { |
| 9304 | | const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{ |
| 9305 | | param_ty.fmt(pt), @tagName(cc), |
| 9306 | | }); |
| 9307 | | errdefer msg.destroy(sema.gpa); |
| 9308 | | |
| 9309 | | try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty); |
| 9310 | | |
| 9311 | | try sema.addDeclaredHereNote(msg, param_ty); |
| 9312 | | break :msg msg; |
| 9313 | | }; |
| 9314 | | return sema.failWithOwnedErrorMsg(block, msg); |
| 9315 | | } |
| 9478 | try sema.checkParamTypeCommon( |
| 9479 | block, |
| 9480 | @intCast(i), |
| 9481 | param_ty, |
| 9482 | is_noalias, |
| 9483 | param_src, |
| 9484 | cc, |
| 9485 | ); |
| 9316 | 9486 | if (param_ty_comptime and !param_is_comptime and has_body and !block.isComptime()) { |
| 9317 | 9487 | const msg = msg: { |
| 9318 | 9488 | const msg = try sema.errMsg(param_src, "parameter of type '{f}' must be declared comptime", .{ |
| ... | ... | @@ -9327,209 +9497,40 @@ fn funcCommon( |
| 9327 | 9497 | }; |
| 9328 | 9498 | return sema.failWithOwnedErrorMsg(block, msg); |
| 9329 | 9499 | } |
| 9330 | | if (!param_ty_generic and is_noalias and |
| 9331 | | !(param_ty.zigTypeTag(zcu) == .pointer or param_ty.isPtrLikeOptional(zcu))) |
| 9332 | | { |
| 9333 | | return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{}); |
| 9334 | | } |
| 9335 | | switch (cc) { |
| 9336 | | .x86_64_interrupt, .x86_interrupt => { |
| 9337 | | const err_code_size = target.ptrBitWidth(); |
| 9338 | | switch (i) { |
| 9339 | | 0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{s}' calling convention must be a pointer type", .{@tagName(cc)}), |
| 9340 | | 1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{s}' calling convention must be a {d}-bit integer", .{ @tagName(cc), err_code_size }), |
| 9341 | | else => return sema.fail(block, param_src, "'{s}' calling convention supports up to 2 parameters, found {d}", .{ @tagName(cc), i + 1 }), |
| 9342 | | } |
| 9343 | | }, |
| 9344 | | .arc_interrupt, |
| 9345 | | .arm_interrupt, |
| 9346 | | .microblaze_interrupt, |
| 9347 | | .mips64_interrupt, |
| 9348 | | .mips_interrupt, |
| 9349 | | .riscv64_interrupt, |
| 9350 | | .riscv32_interrupt, |
| 9351 | | .sh_interrupt, |
| 9352 | | .avr_interrupt, |
| 9353 | | .csky_interrupt, |
| 9354 | | .m68k_interrupt, |
| 9355 | | .msp430_interrupt, |
| 9356 | | .avr_signal, |
| 9357 | | => return sema.fail(block, param_src, "parameters are not allowed with '{s}' calling convention", .{@tagName(cc)}), |
| 9358 | | else => {}, |
| 9359 | | } |
| 9360 | | } |
| 9361 | | |
| 9362 | | if (var_args) { |
| 9363 | | if (is_generic) { |
| 9364 | | return sema.fail(block, func_src, "generic function cannot be variadic", .{}); |
| 9365 | | } |
| 9366 | | const va_args_src = block.src(.{ |
| 9367 | | .fn_proto_param = .{ |
| 9368 | | .fn_proto_node_offset = src_node_offset, |
| 9369 | | .param_index = @intCast(block.params.len), // va_arg must be the last parameter |
| 9370 | | }, |
| 9371 | | }); |
| 9372 | | try sema.checkCallConvSupportsVarArgs(block, va_args_src, cc); |
| 9373 | | } |
| 9374 | | |
| 9375 | | const ret_poison = bare_return_type.isGenericPoison(); |
| 9376 | | |
| 9377 | | const param_types = block.params.items(.ty); |
| 9378 | | |
| 9379 | | if (inferred_error_set) { |
| 9380 | | assert(has_body); |
| 9381 | | if (!ret_poison) |
| 9382 | | try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src); |
| 9383 | | const func_index = try ip.getFuncDeclIes(gpa, pt.tid, .{ |
| 9384 | | .owner_nav = sema.owner.unwrap().nav_val, |
| 9385 | | |
| 9386 | | .param_types = param_types, |
| 9387 | | .noalias_bits = noalias_bits, |
| 9388 | | .comptime_bits = comptime_bits, |
| 9389 | | .bare_return_type = bare_return_type.toIntern(), |
| 9390 | | .cc = cc, |
| 9391 | | .is_var_args = var_args, |
| 9392 | | .is_generic = is_generic, |
| 9393 | | .is_noinline = is_noinline, |
| 9394 | | |
| 9395 | | .zir_body_inst = try block.trackZir(func_inst), |
| 9396 | | .lbrace_line = src_locs.lbrace_line, |
| 9397 | | .rbrace_line = src_locs.rbrace_line, |
| 9398 | | .lbrace_column = @as(u16, @truncate(src_locs.columns)), |
| 9399 | | .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)), |
| 9400 | | }); |
| 9401 | | return finishFunc( |
| 9402 | | sema, |
| 9403 | | block, |
| 9404 | | func_index, |
| 9405 | | .none, |
| 9406 | | ret_poison, |
| 9407 | | bare_return_type, |
| 9408 | | ret_ty_src, |
| 9409 | | cc, |
| 9410 | | ret_ty_requires_comptime, |
| 9411 | | func_inst, |
| 9412 | | cc_src, |
| 9413 | | is_noinline, |
| 9414 | | ); |
| 9415 | 9500 | } |
| 9416 | 9501 | |
| 9417 | | const func_ty = try ip.getFuncType(gpa, pt.tid, .{ |
| 9418 | | .param_types = param_types, |
| 9419 | | .noalias_bits = noalias_bits, |
| 9420 | | .comptime_bits = comptime_bits, |
| 9421 | | .return_type = bare_return_type.toIntern(), |
| 9422 | | .cc = cc, |
| 9423 | | .is_var_args = var_args, |
| 9424 | | .is_generic = is_generic, |
| 9425 | | .is_noinline = is_noinline, |
| 9426 | | }); |
| 9427 | | |
| 9428 | | if (has_body) { |
| 9429 | | const func_index = try ip.getFuncDecl(gpa, pt.tid, .{ |
| 9430 | | .owner_nav = sema.owner.unwrap().nav_val, |
| 9431 | | .ty = func_ty, |
| 9432 | | .cc = cc, |
| 9433 | | .is_noinline = is_noinline, |
| 9434 | | .zir_body_inst = try block.trackZir(func_inst), |
| 9435 | | .lbrace_line = src_locs.lbrace_line, |
| 9436 | | .rbrace_line = src_locs.rbrace_line, |
| 9437 | | .lbrace_column = @as(u16, @truncate(src_locs.columns)), |
| 9438 | | .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)), |
| 9439 | | }); |
| 9440 | | return finishFunc( |
| 9441 | | sema, |
| 9442 | | block, |
| 9443 | | func_index, |
| 9444 | | func_ty, |
| 9445 | | ret_poison, |
| 9446 | | bare_return_type, |
| 9447 | | ret_ty_src, |
| 9448 | | cc, |
| 9449 | | ret_ty_requires_comptime, |
| 9450 | | func_inst, |
| 9451 | | cc_src, |
| 9452 | | is_noinline, |
| 9453 | | ); |
| 9502 | if (var_args and is_generic) { |
| 9503 | return sema.fail(block, func_src, "generic function cannot be variadic", .{}); |
| 9454 | 9504 | } |
| 9455 | 9505 | |
| 9456 | | return finishFunc( |
| 9457 | | sema, |
| 9506 | try sema.checkReturnTypeAndCallConvCommon( |
| 9458 | 9507 | block, |
| 9459 | | .none, |
| 9460 | | func_ty, |
| 9461 | | ret_poison, |
| 9462 | 9508 | bare_return_type, |
| 9463 | 9509 | ret_ty_src, |
| 9464 | 9510 | cc, |
| 9465 | | ret_ty_requires_comptime, |
| 9466 | | func_inst, |
| 9467 | 9511 | cc_src, |
| 9512 | if (var_args) block.src(.{ .fn_proto_param = .{ |
| 9513 | .fn_proto_node_offset = src_node_offset, |
| 9514 | .param_index = @intCast(block.params.len), |
| 9515 | } }) else null, |
| 9516 | inferred_error_set, |
| 9468 | 9517 | is_noinline, |
| 9469 | 9518 | ); |
| 9470 | | } |
| 9471 | | |
| 9472 | | fn finishFunc( |
| 9473 | | sema: *Sema, |
| 9474 | | block: *Block, |
| 9475 | | opt_func_index: InternPool.Index, |
| 9476 | | func_ty: InternPool.Index, |
| 9477 | | ret_poison: bool, |
| 9478 | | bare_return_type: Type, |
| 9479 | | ret_ty_src: LazySrcLoc, |
| 9480 | | cc_resolved: std.builtin.CallingConvention, |
| 9481 | | ret_ty_requires_comptime: bool, |
| 9482 | | func_inst: Zir.Inst.Index, |
| 9483 | | cc_src: LazySrcLoc, |
| 9484 | | is_noinline: bool, |
| 9485 | | ) CompileError!Air.Inst.Ref { |
| 9486 | | const pt = sema.pt; |
| 9487 | | const zcu = pt.zcu; |
| 9488 | | const ip = &zcu.intern_pool; |
| 9489 | | const gpa = sema.gpa; |
| 9490 | | |
| 9491 | | const return_type: Type = if (opt_func_index == .none or ret_poison) |
| 9492 | | bare_return_type |
| 9493 | | else |
| 9494 | | .fromInterned(ip.funcTypeReturnType(ip.typeOf(opt_func_index))); |
| 9495 | | |
| 9496 | | if (!return_type.isValidReturnType(zcu)) { |
| 9497 | | const opaque_str = if (return_type.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; |
| 9498 | | return sema.fail(block, ret_ty_src, "{s}return type '{f}' not allowed", .{ |
| 9499 | | opaque_str, return_type.fmt(pt), |
| 9500 | | }); |
| 9501 | | } |
| 9502 | | if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(cc_resolved) and |
| 9503 | | !try sema.validateExternType(return_type, .ret_ty)) |
| 9504 | | { |
| 9505 | | const msg = msg: { |
| 9506 | | const msg = try sema.errMsg(ret_ty_src, "return type '{f}' not allowed in function with calling convention '{s}'", .{ |
| 9507 | | return_type.fmt(pt), @tagName(cc_resolved), |
| 9508 | | }); |
| 9509 | | errdefer msg.destroy(gpa); |
| 9510 | | |
| 9511 | | try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, return_type, .ret_ty); |
| 9512 | | |
| 9513 | | try sema.addDeclaredHereNote(msg, return_type); |
| 9514 | | break :msg msg; |
| 9515 | | }; |
| 9516 | | return sema.failWithOwnedErrorMsg(block, msg); |
| 9517 | | } |
| 9518 | 9519 | |
| 9519 | 9520 | // If the return type is comptime-only but not dependent on parameters then |
| 9520 | 9521 | // all parameter types also need to be comptime. |
| 9521 | | if (opt_func_index != .none and ret_ty_requires_comptime and !block.isComptime()) comptime_check: { |
| 9522 | if (has_body and ret_ty_requires_comptime and !block.isComptime()) comptime_check: { |
| 9522 | 9523 | for (block.params.items(.is_comptime)) |is_comptime| { |
| 9523 | 9524 | if (!is_comptime) break; |
| 9524 | 9525 | } else break :comptime_check; |
| 9525 | | |
| 9526 | const ies_ret_ty_prefix: []const u8 = if (inferred_error_set) "!" else ""; |
| 9526 | 9527 | const msg = try sema.errMsg( |
| 9527 | 9528 | ret_ty_src, |
| 9528 | | "function with comptime-only return type '{f}' requires all parameters to be comptime", |
| 9529 | | .{return_type.fmt(pt)}, |
| 9529 | "function with comptime-only return type '{s}{f}' requires all parameters to be comptime", |
| 9530 | .{ ies_ret_ty_prefix, bare_return_type.fmt(pt) }, |
| 9530 | 9531 | ); |
| 9531 | 9532 | errdefer msg.destroy(sema.gpa); |
| 9532 | | try sema.explainWhyTypeIsComptime(msg, ret_ty_src, return_type); |
| 9533 | try sema.explainWhyTypeIsComptime(msg, ret_ty_src, bare_return_type); |
| 9533 | 9534 | |
| 9534 | 9535 | const tags = sema.code.instructions.items(.tag); |
| 9535 | 9536 | const data = sema.code.instructions.items(.data); |
| ... | ... | @@ -9556,68 +9557,56 @@ fn finishFunc( |
| 9556 | 9557 | return sema.failWithOwnedErrorMsg(block, msg); |
| 9557 | 9558 | } |
| 9558 | 9559 | |
| 9559 | | validate_incoming_stack_align: { |
| 9560 | | const a: u64 = switch (cc_resolved) { |
| 9561 | | inline else => |payload| if (@TypeOf(payload) != void and @hasField(@TypeOf(payload), "incoming_stack_alignment")) |
| 9562 | | payload.incoming_stack_alignment orelse break :validate_incoming_stack_align |
| 9563 | | else |
| 9564 | | break :validate_incoming_stack_align, |
| 9565 | | }; |
| 9566 | | if (!std.math.isPowerOfTwo(a)) { |
| 9567 | | return sema.fail(block, cc_src, "calling convention incoming stack alignment '{d}' is not a power of two", .{a}); |
| 9568 | | } |
| 9569 | | } |
| 9560 | const param_types = block.params.items(.ty); |
| 9570 | 9561 | |
| 9571 | | switch (cc_resolved) { |
| 9572 | | .x86_64_interrupt, |
| 9573 | | .x86_interrupt, |
| 9574 | | .arm_interrupt, |
| 9575 | | .mips64_interrupt, |
| 9576 | | .mips_interrupt, |
| 9577 | | .riscv64_interrupt, |
| 9578 | | .riscv32_interrupt, |
| 9579 | | .sh_interrupt, |
| 9580 | | .arc_interrupt, |
| 9581 | | .avr_interrupt, |
| 9582 | | .csky_interrupt, |
| 9583 | | .m68k_interrupt, |
| 9584 | | .microblaze_interrupt, |
| 9585 | | .msp430_interrupt, |
| 9586 | | .avr_signal, |
| 9587 | | => if (return_type.zigTypeTag(zcu) != .void and return_type.zigTypeTag(zcu) != .noreturn) { |
| 9588 | | return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(cc_resolved)}); |
| 9589 | | }, |
| 9590 | | .@"inline" => if (is_noinline) { |
| 9591 | | return sema.fail(block, cc_src, "'noinline' function cannot have calling convention 'inline'", .{}); |
| 9592 | | }, |
| 9593 | | else => {}, |
| 9562 | if (inferred_error_set) { |
| 9563 | assert(has_body); |
| 9564 | return .fromIntern(try ip.getFuncDeclIes(gpa, pt.tid, .{ |
| 9565 | .owner_nav = sema.owner.unwrap().nav_val, |
| 9566 | |
| 9567 | .param_types = param_types, |
| 9568 | .noalias_bits = noalias_bits, |
| 9569 | .comptime_bits = comptime_bits, |
| 9570 | .bare_return_type = bare_return_type.toIntern(), |
| 9571 | .cc = cc, |
| 9572 | .is_var_args = var_args, |
| 9573 | .is_generic = is_generic, |
| 9574 | .is_noinline = is_noinline, |
| 9575 | |
| 9576 | .zir_body_inst = try block.trackZir(func_inst), |
| 9577 | .lbrace_line = src_locs.lbrace_line, |
| 9578 | .rbrace_line = src_locs.rbrace_line, |
| 9579 | .lbrace_column = @as(u16, @truncate(src_locs.columns)), |
| 9580 | .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)), |
| 9581 | })); |
| 9594 | 9582 | } |
| 9595 | 9583 | |
| 9596 | | switch (zcu.callconvSupported(cc_resolved)) { |
| 9597 | | .ok => {}, |
| 9598 | | .bad_arch => |allowed_archs| { |
| 9599 | | const ArchListFormatter = struct { |
| 9600 | | archs: []const std.Target.Cpu.Arch, |
| 9601 | | pub fn format(formatter: @This(), w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 9602 | | for (formatter.archs, 0..) |arch, i| { |
| 9603 | | if (i != 0) |
| 9604 | | try w.writeAll(", "); |
| 9605 | | try w.print("'{s}'", .{@tagName(arch)}); |
| 9606 | | } |
| 9607 | | } |
| 9608 | | }; |
| 9609 | | return sema.fail(block, cc_src, "calling convention '{s}' only available on architectures {f}", .{ |
| 9610 | | @tagName(cc_resolved), |
| 9611 | | ArchListFormatter{ .archs = allowed_archs }, |
| 9612 | | }); |
| 9613 | | }, |
| 9614 | | .bad_backend => |bad_backend| return sema.fail(block, cc_src, "calling convention '{s}' not supported by compiler backend '{s}'", .{ |
| 9615 | | @tagName(cc_resolved), |
| 9616 | | @tagName(bad_backend), |
| 9617 | | }), |
| 9584 | const func_ty = try ip.getFuncType(gpa, pt.tid, .{ |
| 9585 | .param_types = param_types, |
| 9586 | .noalias_bits = noalias_bits, |
| 9587 | .comptime_bits = comptime_bits, |
| 9588 | .return_type = bare_return_type.toIntern(), |
| 9589 | .cc = cc, |
| 9590 | .is_var_args = var_args, |
| 9591 | .is_generic = is_generic, |
| 9592 | .is_noinline = is_noinline, |
| 9593 | }); |
| 9594 | |
| 9595 | if (has_body) { |
| 9596 | return .fromIntern(try ip.getFuncDecl(gpa, pt.tid, .{ |
| 9597 | .owner_nav = sema.owner.unwrap().nav_val, |
| 9598 | .ty = func_ty, |
| 9599 | .cc = cc, |
| 9600 | .is_noinline = is_noinline, |
| 9601 | .zir_body_inst = try block.trackZir(func_inst), |
| 9602 | .lbrace_line = src_locs.lbrace_line, |
| 9603 | .rbrace_line = src_locs.rbrace_line, |
| 9604 | .lbrace_column = @as(u16, @truncate(src_locs.columns)), |
| 9605 | .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)), |
| 9606 | })); |
| 9618 | 9607 | } |
| 9619 | 9608 | |
| 9620 | | return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty); |
| 9609 | return .fromIntern(func_ty); |
| 9621 | 9610 | } |
| 9622 | 9611 | |
| 9623 | 9612 | fn zirParam( |
| ... | ... | @@ -19395,7 +19384,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 19395 | 19384 | if (union_ty.zigTypeTag(pt.zcu) != .@"union") { |
| 19396 | 19385 | return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)}); |
| 19397 | 19386 | } |
| 19398 | | const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_name }); |
| 19387 | const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_names }); |
| 19399 | 19388 | const init = try sema.resolveInst(extra.init); |
| 19400 | 19389 | return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src); |
| 19401 | 19390 | } |
| ... | ... | @@ -20553,589 +20542,529 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 20553 | 20542 | return block.addUnOp(.tag_name, casted_operand); |
| 20554 | 20543 | } |
| 20555 | 20544 | |
| 20556 | | fn zirReify( |
| 20545 | fn zirReifyInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20546 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; |
| 20547 | const signedness_src = block.builtinCallArgSrc(inst_data.src_node, 0); |
| 20548 | const bits_src = block.builtinCallArgSrc(inst_data.src_node, 1); |
| 20549 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 20550 | const signedness = try sema.resolveBuiltinEnum(block, signedness_src, extra.lhs, .Signedness, .{ .simple = .int_signedness }); |
| 20551 | const bits: u16 = @intCast(try sema.resolveInt(block, bits_src, extra.rhs, .u16, .{ .simple = .int_bit_width })); |
| 20552 | return .fromType(try sema.pt.intType(signedness, bits)); |
| 20553 | } |
| 20554 | |
| 20555 | fn zirReifySliceArgTy( |
| 20557 | 20556 | sema: *Sema, |
| 20558 | 20557 | block: *Block, |
| 20559 | 20558 | extended: Zir.Inst.Extended.InstData, |
| 20560 | | inst: Zir.Inst.Index, |
| 20561 | 20559 | ) CompileError!Air.Inst.Ref { |
| 20562 | 20560 | const pt = sema.pt; |
| 20563 | 20561 | const zcu = pt.zcu; |
| 20564 | | const gpa = sema.gpa; |
| 20565 | | const ip = &zcu.intern_pool; |
| 20566 | | const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small); |
| 20567 | | const extra = sema.code.extraData(Zir.Inst.Reify, extended.operand).data; |
| 20568 | | const tracked_inst = try block.trackZir(inst); |
| 20569 | | const src: LazySrcLoc = .{ |
| 20570 | | .base_node_inst = tracked_inst, |
| 20571 | | .offset = LazySrcLoc.Offset.nodeOffset(.zero), |
| 20572 | | }; |
| 20573 | | const operand_src: LazySrcLoc = .{ |
| 20574 | | .base_node_inst = tracked_inst, |
| 20575 | | .offset = .{ |
| 20576 | | .node_offset_builtin_call_arg = .{ |
| 20577 | | .builtin_call_node = .zero, // `tracked_inst` is precisely the `reify` instruction, so offset is 0 |
| 20578 | | .arg_index = 0, |
| 20579 | | }, |
| 20580 | | }, |
| 20562 | |
| 20563 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 20564 | const info: Zir.Inst.ReifySliceArgInfo = @enumFromInt(extended.small); |
| 20565 | |
| 20566 | const src = block.nodeOffset(extra.node); |
| 20567 | |
| 20568 | const comptime_reason: std.zig.SimpleComptimeReason, const in_scalar_ty: Type, const out_scalar_ty: Type = switch (info) { |
| 20569 | // zig fmt: off |
| 20570 | .type_to_fn_param_attrs => .{ .fn_param_attrs, .type, try sema.getBuiltinType(src, .@"Type.Fn.Param.Attributes") }, |
| 20571 | .string_to_struct_field_type => .{ .struct_field_types, .slice_const_u8, .type }, |
| 20572 | .string_to_union_field_type => .{ .union_field_types, .slice_const_u8, .type }, |
| 20573 | .string_to_struct_field_attrs => .{ .struct_field_attrs, .slice_const_u8, try sema.getBuiltinType(src, .@"Type.StructField.Attributes") }, |
| 20574 | .string_to_union_field_attrs => .{ .union_field_attrs, .slice_const_u8, try sema.getBuiltinType(src, .@"Type.UnionField.Attributes") }, |
| 20575 | // zig fmt: on |
| 20581 | 20576 | }; |
| 20582 | | const type_info_ty = try sema.getBuiltinType(src, .Type); |
| 20583 | | const uncasted_operand = try sema.resolveInst(extra.operand); |
| 20584 | | const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); |
| 20585 | | const val = try sema.resolveConstDefinedValue(block, operand_src, type_info, .{ .simple = .operand_Type }); |
| 20586 | | const union_val = ip.indexToKey(val.toIntern()).un; |
| 20587 | | if (try sema.anyUndef(block, operand_src, Value.fromInterned(union_val.val))) { |
| 20588 | | return sema.failWithUseOfUndef(block, operand_src, null); |
| 20589 | | } |
| 20590 | | const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), zcu).?; |
| 20591 | | switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { |
| 20592 | | .type => return .type_type, |
| 20593 | | .void => return .void_type, |
| 20594 | | .bool => return .bool_type, |
| 20595 | | .noreturn => return .noreturn_type, |
| 20596 | | .comptime_float => return .comptime_float_type, |
| 20597 | | .comptime_int => return .comptime_int_type, |
| 20598 | | .undefined => return .undefined_type, |
| 20599 | | .null => return .null_type, |
| 20600 | | .@"anyframe" => return sema.failWithUseOfAsync(block, src), |
| 20601 | | .enum_literal => return .enum_literal_type, |
| 20602 | | .int => { |
| 20603 | | const int = try sema.interpretBuiltinType(block, operand_src, .fromInterned(union_val.val), std.builtin.Type.Int); |
| 20604 | | const ty = try pt.intType(int.signedness, int.bits); |
| 20605 | | return Air.internedToRef(ty.toIntern()); |
| 20606 | | }, |
| 20607 | | .vector => { |
| 20608 | | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| 20609 | | const len_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20610 | | ip, |
| 20611 | | try ip.getOrPutString(gpa, pt.tid, "len", .no_embedded_nulls), |
| 20612 | | ).?); |
| 20613 | | const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20614 | | ip, |
| 20615 | | try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls), |
| 20616 | | ).?); |
| 20617 | | |
| 20618 | | const len: u32 = @intCast(try len_val.toUnsignedIntSema(pt)); |
| 20619 | | const child_ty = child_val.toType(); |
| 20620 | | |
| 20621 | | try sema.checkVectorElemType(block, src, child_ty); |
| 20622 | | |
| 20623 | | const ty = try pt.vectorType(.{ |
| 20624 | | .len = len, |
| 20625 | | .child = child_ty.toIntern(), |
| 20626 | | }); |
| 20627 | | return Air.internedToRef(ty.toIntern()); |
| 20628 | | }, |
| 20629 | | .float => { |
| 20630 | | const float = try sema.interpretBuiltinType(block, operand_src, .fromInterned(union_val.val), std.builtin.Type.Float); |
| 20631 | | |
| 20632 | | const ty: Type = switch (float.bits) { |
| 20633 | | 16 => .f16, |
| 20634 | | 32 => .f32, |
| 20635 | | 64 => .f64, |
| 20636 | | 80 => .f80, |
| 20637 | | 128 => .f128, |
| 20638 | | else => return sema.fail(block, src, "{d}-bit float unsupported", .{float.bits}), |
| 20639 | | }; |
| 20640 | | return Air.internedToRef(ty.toIntern()); |
| 20641 | | }, |
| 20642 | | .pointer => { |
| 20643 | | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| 20644 | | const size_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20645 | | ip, |
| 20646 | | try ip.getOrPutString(gpa, pt.tid, "size", .no_embedded_nulls), |
| 20647 | | ).?); |
| 20648 | | const is_const_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20649 | | ip, |
| 20650 | | try ip.getOrPutString(gpa, pt.tid, "is_const", .no_embedded_nulls), |
| 20651 | | ).?); |
| 20652 | | const is_volatile_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20653 | | ip, |
| 20654 | | try ip.getOrPutString(gpa, pt.tid, "is_volatile", .no_embedded_nulls), |
| 20655 | | ).?); |
| 20656 | | const alignment_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20657 | | ip, |
| 20658 | | try ip.getOrPutString(gpa, pt.tid, "alignment", .no_embedded_nulls), |
| 20659 | | ).?); |
| 20660 | | const address_space_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20661 | | ip, |
| 20662 | | try ip.getOrPutString(gpa, pt.tid, "address_space", .no_embedded_nulls), |
| 20663 | | ).?); |
| 20664 | | const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20665 | | ip, |
| 20666 | | try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls), |
| 20667 | | ).?); |
| 20668 | | const is_allowzero_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20669 | | ip, |
| 20670 | | try ip.getOrPutString(gpa, pt.tid, "is_allowzero", .no_embedded_nulls), |
| 20671 | | ).?); |
| 20672 | | const sentinel_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20673 | | ip, |
| 20674 | | try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls), |
| 20675 | | ).?); |
| 20676 | | |
| 20677 | | if (!try sema.intFitsInType(alignment_val, align_ty, null)) { |
| 20678 | | return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)}); |
| 20679 | | } |
| 20680 | | const alignment_val_int = try alignment_val.toUnsignedIntSema(pt); |
| 20681 | | const abi_align = try sema.validateAlign(block, src, alignment_val_int); |
| 20682 | | |
| 20683 | | const elem_ty = child_val.toType(); |
| 20684 | | if (abi_align != .none) { |
| 20685 | | try elem_ty.resolveLayout(pt); |
| 20686 | | } |
| 20687 | | |
| 20688 | | const ptr_size = try sema.interpretBuiltinType(block, operand_src, size_val, std.builtin.Type.Pointer.Size); |
| 20689 | | |
| 20690 | | const actual_sentinel: InternPool.Index = s: { |
| 20691 | | if (!sentinel_val.isNull(zcu)) { |
| 20692 | | if (ptr_size == .one or ptr_size == .c) { |
| 20693 | | return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{}); |
| 20694 | | } |
| 20695 | | const sentinel_ptr_val = sentinel_val.optionalValue(zcu).?; |
| 20696 | | const ptr_ty = try pt.singleMutPtrType(elem_ty); |
| 20697 | | const sent_val = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?; |
| 20698 | | try sema.checkSentinelType(block, src, elem_ty); |
| 20699 | | if (sent_val.canMutateComptimeVarState(zcu)) { |
| 20700 | | const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls); |
| 20701 | | return sema.failWithContainsReferenceToComptimeVar(block, src, sentinel_name, "sentinel", sent_val); |
| 20702 | | } |
| 20703 | | break :s sent_val.toIntern(); |
| 20704 | | } |
| 20705 | | break :s .none; |
| 20706 | | }; |
| 20707 | 20577 | |
| 20708 | | if (elem_ty.zigTypeTag(zcu) == .noreturn) { |
| 20709 | | return sema.fail(block, src, "pointer to noreturn not allowed", .{}); |
| 20710 | | } else if (elem_ty.zigTypeTag(zcu) == .@"fn") { |
| 20711 | | if (ptr_size != .one) { |
| 20712 | | return sema.fail(block, src, "function pointers must be single pointers", .{}); |
| 20713 | | } |
| 20714 | | } else if (ptr_size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") { |
| 20715 | | return sema.fail(block, src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)}); |
| 20716 | | } else if (ptr_size == .c) { |
| 20717 | | if (!try sema.validateExternType(elem_ty, .other)) { |
| 20718 | | const msg = msg: { |
| 20719 | | const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); |
| 20720 | | errdefer msg.destroy(gpa); |
| 20578 | const operand_ty = try pt.ptrTypeSema(.{ |
| 20579 | .child = in_scalar_ty.toIntern(), |
| 20580 | .flags = .{ .size = .slice, .is_const = true }, |
| 20581 | }); |
| 20721 | 20582 | |
| 20722 | | try sema.explainWhyTypeIsNotExtern(msg, src, elem_ty, .other); |
| 20583 | const operand_uncoerced = try sema.resolveInst(extra.operand); |
| 20584 | const operand_coerced = try sema.coerce(block, operand_ty, operand_uncoerced, src); |
| 20585 | const operand_val = try sema.resolveConstDefinedValue(block, src, operand_coerced, .{ .simple = comptime_reason }); |
| 20586 | const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len); |
| 20587 | if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null); |
| 20588 | const len = try len_val.toUnsignedIntSema(pt); |
| 20723 | 20589 | |
| 20724 | | try sema.addDeclaredHereNote(msg, elem_ty); |
| 20725 | | break :msg msg; |
| 20726 | | }; |
| 20727 | | return sema.failWithOwnedErrorMsg(block, msg); |
| 20728 | | } |
| 20729 | | } |
| 20590 | return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{ |
| 20591 | .len = len, |
| 20592 | .child = out_scalar_ty.toIntern(), |
| 20593 | }))); |
| 20594 | } |
| 20730 | 20595 | |
| 20731 | | const ty = try pt.ptrTypeSema(.{ |
| 20732 | | .child = elem_ty.toIntern(), |
| 20733 | | .sentinel = actual_sentinel, |
| 20734 | | .flags = .{ |
| 20735 | | .size = ptr_size, |
| 20736 | | .is_const = is_const_val.toBool(), |
| 20737 | | .is_volatile = is_volatile_val.toBool(), |
| 20738 | | .alignment = abi_align, |
| 20739 | | .address_space = try sema.interpretBuiltinType(block, operand_src, address_space_val, std.builtin.AddressSpace), |
| 20740 | | .is_allowzero = is_allowzero_val.toBool(), |
| 20741 | | }, |
| 20742 | | }); |
| 20743 | | return Air.internedToRef(ty.toIntern()); |
| 20744 | | }, |
| 20745 | | .array => { |
| 20746 | | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| 20747 | | const len_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20748 | | ip, |
| 20749 | | try ip.getOrPutString(gpa, pt.tid, "len", .no_embedded_nulls), |
| 20750 | | ).?); |
| 20751 | | const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20752 | | ip, |
| 20753 | | try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls), |
| 20754 | | ).?); |
| 20755 | | const sentinel_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20756 | | ip, |
| 20757 | | try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls), |
| 20758 | | ).?); |
| 20759 | | |
| 20760 | | const len = try len_val.toUnsignedIntSema(pt); |
| 20761 | | const child_ty = child_val.toType(); |
| 20762 | | const sentinel = if (sentinel_val.optionalValue(zcu)) |p| blk: { |
| 20763 | | const ptr_ty = try pt.singleMutPtrType(child_ty); |
| 20764 | | try sema.checkSentinelType(block, src, child_ty); |
| 20765 | | const sentinel = (try sema.pointerDeref(block, src, p, ptr_ty)).?; |
| 20766 | | if (sentinel.canMutateComptimeVarState(zcu)) { |
| 20767 | | const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls); |
| 20768 | | return sema.failWithContainsReferenceToComptimeVar(block, src, sentinel_name, "sentinel", sentinel); |
| 20769 | | } |
| 20770 | | break :blk sentinel; |
| 20771 | | } else null; |
| 20772 | | |
| 20773 | | const ty = try pt.arrayType(.{ |
| 20774 | | .len = len, |
| 20775 | | .sentinel = if (sentinel) |s| s.toIntern() else .none, |
| 20776 | | .child = child_ty.toIntern(), |
| 20777 | | }); |
| 20778 | | return Air.internedToRef(ty.toIntern()); |
| 20779 | | }, |
| 20780 | | .optional => { |
| 20781 | | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| 20782 | | const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20783 | | ip, |
| 20784 | | try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls), |
| 20785 | | ).?); |
| 20596 | fn zirReifyEnumValueSliceTy( |
| 20597 | sema: *Sema, |
| 20598 | block: *Block, |
| 20599 | extended: Zir.Inst.Extended.InstData, |
| 20600 | ) CompileError!Air.Inst.Ref { |
| 20601 | const pt = sema.pt; |
| 20602 | const zcu = pt.zcu; |
| 20786 | 20603 | |
| 20787 | | const child_ty = child_val.toType(); |
| 20604 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 20788 | 20605 | |
| 20789 | | const ty = try pt.optionalType(child_ty.toIntern()); |
| 20790 | | return Air.internedToRef(ty.toIntern()); |
| 20791 | | }, |
| 20792 | | .error_union => { |
| 20793 | | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| 20794 | | const error_set_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20795 | | ip, |
| 20796 | | try ip.getOrPutString(gpa, pt.tid, "error_set", .no_embedded_nulls), |
| 20797 | | ).?); |
| 20798 | | const payload_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20799 | | ip, |
| 20800 | | try ip.getOrPutString(gpa, pt.tid, "payload", .no_embedded_nulls), |
| 20801 | | ).?); |
| 20606 | const int_tag_ty_src = block.builtinCallArgSrc(extra.node, 0); |
| 20607 | const field_names_src = block.builtinCallArgSrc(extra.node, 2); |
| 20802 | 20608 | |
| 20803 | | const error_set_ty = error_set_val.toType(); |
| 20804 | | const payload_ty = payload_val.toType(); |
| 20609 | const int_tag_ty = try sema.resolveType(block, int_tag_ty_src, extra.lhs); |
| 20805 | 20610 | |
| 20806 | | if (error_set_ty.zigTypeTag(zcu) != .error_set) { |
| 20807 | | return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{}); |
| 20808 | | } |
| 20611 | const operand_uncoerced = try sema.resolveInst(extra.rhs); |
| 20612 | const operand_coerced = try sema.coerce(block, .slice_const_slice_const_u8, operand_uncoerced, field_names_src); |
| 20613 | const operand_val = try sema.resolveConstDefinedValue(block, field_names_src, operand_coerced, .{ .simple = .enum_field_names }); |
| 20614 | const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len); |
| 20615 | if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, field_names_src, null); |
| 20616 | const len = try len_val.toUnsignedIntSema(pt); |
| 20809 | 20617 | |
| 20810 | | const ty = try pt.errorUnionType(error_set_ty, payload_ty); |
| 20811 | | return Air.internedToRef(ty.toIntern()); |
| 20812 | | }, |
| 20813 | | .error_set => { |
| 20814 | | const payload_val = Value.fromInterned(union_val.val).optionalValue(zcu) orelse |
| 20815 | | return .anyerror_type; |
| 20618 | return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{ |
| 20619 | .len = len, |
| 20620 | .child = int_tag_ty.toIntern(), |
| 20621 | }))); |
| 20622 | } |
| 20623 | |
| 20624 | fn zirReifyPointerSentinelTy( |
| 20625 | sema: *Sema, |
| 20626 | block: *Block, |
| 20627 | extended: Zir.Inst.Extended.InstData, |
| 20628 | ) CompileError!Air.Inst.Ref { |
| 20629 | const pt = sema.pt; |
| 20630 | const zcu = pt.zcu; |
| 20631 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 20632 | const src = block.nodeOffset(extra.node); |
| 20633 | const elem_ty = try sema.resolveType(block, src, extra.operand); |
| 20634 | return .fromType(switch (elem_ty.zigTypeTag(zcu)) { |
| 20635 | else => try pt.optionalType(elem_ty.toIntern()), |
| 20636 | // These types cannot be the child of an optional. To allow reifying pointers to them still, |
| 20637 | // we treat the "sentinel" argument to `@Pointer` as `?noreturn` instead of `?T`. |
| 20638 | .@"opaque", .null => .optional_noreturn, |
| 20639 | }); |
| 20640 | } |
| 20816 | 20641 | |
| 20817 | | const names_val = try sema.derefSliceAsArray(block, src, payload_val, .{ .simple = .error_set_contents }); |
| 20642 | fn zirReifyTuple( |
| 20643 | sema: *Sema, |
| 20644 | block: *Block, |
| 20645 | extended: Zir.Inst.Extended.InstData, |
| 20646 | ) CompileError!Air.Inst.Ref { |
| 20647 | const pt = sema.pt; |
| 20648 | const zcu = pt.zcu; |
| 20818 | 20649 | |
| 20819 | | const len = try sema.usizeCast(block, src, names_val.typeOf(zcu).arrayLen(zcu)); |
| 20820 | | var names: InferredErrorSet.NameMap = .{}; |
| 20821 | | try names.ensureUnusedCapacity(sema.arena, len); |
| 20822 | | for (0..len) |i| { |
| 20823 | | const elem_val = try names_val.elemValue(pt, i); |
| 20824 | | const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); |
| 20825 | | const name_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex( |
| 20826 | | ip, |
| 20827 | | try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), |
| 20828 | | ).?); |
| 20829 | | |
| 20830 | | const name = try sema.sliceToIpString(block, src, name_val, .{ .simple = .error_set_contents }); |
| 20831 | | _ = try pt.getErrorValue(name); |
| 20832 | | const gop = names.getOrPutAssumeCapacity(name); |
| 20833 | | if (gop.found_existing) { |
| 20834 | | return sema.fail(block, src, "duplicate error '{f}'", .{ |
| 20835 | | name.fmt(ip), |
| 20836 | | }); |
| 20837 | | } |
| 20838 | | } |
| 20650 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 20651 | const operand_src = block.builtinCallArgSrc(extra.node, 0); |
| 20839 | 20652 | |
| 20840 | | const ty = try pt.errorSetFromUnsortedNames(names.keys()); |
| 20841 | | return Air.internedToRef(ty.toIntern()); |
| 20842 | | }, |
| 20843 | | .@"struct" => { |
| 20844 | | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| 20845 | | const layout_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20846 | | ip, |
| 20847 | | try ip.getOrPutString(gpa, pt.tid, "layout", .no_embedded_nulls), |
| 20848 | | ).?); |
| 20849 | | const backing_integer_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20850 | | ip, |
| 20851 | | try ip.getOrPutString(gpa, pt.tid, "backing_integer", .no_embedded_nulls), |
| 20852 | | ).?); |
| 20853 | | const fields_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20854 | | ip, |
| 20855 | | try ip.getOrPutString(gpa, pt.tid, "fields", .no_embedded_nulls), |
| 20856 | | ).?); |
| 20857 | | const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20858 | | ip, |
| 20859 | | try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls), |
| 20860 | | ).?); |
| 20861 | | const is_tuple_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20862 | | ip, |
| 20863 | | try ip.getOrPutString(gpa, pt.tid, "is_tuple", .no_embedded_nulls), |
| 20864 | | ).?); |
| 20865 | | |
| 20866 | | const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout); |
| 20867 | | |
| 20868 | | // Decls |
| 20869 | | if (try decls_val.sliceLen(pt) > 0) { |
| 20870 | | return sema.fail(block, src, "reified structs must have no decls", .{}); |
| 20871 | | } |
| 20872 | | |
| 20873 | | if (layout != .@"packed" and !backing_integer_val.isNull(zcu)) { |
| 20874 | | return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); |
| 20875 | | } |
| 20876 | | |
| 20877 | | const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .struct_fields }); |
| 20878 | | |
| 20879 | | if (is_tuple_val.toBool()) { |
| 20880 | | switch (layout) { |
| 20881 | | .@"extern" => return sema.fail(block, src, "extern tuples are not supported", .{}), |
| 20882 | | .@"packed" => return sema.fail(block, src, "packed tuples are not supported", .{}), |
| 20883 | | .auto => {}, |
| 20884 | | } |
| 20885 | | return sema.reifyTuple(block, src, fields_arr); |
| 20886 | | } else { |
| 20887 | | return sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_arr, name_strategy); |
| 20888 | | } |
| 20889 | | }, |
| 20890 | | .@"enum" => { |
| 20891 | | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| 20892 | | const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20893 | | ip, |
| 20894 | | try ip.getOrPutString(gpa, pt.tid, "tag_type", .no_embedded_nulls), |
| 20895 | | ).?); |
| 20896 | | const fields_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20897 | | ip, |
| 20898 | | try ip.getOrPutString(gpa, pt.tid, "fields", .no_embedded_nulls), |
| 20899 | | ).?); |
| 20900 | | const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20901 | | ip, |
| 20902 | | try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls), |
| 20903 | | ).?); |
| 20904 | | const is_exhaustive_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20905 | | ip, |
| 20906 | | try ip.getOrPutString(gpa, pt.tid, "is_exhaustive", .no_embedded_nulls), |
| 20907 | | ).?); |
| 20908 | | |
| 20909 | | if (try decls_val.sliceLen(pt) > 0) { |
| 20910 | | return sema.fail(block, src, "reified enums must have no decls", .{}); |
| 20911 | | } |
| 20912 | | |
| 20913 | | const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .enum_fields }); |
| 20914 | | |
| 20915 | | return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_arr, name_strategy); |
| 20916 | | }, |
| 20917 | | .@"opaque" => { |
| 20918 | | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| 20919 | | const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20920 | | ip, |
| 20921 | | try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls), |
| 20922 | | ).?); |
| 20653 | const types_uncoerced = try sema.resolveInst(extra.operand); |
| 20654 | const types_coerced = try sema.coerce(block, .slice_const_type, types_uncoerced, operand_src); |
| 20655 | const types_slice_val = try sema.resolveConstDefinedValue(block, operand_src, types_coerced, .{ .simple = .tuple_field_types }); |
| 20656 | const types_array_val = try sema.derefSliceAsArray(block, operand_src, types_slice_val, .{ .simple = .tuple_field_types }); |
| 20657 | const fields_len: u32 = @intCast(types_array_val.typeOf(zcu).arrayLen(zcu)); |
| 20923 | 20658 | |
| 20924 | | // Decls |
| 20925 | | if (try decls_val.sliceLen(pt) > 0) { |
| 20926 | | return sema.fail(block, src, "reified opaque must have no decls", .{}); |
| 20927 | | } |
| 20659 | const field_types = try sema.arena.alloc(InternPool.Index, fields_len); |
| 20660 | for (field_types, 0..) |*field_ty, field_idx| { |
| 20661 | const field_ty_val = try types_array_val.elemValue(pt, field_idx); |
| 20662 | if (field_ty_val.isUndef(zcu)) { |
| 20663 | return sema.failWithUseOfUndef(block, operand_src, null); |
| 20664 | } |
| 20665 | field_ty.* = field_ty_val.toIntern(); |
| 20666 | } |
| 20928 | 20667 | |
| 20929 | | const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, .{ |
| 20930 | | .key = .{ .reified = .{ |
| 20931 | | .zir_index = try block.trackZir(inst), |
| 20932 | | } }, |
| 20933 | | })) { |
| 20934 | | .existing => |ty| { |
| 20935 | | try sema.addTypeReferenceEntry(src, ty); |
| 20936 | | return Air.internedToRef(ty); |
| 20937 | | }, |
| 20938 | | .wip => |wip| wip, |
| 20939 | | }; |
| 20940 | | errdefer wip_ty.cancel(ip, pt.tid); |
| 20668 | const field_values = try sema.arena.alloc(InternPool.Index, fields_len); |
| 20669 | @memset(field_values, .none); |
| 20941 | 20670 | |
| 20942 | | const type_name = try sema.createTypeName( |
| 20943 | | block, |
| 20944 | | name_strategy, |
| 20945 | | "opaque", |
| 20946 | | inst, |
| 20947 | | wip_ty.index, |
| 20948 | | ); |
| 20949 | | wip_ty.setName(ip, type_name.name, type_name.nav); |
| 20671 | return .fromIntern(try zcu.intern_pool.getTupleType(zcu.gpa, pt.tid, .{ |
| 20672 | .types = field_types, |
| 20673 | .values = field_values, |
| 20674 | })); |
| 20675 | } |
| 20950 | 20676 | |
| 20951 | | const new_namespace_index = try pt.createNamespace(.{ |
| 20952 | | .parent = block.namespace.toOptional(), |
| 20953 | | .owner_type = wip_ty.index, |
| 20954 | | .file_scope = block.getFileScopeIndex(zcu), |
| 20955 | | .generation = zcu.generation, |
| 20956 | | }); |
| 20677 | fn zirReifyPointer( |
| 20678 | sema: *Sema, |
| 20679 | block: *Block, |
| 20680 | extended: Zir.Inst.Extended.InstData, |
| 20681 | ) CompileError!Air.Inst.Ref { |
| 20682 | const pt = sema.pt; |
| 20683 | const zcu = pt.zcu; |
| 20684 | const gpa = zcu.gpa; |
| 20685 | const ip = &zcu.intern_pool; |
| 20957 | 20686 | |
| 20958 | | try sema.addTypeReferenceEntry(src, wip_ty.index); |
| 20959 | | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); |
| 20960 | | return Air.internedToRef(wip_ty.finish(ip, new_namespace_index)); |
| 20961 | | }, |
| 20962 | | .@"union" => { |
| 20963 | | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| 20964 | | const layout_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20965 | | ip, |
| 20966 | | try ip.getOrPutString(gpa, pt.tid, "layout", .no_embedded_nulls), |
| 20967 | | ).?); |
| 20968 | | const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20969 | | ip, |
| 20970 | | try ip.getOrPutString(gpa, pt.tid, "tag_type", .no_embedded_nulls), |
| 20971 | | ).?); |
| 20972 | | const fields_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20973 | | ip, |
| 20974 | | try ip.getOrPutString(gpa, pt.tid, "fields", .no_embedded_nulls), |
| 20975 | | ).?); |
| 20976 | | const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 20977 | | ip, |
| 20978 | | try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls), |
| 20979 | | ).?); |
| 20687 | const extra = sema.code.extraData(Zir.Inst.ReifyPointer, extended.operand).data; |
| 20688 | const src = block.nodeOffset(extra.node); |
| 20689 | const size_src = block.builtinCallArgSrc(extra.node, 0); |
| 20690 | const attrs_src = block.builtinCallArgSrc(extra.node, 1); |
| 20691 | const elem_ty_src = block.builtinCallArgSrc(extra.node, 2); |
| 20692 | const sentinel_src = block.builtinCallArgSrc(extra.node, 3); |
| 20693 | |
| 20694 | const size_ty = try sema.getBuiltinType(size_src, .@"Type.Pointer.Size"); |
| 20695 | const attrs_ty = try sema.getBuiltinType(attrs_src, .@"Type.Pointer.Attributes"); |
| 20696 | |
| 20697 | const size_uncoerced = try sema.resolveInst(extra.size); |
| 20698 | const size_coerced = try sema.coerce(block, size_ty, size_uncoerced, size_src); |
| 20699 | const size_val = try sema.resolveConstDefinedValue(block, size_src, size_coerced, .{ .simple = .pointer_size }); |
| 20700 | const size = try sema.interpretBuiltinType(block, size_src, size_val, std.builtin.Type.Pointer.Size); |
| 20701 | |
| 20702 | const attrs_uncoerced = try sema.resolveInst(extra.attrs); |
| 20703 | const attrs_coerced = try sema.coerce(block, attrs_ty, attrs_uncoerced, attrs_src); |
| 20704 | const attrs_val = try sema.resolveConstDefinedValue(block, attrs_src, attrs_coerced, .{ .simple = .pointer_attrs }); |
| 20705 | const attrs = try sema.interpretBuiltinType(block, attrs_src, attrs_val, std.builtin.Type.Pointer.Attributes); |
| 20706 | |
| 20707 | const @"align": Alignment = if (attrs.@"align") |bytes| a: { |
| 20708 | break :a try sema.validateAlign(block, attrs_src, bytes); |
| 20709 | } else .none; |
| 20980 | 20710 | |
| 20981 | | if (try decls_val.sliceLen(pt) > 0) { |
| 20982 | | return sema.fail(block, src, "reified unions must have no decls", .{}); |
| 20983 | | } |
| 20984 | | const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout); |
| 20711 | const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_ty); |
| 20985 | 20712 | |
| 20986 | | const has_tag = tag_type_val.optionalValue(zcu) != null; |
| 20713 | switch (elem_ty.zigTypeTag(zcu)) { |
| 20714 | .noreturn => return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}), |
| 20715 | // This needs to be disallowed, because the sentinel parameter would otherwise have type |
| 20716 | // `?@TypeOf(null)`, which is not a valid type because you cannot differentiate between |
| 20717 | // constructing the "inner" null value and the "outer" null value. |
| 20718 | .null => return sema.fail(block, elem_ty_src, "cannot reify pointer to '@TypeOf(null)'", .{}), |
| 20719 | .@"fn" => switch (size) { |
| 20720 | .one => {}, |
| 20721 | .many, .c, .slice => return sema.fail(block, src, "function pointers must be single pointers", .{}), |
| 20722 | }, |
| 20723 | .@"opaque" => switch (size) { |
| 20724 | .one => {}, |
| 20725 | .many, .c, .slice => return sema.fail(block, src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)}), |
| 20726 | }, |
| 20727 | else => {}, |
| 20728 | } |
| 20987 | 20729 | |
| 20988 | | if (has_tag) { |
| 20989 | | switch (layout) { |
| 20990 | | .@"extern" => return sema.fail(block, src, "extern union does not support enum tag type", .{}), |
| 20991 | | .@"packed" => return sema.fail(block, src, "packed union does not support enum tag type", .{}), |
| 20992 | | .auto => {}, |
| 20993 | | } |
| 20994 | | } |
| 20730 | if (size == .c and !try sema.validateExternType(elem_ty, .other)) { |
| 20731 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 20732 | const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); |
| 20733 | errdefer msg.destroy(gpa); |
| 20734 | try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other); |
| 20735 | try sema.addDeclaredHereNote(msg, elem_ty); |
| 20736 | break :msg msg; |
| 20737 | }); |
| 20738 | } |
| 20995 | 20739 | |
| 20996 | | const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields }); |
| 20740 | const sentinel_ty = try pt.optionalType(elem_ty.toIntern()); |
| 20741 | const sentinel_uncoerced = try sema.resolveInst(extra.sentinel); |
| 20742 | const sentinel_coerced = try sema.coerce(block, sentinel_ty, sentinel_uncoerced, sentinel_src); |
| 20743 | const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel_coerced, .{ .simple = .pointer_sentinel }); |
| 20744 | const opt_sentinel = sentinel_val.optionalValue(zcu); |
| 20745 | if (opt_sentinel) |sentinel| { |
| 20746 | switch (size) { |
| 20747 | .many, .slice => {}, |
| 20748 | .one, .c => return sema.fail(block, sentinel_src, "sentinels are only allowed on slices and unknown-length pointers", .{}), |
| 20749 | } |
| 20750 | try checkSentinelType(sema, block, sentinel_src, elem_ty); |
| 20751 | if (sentinel.canMutateComptimeVarState(zcu)) { |
| 20752 | const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel", .no_embedded_nulls); |
| 20753 | return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", sentinel); |
| 20754 | } |
| 20755 | } |
| 20997 | 20756 | |
| 20998 | | return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy); |
| 20757 | return .fromType(try pt.ptrTypeSema(.{ |
| 20758 | .child = elem_ty.toIntern(), |
| 20759 | .sentinel = if (opt_sentinel) |s| s.toIntern() else .none, |
| 20760 | .flags = .{ |
| 20761 | .size = size, |
| 20762 | .is_const = attrs.@"const", |
| 20763 | .is_volatile = attrs.@"volatile", |
| 20764 | .is_allowzero = attrs.@"allowzero", |
| 20765 | .address_space = attrs.@"addrspace" orelse as: { |
| 20766 | if (elem_ty.zigTypeTag(zcu) == .@"fn" and zcu.getTarget().cpu.arch == .avr) break :as .flash; |
| 20767 | break :as .generic; |
| 20768 | }, |
| 20769 | .alignment = @"align", |
| 20999 | 20770 | }, |
| 21000 | | .@"fn" => { |
| 21001 | | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| 21002 | | const calling_convention_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 21003 | | ip, |
| 21004 | | try ip.getOrPutString(gpa, pt.tid, "calling_convention", .no_embedded_nulls), |
| 21005 | | ).?); |
| 21006 | | const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 21007 | | ip, |
| 21008 | | try ip.getOrPutString(gpa, pt.tid, "is_generic", .no_embedded_nulls), |
| 21009 | | ).?); |
| 21010 | | const is_var_args_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 21011 | | ip, |
| 21012 | | try ip.getOrPutString(gpa, pt.tid, "is_var_args", .no_embedded_nulls), |
| 21013 | | ).?); |
| 21014 | | const return_type_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 21015 | | ip, |
| 21016 | | try ip.getOrPutString(gpa, pt.tid, "return_type", .no_embedded_nulls), |
| 21017 | | ).?); |
| 21018 | | const params_slice_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( |
| 21019 | | ip, |
| 21020 | | try ip.getOrPutString(gpa, pt.tid, "params", .no_embedded_nulls), |
| 21021 | | ).?); |
| 21022 | | |
| 21023 | | const is_generic = is_generic_val.toBool(); |
| 21024 | | if (is_generic) { |
| 21025 | | return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{}); |
| 21026 | | } |
| 21027 | | |
| 21028 | | const is_var_args = is_var_args_val.toBool(); |
| 21029 | | const cc = try sema.analyzeValueAsCallconv(block, src, calling_convention_val); |
| 21030 | | if (is_var_args) { |
| 21031 | | try sema.checkCallConvSupportsVarArgs(block, src, cc); |
| 21032 | | } |
| 21033 | | |
| 21034 | | const return_type = return_type_val.optionalValue(zcu) orelse |
| 21035 | | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); |
| 21036 | | |
| 21037 | | const params_val = try sema.derefSliceAsArray(block, operand_src, params_slice_val, .{ .simple = .function_parameters }); |
| 21038 | | |
| 21039 | | const args_len = try sema.usizeCast(block, src, params_val.typeOf(zcu).arrayLen(zcu)); |
| 21040 | | const param_types = try sema.arena.alloc(InternPool.Index, args_len); |
| 20771 | })); |
| 20772 | } |
| 21041 | 20773 | |
| 21042 | | var noalias_bits: u32 = 0; |
| 21043 | | for (param_types, 0..) |*param_type, i| { |
| 21044 | | const elem_val = try params_val.elemValue(pt, i); |
| 21045 | | const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); |
| 21046 | | const param_is_generic_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex( |
| 21047 | | ip, |
| 21048 | | try ip.getOrPutString(gpa, pt.tid, "is_generic", .no_embedded_nulls), |
| 21049 | | ).?); |
| 21050 | | const param_is_noalias_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex( |
| 21051 | | ip, |
| 21052 | | try ip.getOrPutString(gpa, pt.tid, "is_noalias", .no_embedded_nulls), |
| 21053 | | ).?); |
| 21054 | | const opt_param_type_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex( |
| 21055 | | ip, |
| 21056 | | try ip.getOrPutString(gpa, pt.tid, "type", .no_embedded_nulls), |
| 21057 | | ).?); |
| 21058 | | |
| 21059 | | if (param_is_generic_val.toBool()) { |
| 21060 | | return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{}); |
| 21061 | | } |
| 21062 | | |
| 21063 | | const param_type_val = opt_param_type_val.optionalValue(zcu) orelse |
| 21064 | | return sema.fail(block, src, "Type.Fn.Param.type must be non-null for @Type", .{}); |
| 21065 | | param_type.* = param_type_val.toIntern(); |
| 21066 | | |
| 21067 | | if (param_is_noalias_val.toBool()) { |
| 21068 | | if (!Type.fromInterned(param_type.*).isPtrAtRuntime(zcu)) { |
| 21069 | | return sema.fail(block, src, "non-pointer parameter declared noalias", .{}); |
| 21070 | | } |
| 21071 | | noalias_bits |= @as(u32, 1) << (std.math.cast(u5, i) orelse |
| 21072 | | return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); |
| 21073 | | } |
| 20774 | fn zirReifyFn( |
| 20775 | sema: *Sema, |
| 20776 | block: *Block, |
| 20777 | extended: Zir.Inst.Extended.InstData, |
| 20778 | ) CompileError!Air.Inst.Ref { |
| 20779 | const pt = sema.pt; |
| 20780 | const zcu = pt.zcu; |
| 20781 | const gpa = zcu.gpa; |
| 20782 | const ip = &zcu.intern_pool; |
| 20783 | |
| 20784 | const extra = sema.code.extraData(Zir.Inst.ReifyFn, extended.operand).data; |
| 20785 | const param_types_src = block.builtinCallArgSrc(extra.node, 0); |
| 20786 | const param_attrs_src = block.builtinCallArgSrc(extra.node, 1); |
| 20787 | const ret_ty_src = block.builtinCallArgSrc(extra.node, 2); |
| 20788 | const fn_attrs_src = block.builtinCallArgSrc(extra.node, 3); |
| 20789 | |
| 20790 | const single_param_attrs_ty = try sema.getBuiltinType(param_attrs_src, .@"Type.Fn.Param.Attributes"); |
| 20791 | const fn_attrs_ty = try sema.getBuiltinType(fn_attrs_src, .@"Type.Fn.Attributes"); |
| 20792 | |
| 20793 | const param_types_uncoerced = try sema.resolveInst(extra.param_types); |
| 20794 | const param_types_coerced = try sema.coerce(block, .slice_const_type, param_types_uncoerced, param_types_src); |
| 20795 | const param_types_slice = try sema.resolveConstDefinedValue(block, param_types_src, param_types_coerced, .{ .simple = .fn_param_types }); |
| 20796 | const param_types_arr = try sema.derefSliceAsArray(block, param_types_src, param_types_slice, .{ .simple = .fn_param_types }); |
| 20797 | |
| 20798 | const params_len = param_types_arr.typeOf(zcu).arrayLen(zcu); |
| 20799 | |
| 20800 | const param_attrs_ty = try pt.singleConstPtrType(try pt.arrayType(.{ |
| 20801 | .len = params_len, |
| 20802 | .child = single_param_attrs_ty.toIntern(), |
| 20803 | })); |
| 20804 | const param_attrs_uncoerced = try sema.resolveInst(extra.param_attrs); |
| 20805 | const param_attrs_coerced = try sema.coerce(block, param_attrs_ty, param_attrs_uncoerced, param_attrs_src); |
| 20806 | const param_attrs_slice = try sema.resolveConstDefinedValue(block, param_attrs_src, param_attrs_coerced, .{ .simple = .fn_param_attrs }); |
| 20807 | const param_attrs_arr = try sema.derefSliceAsArray(block, param_attrs_src, param_attrs_slice, .{ .simple = .fn_param_attrs }); |
| 20808 | |
| 20809 | const ret_ty = try sema.resolveType(block, ret_ty_src, extra.ret_ty); |
| 20810 | |
| 20811 | const fn_attrs_uncoerced = try sema.resolveInst(extra.fn_attrs); |
| 20812 | const fn_attrs_coerced = try sema.coerce(block, fn_attrs_ty, fn_attrs_uncoerced, fn_attrs_src); |
| 20813 | const fn_attrs_val = try sema.resolveConstDefinedValue(block, fn_attrs_src, fn_attrs_coerced, .{ .simple = .fn_attrs }); |
| 20814 | const fn_attrs = try sema.interpretBuiltinType(block, fn_attrs_src, fn_attrs_val, std.builtin.Type.Fn.Attributes); |
| 20815 | |
| 20816 | var noalias_bits: u32 = 0; |
| 20817 | const param_types_ip = try sema.arena.alloc(InternPool.Index, @intCast(params_len)); |
| 20818 | for (param_types_ip, 0..@intCast(params_len)) |*param_ty_ip, param_idx| { |
| 20819 | const param_ty: Type = (try param_types_arr.elemValue(pt, param_idx)).toType(); |
| 20820 | const param_attrs = try sema.interpretBuiltinType( |
| 20821 | block, |
| 20822 | param_attrs_src, |
| 20823 | try param_attrs_arr.elemValue(pt, param_idx), |
| 20824 | std.builtin.Type.Fn.Param.Attributes, |
| 20825 | ); |
| 20826 | try sema.checkParamTypeCommon( |
| 20827 | block, |
| 20828 | @intCast(param_idx), |
| 20829 | param_ty, |
| 20830 | param_attrs.@"noalias", |
| 20831 | param_types_src, |
| 20832 | fn_attrs.@"callconv", |
| 20833 | ); |
| 20834 | if (try param_ty.comptimeOnlySema(pt)) { |
| 20835 | return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only parameter type '{f}'", .{param_ty.fmt(pt)}); |
| 20836 | } |
| 20837 | if (param_attrs.@"noalias") { |
| 20838 | if (param_idx > 31) { |
| 20839 | return sema.fail(block, param_attrs_src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{}); |
| 21074 | 20840 | } |
| 20841 | noalias_bits |= @as(u32, 1) << @intCast(param_idx); |
| 20842 | } |
| 20843 | param_ty_ip.* = param_ty.toIntern(); |
| 20844 | } |
| 21075 | 20845 | |
| 21076 | | const ty = try pt.funcType(.{ |
| 21077 | | .param_types = param_types, |
| 21078 | | .noalias_bits = noalias_bits, |
| 21079 | | .return_type = return_type.toIntern(), |
| 21080 | | .cc = cc, |
| 21081 | | .is_var_args = is_var_args, |
| 21082 | | }); |
| 21083 | | return Air.internedToRef(ty.toIntern()); |
| 21084 | | }, |
| 21085 | | .frame => return sema.failWithUseOfAsync(block, src), |
| 20846 | if (fn_attrs.varargs) { |
| 20847 | try sema.checkCallConvSupportsVarArgs(block, fn_attrs_src, fn_attrs.@"callconv"); |
| 21086 | 20848 | } |
| 20849 | |
| 20850 | try sema.checkReturnTypeAndCallConvCommon( |
| 20851 | block, |
| 20852 | ret_ty, |
| 20853 | ret_ty_src, |
| 20854 | fn_attrs.@"callconv", |
| 20855 | fn_attrs_src, |
| 20856 | if (fn_attrs.varargs) fn_attrs_src else null, |
| 20857 | false, |
| 20858 | false, |
| 20859 | ); |
| 20860 | if (try ret_ty.comptimeOnlySema(pt)) { |
| 20861 | return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only return type '{f}'", .{ret_ty.fmt(pt)}); |
| 20862 | } |
| 20863 | |
| 20864 | return .fromIntern(try ip.getFuncType(gpa, pt.tid, .{ |
| 20865 | .param_types = param_types_ip, |
| 20866 | .noalias_bits = noalias_bits, |
| 20867 | .comptime_bits = 0, |
| 20868 | .return_type = ret_ty.toIntern(), |
| 20869 | .cc = fn_attrs.@"callconv", |
| 20870 | .is_var_args = fn_attrs.varargs, |
| 20871 | .is_generic = false, |
| 20872 | .is_noinline = false, |
| 20873 | })); |
| 21087 | 20874 | } |
| 21088 | 20875 | |
| 21089 | | fn reifyEnum( |
| 20876 | fn zirReifyStruct( |
| 21090 | 20877 | sema: *Sema, |
| 21091 | 20878 | block: *Block, |
| 20879 | extended: Zir.Inst.Extended.InstData, |
| 21092 | 20880 | inst: Zir.Inst.Index, |
| 21093 | | src: LazySrcLoc, |
| 21094 | | tag_ty: Type, |
| 21095 | | is_exhaustive: bool, |
| 21096 | | fields_val: Value, |
| 21097 | | name_strategy: Zir.Inst.NameStrategy, |
| 21098 | 20881 | ) CompileError!Air.Inst.Ref { |
| 21099 | 20882 | const pt = sema.pt; |
| 21100 | 20883 | const zcu = pt.zcu; |
| 21101 | 20884 | const gpa = sema.gpa; |
| 21102 | 20885 | const ip = &zcu.intern_pool; |
| 21103 | 20886 | |
| 21104 | | // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`. |
| 20887 | const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small); |
| 20888 | const extra = sema.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data; |
| 20889 | const tracked_inst = try block.trackZir(inst); |
| 20890 | const src: LazySrcLoc = .{ |
| 20891 | .base_node_inst = tracked_inst, |
| 20892 | .offset = .nodeOffset(.zero), |
| 20893 | }; |
| 20894 | |
| 20895 | const layout_src: LazySrcLoc = .{ |
| 20896 | .base_node_inst = tracked_inst, |
| 20897 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 20898 | .builtin_call_node = .zero, |
| 20899 | .arg_index = 0, |
| 20900 | } }, |
| 20901 | }; |
| 20902 | const backing_ty_src: LazySrcLoc = .{ |
| 20903 | .base_node_inst = tracked_inst, |
| 20904 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 20905 | .builtin_call_node = .zero, |
| 20906 | .arg_index = 1, |
| 20907 | } }, |
| 20908 | }; |
| 20909 | const field_names_src: LazySrcLoc = .{ |
| 20910 | .base_node_inst = tracked_inst, |
| 20911 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 20912 | .builtin_call_node = .zero, |
| 20913 | .arg_index = 2, |
| 20914 | } }, |
| 20915 | }; |
| 20916 | const field_types_src: LazySrcLoc = .{ |
| 20917 | .base_node_inst = tracked_inst, |
| 20918 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 20919 | .builtin_call_node = .zero, |
| 20920 | .arg_index = 3, |
| 20921 | } }, |
| 20922 | }; |
| 20923 | const field_attrs_src: LazySrcLoc = .{ |
| 20924 | .base_node_inst = tracked_inst, |
| 20925 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 20926 | .builtin_call_node = .zero, |
| 20927 | .arg_index = 4, |
| 20928 | } }, |
| 20929 | }; |
| 20930 | |
| 20931 | const container_layout_ty = try sema.getBuiltinType(layout_src, .@"Type.ContainerLayout"); |
| 20932 | const single_field_attrs_ty = try sema.getBuiltinType(field_attrs_src, .@"Type.StructField.Attributes"); |
| 20933 | |
| 20934 | const layout_uncoerced = try sema.resolveInst(extra.layout); |
| 20935 | const layout_coerced = try sema.coerce(block, container_layout_ty, layout_uncoerced, layout_src); |
| 20936 | const layout_val = try sema.resolveConstDefinedValue(block, layout_src, layout_coerced, .{ .simple = .struct_layout }); |
| 20937 | const layout = try sema.interpretBuiltinType(block, layout_src, layout_val, std.builtin.Type.ContainerLayout); |
| 20938 | |
| 20939 | const backing_int_ty_uncoerced = try sema.resolveInst(extra.backing_ty); |
| 20940 | const backing_int_ty_coerced = try sema.coerce(block, .optional_type, backing_int_ty_uncoerced, backing_ty_src); |
| 20941 | const backing_int_ty_val = try sema.resolveConstDefinedValue(block, backing_ty_src, backing_int_ty_coerced, .{ .simple = .type }); |
| 20942 | |
| 20943 | const field_names_uncoerced = try sema.resolveInst(extra.field_names); |
| 20944 | const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src); |
| 20945 | const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .struct_field_names }); |
| 20946 | const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .struct_field_names }); |
| 20947 | |
| 20948 | const fields_len = try sema.usizeCast(block, src, field_names_arr.typeOf(zcu).arrayLen(zcu)); |
| 20949 | |
| 20950 | const field_types_ty = try pt.singleConstPtrType(try pt.arrayType(.{ |
| 20951 | .len = fields_len, |
| 20952 | .child = .type_type, |
| 20953 | })); |
| 20954 | const field_attrs_ty = try pt.singleConstPtrType(try pt.arrayType(.{ |
| 20955 | .len = fields_len, |
| 20956 | .child = single_field_attrs_ty.toIntern(), |
| 20957 | })); |
| 20958 | |
| 20959 | const field_types_uncoerced = try sema.resolveInst(extra.field_types); |
| 20960 | const field_types_coerced = try sema.coerce(block, field_types_ty, field_types_uncoerced, field_types_src); |
| 20961 | const field_types_slice = try sema.resolveConstDefinedValue(block, field_types_src, field_types_coerced, .{ .simple = .struct_field_types }); |
| 20962 | const field_types_arr = try sema.derefSliceAsArray(block, field_types_src, field_types_slice, .{ .simple = .struct_field_types }); |
| 21105 | 20963 | |
| 21106 | | const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu)); |
| 20964 | const field_attrs_uncoerced = try sema.resolveInst(extra.field_attrs); |
| 20965 | const field_attrs_coerced = try sema.coerce(block, field_attrs_ty, field_attrs_uncoerced, field_attrs_src); |
| 20966 | const field_attrs_slice = try sema.resolveConstDefinedValue(block, field_attrs_src, field_attrs_coerced, .{ .simple = .struct_field_attrs }); |
| 20967 | const field_attrs_arr = try sema.derefSliceAsArray(block, field_attrs_src, field_attrs_slice, .{ .simple = .struct_field_attrs }); |
| 20968 | |
| 20969 | // Before we begin, check for undefs... |
| 20970 | if (try sema.anyUndef(block, field_attrs_src, field_attrs_arr)) { |
| 20971 | return sema.failWithUseOfUndef(block, field_attrs_src, null); |
| 20972 | } |
| 20973 | if (try sema.anyUndef(block, field_types_src, field_types_arr)) { |
| 20974 | return sema.failWithUseOfUndef(block, field_types_src, null); |
| 20975 | } |
| 20976 | // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us. |
| 20977 | if (try sema.anyUndef(block, backing_ty_src, backing_int_ty_val)) { |
| 20978 | return sema.failWithUseOfUndef(block, backing_ty_src, null); |
| 20979 | } |
| 21107 | 20980 | |
| 21108 | 20981 | // The validation work here is non-trivial, and it's possible the type already exists. |
| 21109 | 20982 | // So in this first pass, let's just construct a hash to optimize for this case. If the |
| 21110 | 20983 | // inputs turn out to be invalid, we can cancel the WIP type later. |
| 21111 | 20984 | |
| 20985 | var any_comptime_fields = false; |
| 20986 | var any_default_inits = false; |
| 20987 | var any_aligned_fields = false; |
| 20988 | |
| 21112 | 20989 | // For deduplication purposes, we must create a hash including all details of this type. |
| 21113 | 20990 | // TODO: use a longer hash! |
| 21114 | 20991 | var hasher = std.hash.Wyhash.init(0); |
| 21115 | | std.hash.autoHash(&hasher, tag_ty.toIntern()); |
| 21116 | | std.hash.autoHash(&hasher, is_exhaustive); |
| 21117 | | std.hash.autoHash(&hasher, fields_len); |
| 21118 | | |
| 20992 | std.hash.autoHash(&hasher, layout); |
| 20993 | std.hash.autoHash(&hasher, backing_int_ty_val); |
| 20994 | // The field *type* array has already been deduplicated for us thanks to the InternPool! |
| 20995 | std.hash.autoHash(&hasher, field_types_arr); |
| 20996 | // However, for field names and attributes, we need to actually iterate the individual fields, |
| 20997 | // because the presence of pointers (the `[]const u8` for the name and the `*const anyopaque` |
| 20998 | // for the default value) means that distinct interned values could ultimately result in the |
| 20999 | // same struct type. |
| 21119 | 21000 | for (0..fields_len) |field_idx| { |
| 21120 | | const field_info = try fields_val.elemValue(pt, field_idx); |
| 21001 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 21002 | const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx); |
| 21003 | |
| 21004 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, .{ .simple = .struct_field_names }); |
| 21005 | |
| 21006 | const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( |
| 21007 | std.builtin.Type.StructField.Attributes, |
| 21008 | "comptime", |
| 21009 | ).?); |
| 21010 | const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( |
| 21011 | std.builtin.Type.StructField.Attributes, |
| 21012 | "align", |
| 21013 | ).?); |
| 21014 | const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( |
| 21015 | std.builtin.Type.StructField.Attributes, |
| 21016 | "default_value_ptr", |
| 21017 | ).?); |
| 21121 | 21018 | |
| 21122 | | const field_name_val = try field_info.fieldValue(pt, 0); |
| 21123 | | const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 1)); |
| 21124 | | |
| 21125 | | const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .enum_field_name }); |
| 21019 | const field_default: InternPool.Index = d: { |
| 21020 | const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none; |
| 21021 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); |
| 21022 | const ptr_ty = try pt.singleConstPtrType(field_ty); |
| 21023 | const deref_val = try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime( |
| 21024 | block, |
| 21025 | field_attrs_src, |
| 21026 | .{ .simple = .struct_field_default_value }, |
| 21027 | ); |
| 21028 | // Resolve the value so that lazy values do not create distinct types. |
| 21029 | break :d (try sema.resolveLazyValue(deref_val)).toIntern(); |
| 21030 | }; |
| 21126 | 21031 | |
| 21127 | 21032 | std.hash.autoHash(&hasher, .{ |
| 21128 | 21033 | field_name, |
| 21129 | | field_value_val.toIntern(), |
| 21034 | field_attr_comptime, |
| 21035 | field_attr_align, |
| 21036 | field_default, |
| 21130 | 21037 | }); |
| 21038 | |
| 21039 | if (field_attr_comptime.toBool()) any_comptime_fields = true; |
| 21040 | if (field_attr_align.optionalValue(zcu)) |_| any_aligned_fields = true; |
| 21041 | if (field_default != .none) any_default_inits = true; |
| 21131 | 21042 | } |
| 21132 | 21043 | |
| 21133 | | const tracked_inst = try block.trackZir(inst); |
| 21044 | // Some basic validation to avoid a bogus `getStructType` call... |
| 21045 | const backing_int_ty: ?Type = if (backing_int_ty_val.optionalValue(zcu)) |backing| ty: { |
| 21046 | switch (layout) { |
| 21047 | .auto, .@"extern" => return sema.fail(block, backing_ty_src, "non-packed struct does not support backing integer type", .{}), |
| 21048 | .@"packed" => {}, |
| 21049 | } |
| 21050 | break :ty backing.toType(); |
| 21051 | } else null; |
| 21052 | if (any_aligned_fields and layout == .@"packed") { |
| 21053 | return sema.fail(block, field_attrs_src, "packed struct fields cannot be aligned", .{}); |
| 21054 | } |
| 21055 | if (any_comptime_fields and layout != .auto) { |
| 21056 | return sema.fail(block, field_attrs_src, "{t} struct fields cannot be marked comptime", .{layout}); |
| 21057 | } |
| 21134 | 21058 | |
| 21135 | | const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{ |
| 21136 | | .has_values = true, |
| 21137 | | .tag_mode = if (is_exhaustive) .explicit else .nonexhaustive, |
| 21138 | | .fields_len = fields_len, |
| 21059 | const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{ |
| 21060 | .layout = layout, |
| 21061 | .fields_len = @intCast(fields_len), |
| 21062 | .known_non_opv = false, |
| 21063 | .requires_comptime = .unknown, |
| 21064 | .any_comptime_fields = any_comptime_fields, |
| 21065 | .any_default_inits = any_default_inits, |
| 21066 | .any_aligned_fields = any_aligned_fields, |
| 21067 | .inits_resolved = true, |
| 21139 | 21068 | .key = .{ .reified = .{ |
| 21140 | 21069 | .zir_index = tracked_inst, |
| 21141 | 21070 | .type_hash = hasher.final(), |
| ... | ... | @@ -21148,79 +21077,144 @@ fn reifyEnum( |
| 21148 | 21077 | return Air.internedToRef(ty); |
| 21149 | 21078 | }, |
| 21150 | 21079 | }; |
| 21151 | | var done = false; |
| 21152 | | errdefer if (!done) wip_ty.cancel(ip, pt.tid); |
| 21153 | | |
| 21154 | | if (tag_ty.zigTypeTag(zcu) != .int) { |
| 21155 | | return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); |
| 21156 | | } |
| 21080 | errdefer wip_ty.cancel(ip, pt.tid); |
| 21157 | 21081 | |
| 21158 | 21082 | const type_name = try sema.createTypeName( |
| 21159 | 21083 | block, |
| 21160 | 21084 | name_strategy, |
| 21161 | | "enum", |
| 21085 | "struct", |
| 21162 | 21086 | inst, |
| 21163 | 21087 | wip_ty.index, |
| 21164 | 21088 | ); |
| 21165 | 21089 | wip_ty.setName(ip, type_name.name, type_name.nav); |
| 21166 | 21090 | |
| 21167 | | const new_namespace_index = try pt.createNamespace(.{ |
| 21168 | | .parent = block.namespace.toOptional(), |
| 21169 | | .owner_type = wip_ty.index, |
| 21170 | | .file_scope = block.getFileScopeIndex(zcu), |
| 21171 | | .generation = zcu.generation, |
| 21172 | | }); |
| 21173 | | |
| 21174 | | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 21175 | | try sema.addTypeReferenceEntry(src, wip_ty.index); |
| 21176 | | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); |
| 21177 | | wip_ty.prepare(ip, new_namespace_index); |
| 21178 | | wip_ty.setTagTy(ip, tag_ty.toIntern()); |
| 21179 | | done = true; |
| 21091 | const wip_struct_type = ip.loadStructType(wip_ty.index); |
| 21180 | 21092 | |
| 21181 | 21093 | for (0..fields_len) |field_idx| { |
| 21182 | | const field_info = try fields_val.elemValue(pt, field_idx); |
| 21094 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 21095 | const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx); |
| 21183 | 21096 | |
| 21184 | | const field_name_val = try field_info.fieldValue(pt, 0); |
| 21185 | | const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 1)); |
| 21097 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); |
| 21186 | 21098 | |
| 21187 | | // Don't pass a reason; first loop acts as an assertion that this is valid. |
| 21188 | | const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined); |
| 21099 | // Don't pass a reason; first loop acts as a check that this is valid. |
| 21100 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); |
| 21101 | if (wip_struct_type.addFieldName(ip, field_name)) |prev_index| { |
| 21102 | _ = prev_index; // TODO: better source location |
| 21103 | return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)}); |
| 21104 | } |
| 21105 | |
| 21106 | const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( |
| 21107 | std.builtin.Type.StructField.Attributes, |
| 21108 | "comptime", |
| 21109 | ).?); |
| 21110 | const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( |
| 21111 | std.builtin.Type.StructField.Attributes, |
| 21112 | "align", |
| 21113 | ).?); |
| 21114 | const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( |
| 21115 | std.builtin.Type.StructField.Attributes, |
| 21116 | "default_value_ptr", |
| 21117 | ).?); |
| 21118 | |
| 21119 | if (field_attr_align.optionalValue(zcu)) |field_align_val| { |
| 21120 | assert(layout != .@"packed"); |
| 21121 | const bytes = try field_align_val.toUnsignedIntSema(pt); |
| 21122 | const a = try sema.validateAlign(block, field_attrs_src, bytes); |
| 21123 | wip_struct_type.field_aligns.get(ip)[field_idx] = a; |
| 21124 | } else if (any_aligned_fields) { |
| 21125 | assert(layout != .@"packed"); |
| 21126 | wip_struct_type.field_aligns.get(ip)[field_idx] = .none; |
| 21127 | } |
| 21189 | 21128 | |
| 21190 | | if (!try sema.intFitsInType(field_value_val, tag_ty, null)) { |
| 21191 | | // TODO: better source location |
| 21192 | | return sema.fail(block, src, "field '{f}' with enumeration value '{f}' is too large for backing int type '{f}'", .{ |
| 21193 | | field_name.fmt(ip), |
| 21194 | | field_value_val.fmtValueSema(pt, sema), |
| 21195 | | tag_ty.fmt(pt), |
| 21196 | | }); |
| 21129 | const field_default: InternPool.Index = d: { |
| 21130 | const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none; |
| 21131 | assert(any_default_inits); |
| 21132 | const ptr_ty = try pt.singleConstPtrType(field_ty); |
| 21133 | // The first loop checked that this is comptime-dereferencable. |
| 21134 | const deref_val = (try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty)).?; |
| 21135 | // ...but we've not checked this yet! |
| 21136 | if (deref_val.canMutateComptimeVarState(zcu)) { |
| 21137 | return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val); |
| 21138 | } |
| 21139 | break :d (try sema.resolveLazyValue(deref_val)).toIntern(); |
| 21140 | }; |
| 21141 | |
| 21142 | if (field_attr_comptime.toBool()) { |
| 21143 | assert(layout == .auto); |
| 21144 | if (field_default == .none) { |
| 21145 | return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{}); |
| 21146 | } |
| 21147 | wip_struct_type.setFieldComptime(ip, field_idx); |
| 21197 | 21148 | } |
| 21198 | 21149 | |
| 21199 | | const coerced_field_val = try pt.getCoerced(field_value_val, tag_ty); |
| 21200 | | if (wip_ty.nextField(ip, field_name, coerced_field_val.toIntern())) |conflict| { |
| 21201 | | return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) { |
| 21202 | | .name => msg: { |
| 21203 | | const msg = try sema.errMsg(src, "duplicate enum field '{f}'", .{field_name.fmt(ip)}); |
| 21150 | wip_struct_type.field_types.get(ip)[field_idx] = field_ty.toIntern(); |
| 21151 | if (field_default != .none) { |
| 21152 | wip_struct_type.field_inits.get(ip)[field_idx] = field_default; |
| 21153 | } |
| 21154 | |
| 21155 | switch (field_ty.zigTypeTag(zcu)) { |
| 21156 | .@"opaque" => return sema.failWithOwnedErrorMsg(block, msg: { |
| 21157 | const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 21158 | errdefer msg.destroy(gpa); |
| 21159 | try sema.addDeclaredHereNote(msg, field_ty); |
| 21160 | break :msg msg; |
| 21161 | }), |
| 21162 | .noreturn => return sema.failWithOwnedErrorMsg(block, msg: { |
| 21163 | const msg = try sema.errMsg(field_types_src, "struct fields cannot be 'noreturn'", .{}); |
| 21164 | errdefer msg.destroy(gpa); |
| 21165 | try sema.addDeclaredHereNote(msg, field_ty); |
| 21166 | break :msg msg; |
| 21167 | }), |
| 21168 | else => {}, |
| 21169 | } |
| 21170 | |
| 21171 | switch (layout) { |
| 21172 | .auto => {}, |
| 21173 | .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) { |
| 21174 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21175 | const msg = try sema.errMsg(field_types_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 21204 | 21176 | errdefer msg.destroy(gpa); |
| 21205 | | _ = conflict.prev_field_idx; // TODO: this note is incorrect |
| 21206 | | try sema.errNote(src, msg, "other field here", .{}); |
| 21177 | try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .struct_field); |
| 21178 | try sema.addDeclaredHereNote(msg, field_ty); |
| 21207 | 21179 | break :msg msg; |
| 21208 | | }, |
| 21209 | | .value => msg: { |
| 21210 | | const msg = try sema.errMsg(src, "enum tag value {f} already taken", .{field_value_val.fmtValueSema(pt, sema)}); |
| 21180 | }); |
| 21181 | }, |
| 21182 | .@"packed" => if (!try sema.validatePackedType(field_ty)) { |
| 21183 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21184 | const msg = try sema.errMsg(field_types_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 21211 | 21185 | errdefer msg.destroy(gpa); |
| 21212 | | _ = conflict.prev_field_idx; // TODO: this note is incorrect |
| 21213 | | try sema.errNote(src, msg, "other enum tag value here", .{}); |
| 21186 | try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty); |
| 21187 | try sema.addDeclaredHereNote(msg, field_ty); |
| 21214 | 21188 | break :msg msg; |
| 21215 | | }, |
| 21216 | | }); |
| 21189 | }); |
| 21190 | }, |
| 21217 | 21191 | } |
| 21218 | 21192 | } |
| 21219 | 21193 | |
| 21220 | | if (!is_exhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) { |
| 21221 | | return sema.fail(block, src, "non-exhaustive enum specified every value", .{}); |
| 21194 | if (layout == .@"packed") { |
| 21195 | var fields_bit_sum: u64 = 0; |
| 21196 | for (0..wip_struct_type.field_types.len) |field_idx| { |
| 21197 | const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]); |
| 21198 | try field_ty.resolveLayout(pt); |
| 21199 | fields_bit_sum += field_ty.bitSize(zcu); |
| 21200 | } |
| 21201 | if (backing_int_ty) |ty| { |
| 21202 | try sema.checkBackingIntType(block, src, ty, fields_bit_sum); |
| 21203 | wip_struct_type.setBackingIntType(ip, ty.toIntern()); |
| 21204 | } else { |
| 21205 | const ty = try pt.intType(.unsigned, @intCast(fields_bit_sum)); |
| 21206 | wip_struct_type.setBackingIntType(ip, ty.toIntern()); |
| 21207 | } |
| 21222 | 21208 | } |
| 21223 | 21209 | |
| 21210 | const new_namespace_index = try pt.createNamespace(.{ |
| 21211 | .parent = block.namespace.toOptional(), |
| 21212 | .owner_type = wip_ty.index, |
| 21213 | .file_scope = block.getFileScopeIndex(zcu), |
| 21214 | .generation = zcu.generation, |
| 21215 | }); |
| 21216 | |
| 21217 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); |
| 21224 | 21218 | codegen_type: { |
| 21225 | 21219 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| 21226 | 21220 | if (block.ownerModule().strip) break :codegen_type; |
| ... | ... | @@ -21228,75 +21222,177 @@ fn reifyEnum( |
| 21228 | 21222 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); |
| 21229 | 21223 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); |
| 21230 | 21224 | } |
| 21231 | | return Air.internedToRef(wip_ty.index); |
| 21225 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 21226 | try sema.addTypeReferenceEntry(src, wip_ty.index); |
| 21227 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); |
| 21228 | return .fromIntern(wip_ty.finish(ip, new_namespace_index)); |
| 21232 | 21229 | } |
| 21233 | 21230 | |
| 21234 | | fn reifyUnion( |
| 21231 | fn zirReifyUnion( |
| 21235 | 21232 | sema: *Sema, |
| 21236 | 21233 | block: *Block, |
| 21234 | extended: Zir.Inst.Extended.InstData, |
| 21237 | 21235 | inst: Zir.Inst.Index, |
| 21238 | | src: LazySrcLoc, |
| 21239 | | layout: std.builtin.Type.ContainerLayout, |
| 21240 | | opt_tag_type_val: Value, |
| 21241 | | fields_val: Value, |
| 21242 | | name_strategy: Zir.Inst.NameStrategy, |
| 21243 | 21236 | ) CompileError!Air.Inst.Ref { |
| 21244 | 21237 | const pt = sema.pt; |
| 21245 | 21238 | const zcu = pt.zcu; |
| 21246 | 21239 | const gpa = sema.gpa; |
| 21247 | 21240 | const ip = &zcu.intern_pool; |
| 21248 | 21241 | |
| 21249 | | // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`. |
| 21242 | const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small); |
| 21243 | const extra = sema.code.extraData(Zir.Inst.ReifyUnion, extended.operand).data; |
| 21244 | const tracked_inst = try block.trackZir(inst); |
| 21245 | const src: LazySrcLoc = .{ |
| 21246 | .base_node_inst = tracked_inst, |
| 21247 | .offset = .nodeOffset(.zero), |
| 21248 | }; |
| 21249 | |
| 21250 | const layout_src: LazySrcLoc = .{ |
| 21251 | .base_node_inst = tracked_inst, |
| 21252 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 21253 | .builtin_call_node = .zero, |
| 21254 | .arg_index = 0, |
| 21255 | } }, |
| 21256 | }; |
| 21257 | const arg_ty_src: LazySrcLoc = .{ |
| 21258 | .base_node_inst = tracked_inst, |
| 21259 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 21260 | .builtin_call_node = .zero, |
| 21261 | .arg_index = 1, |
| 21262 | } }, |
| 21263 | }; |
| 21264 | const field_names_src: LazySrcLoc = .{ |
| 21265 | .base_node_inst = tracked_inst, |
| 21266 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 21267 | .builtin_call_node = .zero, |
| 21268 | .arg_index = 2, |
| 21269 | } }, |
| 21270 | }; |
| 21271 | const field_types_src: LazySrcLoc = .{ |
| 21272 | .base_node_inst = tracked_inst, |
| 21273 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 21274 | .builtin_call_node = .zero, |
| 21275 | .arg_index = 3, |
| 21276 | } }, |
| 21277 | }; |
| 21278 | const field_attrs_src: LazySrcLoc = .{ |
| 21279 | .base_node_inst = tracked_inst, |
| 21280 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 21281 | .builtin_call_node = .zero, |
| 21282 | .arg_index = 4, |
| 21283 | } }, |
| 21284 | }; |
| 21285 | |
| 21286 | const container_layout_ty = try sema.getBuiltinType(layout_src, .@"Type.ContainerLayout"); |
| 21287 | const single_field_attrs_ty = try sema.getBuiltinType(field_attrs_src, .@"Type.UnionField.Attributes"); |
| 21288 | |
| 21289 | const layout_uncoerced = try sema.resolveInst(extra.layout); |
| 21290 | const layout_coerced = try sema.coerce(block, container_layout_ty, layout_uncoerced, layout_src); |
| 21291 | const layout_val = try sema.resolveConstDefinedValue(block, layout_src, layout_coerced, .{ .simple = .union_layout }); |
| 21292 | const layout = try sema.interpretBuiltinType(block, layout_src, layout_val, std.builtin.Type.ContainerLayout); |
| 21293 | |
| 21294 | const arg_ty_uncoerced = try sema.resolveInst(extra.arg_ty); |
| 21295 | const arg_ty_coerced = try sema.coerce(block, .optional_type, arg_ty_uncoerced, arg_ty_src); |
| 21296 | const arg_ty_val = try sema.resolveConstDefinedValue(block, arg_ty_src, arg_ty_coerced, .{ .simple = .type }); |
| 21297 | |
| 21298 | const field_names_uncoerced = try sema.resolveInst(extra.field_names); |
| 21299 | const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src); |
| 21300 | const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .union_field_names }); |
| 21301 | const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .union_field_names }); |
| 21302 | |
| 21303 | const fields_len = try sema.usizeCast(block, src, field_names_arr.typeOf(zcu).arrayLen(zcu)); |
| 21304 | |
| 21305 | const field_types_ty = try pt.singleConstPtrType(try pt.arrayType(.{ |
| 21306 | .len = fields_len, |
| 21307 | .child = .type_type, |
| 21308 | })); |
| 21309 | const field_attrs_ty = try pt.singleConstPtrType(try pt.arrayType(.{ |
| 21310 | .len = fields_len, |
| 21311 | .child = single_field_attrs_ty.toIntern(), |
| 21312 | })); |
| 21313 | |
| 21314 | const field_types_uncoerced = try sema.resolveInst(extra.field_types); |
| 21315 | const field_types_coerced = try sema.coerce(block, field_types_ty, field_types_uncoerced, field_types_src); |
| 21316 | const field_types_slice = try sema.resolveConstDefinedValue(block, field_types_src, field_types_coerced, .{ .simple = .union_field_types }); |
| 21317 | const field_types_arr = try sema.derefSliceAsArray(block, field_types_src, field_types_slice, .{ .simple = .union_field_types }); |
| 21250 | 21318 | |
| 21251 | | const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu)); |
| 21319 | const field_attrs_uncoerced = try sema.resolveInst(extra.field_attrs); |
| 21320 | const field_attrs_coerced = try sema.coerce(block, field_attrs_ty, field_attrs_uncoerced, field_attrs_src); |
| 21321 | const field_attrs_slice = try sema.resolveConstDefinedValue(block, field_attrs_src, field_attrs_coerced, .{ .simple = .union_field_attrs }); |
| 21322 | const field_attrs_arr = try sema.derefSliceAsArray(block, field_attrs_src, field_attrs_slice, .{ .simple = .union_field_attrs }); |
| 21323 | |
| 21324 | // Before we begin, check for undefs... |
| 21325 | if (try sema.anyUndef(block, field_attrs_src, field_attrs_arr)) { |
| 21326 | return sema.failWithUseOfUndef(block, field_attrs_src, null); |
| 21327 | } |
| 21328 | if (try sema.anyUndef(block, field_types_src, field_types_arr)) { |
| 21329 | return sema.failWithUseOfUndef(block, field_types_src, null); |
| 21330 | } |
| 21331 | // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us. |
| 21332 | if (try sema.anyUndef(block, arg_ty_src, arg_ty_val)) { |
| 21333 | return sema.failWithUseOfUndef(block, arg_ty_src, null); |
| 21334 | } |
| 21252 | 21335 | |
| 21253 | 21336 | // The validation work here is non-trivial, and it's possible the type already exists. |
| 21254 | 21337 | // So in this first pass, let's just construct a hash to optimize for this case. If the |
| 21255 | 21338 | // inputs turn out to be invalid, we can cancel the WIP type later. |
| 21256 | 21339 | |
| 21340 | var any_aligned_fields = false; |
| 21341 | |
| 21257 | 21342 | // For deduplication purposes, we must create a hash including all details of this type. |
| 21258 | 21343 | // TODO: use a longer hash! |
| 21259 | 21344 | var hasher = std.hash.Wyhash.init(0); |
| 21260 | 21345 | std.hash.autoHash(&hasher, layout); |
| 21261 | | std.hash.autoHash(&hasher, opt_tag_type_val.toIntern()); |
| 21262 | | std.hash.autoHash(&hasher, fields_len); |
| 21263 | | |
| 21346 | std.hash.autoHash(&hasher, arg_ty_val); |
| 21347 | // `field_types_arr` and `field_attrs_arr` are already deduplicated by the InternPool! |
| 21348 | std.hash.autoHash(&hasher, field_types_arr); |
| 21349 | std.hash.autoHash(&hasher, field_attrs_arr); |
| 21350 | // However, for field names, we need to iterate the individual fields, because the pointers (the |
| 21351 | // names are slices) mean that distinct values could ultimately result in the same union type. |
| 21264 | 21352 | for (0..fields_len) |field_idx| { |
| 21265 | | const field_info = try fields_val.elemValue(pt, field_idx); |
| 21266 | | |
| 21267 | | const field_name_val = try field_info.fieldValue(pt, 0); |
| 21268 | | const field_type_val = try field_info.fieldValue(pt, 1); |
| 21269 | | const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 2)); |
| 21353 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 21354 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, .{ .simple = .union_field_names }); |
| 21355 | std.hash.autoHash(&hasher, field_name); |
| 21270 | 21356 | |
| 21271 | | const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .union_field_name }); |
| 21272 | | std.hash.autoHash(&hasher, .{ |
| 21273 | | field_name, |
| 21274 | | field_type_val.toIntern(), |
| 21275 | | field_align_val.toIntern(), |
| 21276 | | }); |
| 21357 | const field_attrs = try sema.interpretBuiltinType( |
| 21358 | block, |
| 21359 | field_attrs_src, |
| 21360 | try field_attrs_arr.elemValue(pt, field_idx), |
| 21361 | std.builtin.Type.UnionField.Attributes, |
| 21362 | ); |
| 21363 | if (field_attrs.@"align" != null) { |
| 21364 | any_aligned_fields = true; |
| 21365 | } |
| 21277 | 21366 | } |
| 21278 | 21367 | |
| 21279 | | const tracked_inst = try block.trackZir(inst); |
| 21368 | // Some basic validation to avoid a bogus `getUnionType` call... |
| 21369 | const explicit_tag_ty: ?Type = if (arg_ty_val.optionalValue(zcu)) |arg_ty| ty: { |
| 21370 | switch (layout) { |
| 21371 | .@"extern", .@"packed" => return sema.fail(block, arg_ty_src, "{t} union does not support enum tag type", .{layout}), |
| 21372 | .auto => {}, |
| 21373 | } |
| 21374 | break :ty arg_ty.toType(); |
| 21375 | } else null; |
| 21376 | if (any_aligned_fields and layout == .@"packed") { |
| 21377 | return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{}); |
| 21378 | } |
| 21280 | 21379 | |
| 21281 | 21380 | const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, .{ |
| 21282 | 21381 | .flags = .{ |
| 21283 | 21382 | .layout = layout, |
| 21284 | 21383 | .status = .none, |
| 21285 | | .runtime_tag = if (opt_tag_type_val.optionalValue(zcu) != null) |
| 21286 | | .tagged |
| 21287 | | else if (layout != .auto) |
| 21288 | | .none |
| 21289 | | else switch (block.wantSafeTypes()) { |
| 21290 | | true => .safety, |
| 21291 | | false => .none, |
| 21384 | .runtime_tag = rt: { |
| 21385 | if (explicit_tag_ty != null) break :rt .tagged; |
| 21386 | if (layout == .auto and block.wantSafeTypes()) break :rt .safety; |
| 21387 | break :rt .none; |
| 21292 | 21388 | }, |
| 21293 | | .any_aligned_fields = layout != .@"packed", |
| 21389 | .any_aligned_fields = any_aligned_fields, |
| 21294 | 21390 | .requires_comptime = .unknown, |
| 21295 | 21391 | .assumed_runtime_bits = false, |
| 21296 | 21392 | .assumed_pointer_aligned = false, |
| 21297 | 21393 | .alignment = .none, |
| 21298 | 21394 | }, |
| 21299 | | .fields_len = fields_len, |
| 21395 | .fields_len = @intCast(fields_len), |
| 21300 | 21396 | .enum_tag_ty = .none, // set later because not yet validated |
| 21301 | 21397 | .field_types = &.{}, // set later |
| 21302 | 21398 | .field_aligns = &.{}, // set later |
| ... | ... | @@ -21325,128 +21421,117 @@ fn reifyUnion( |
| 21325 | 21421 | |
| 21326 | 21422 | const loaded_union = ip.loadUnionType(wip_ty.index); |
| 21327 | 21423 | |
| 21328 | | const enum_tag_ty, const has_explicit_tag = if (opt_tag_type_val.optionalValue(zcu)) |tag_type_val| tag_ty: { |
| 21329 | | switch (ip.indexToKey(tag_type_val.toIntern())) { |
| 21330 | | .enum_type => {}, |
| 21331 | | else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}), |
| 21424 | const enum_tag_ty, const has_explicit_tag = if (explicit_tag_ty) |enum_tag_ty| tag: { |
| 21425 | if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") { |
| 21426 | return sema.fail(block, arg_ty_src, "tag type must be an enum type", .{}); |
| 21332 | 21427 | } |
| 21333 | | const enum_tag_ty = tag_type_val.toType(); |
| 21334 | 21428 | |
| 21335 | | // We simply track which fields of the tag type have been seen. |
| 21336 | 21429 | const tag_ty_fields_len = enum_tag_ty.enumFieldCount(zcu); |
| 21337 | | var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len); |
| 21338 | 21430 | |
| 21339 | 21431 | for (0..fields_len) |field_idx| { |
| 21340 | | const field_info = try fields_val.elemValue(pt, field_idx); |
| 21432 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 21433 | // Don't pass a reason; first loop acts as a check that this is valid. |
| 21434 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); |
| 21341 | 21435 | |
| 21342 | | const field_name_val = try field_info.fieldValue(pt, 0); |
| 21343 | | const field_type_val = try field_info.fieldValue(pt, 1); |
| 21344 | | const field_alignment_val = try field_info.fieldValue(pt, 2); |
| 21345 | | |
| 21346 | | // Don't pass a reason; first loop acts as an assertion that this is valid. |
| 21347 | | const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined); |
| 21348 | | |
| 21349 | | const enum_index = enum_tag_ty.enumFieldIndex(field_name, zcu) orelse { |
| 21350 | | // TODO: better source location |
| 21351 | | return sema.fail(block, src, "no field named '{f}' in enum '{f}'", .{ |
| 21436 | if (field_idx >= tag_ty_fields_len) { |
| 21437 | return sema.fail(block, field_names_src, "no field named '{f}' in enum '{f}'", .{ |
| 21352 | 21438 | field_name.fmt(ip), enum_tag_ty.fmt(pt), |
| 21353 | 21439 | }); |
| 21354 | | }; |
| 21355 | | if (seen_tags.isSet(enum_index)) { |
| 21356 | | // TODO: better source location |
| 21357 | | return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)}); |
| 21358 | 21440 | } |
| 21359 | | seen_tags.set(enum_index); |
| 21360 | 21441 | |
| 21361 | | loaded_union.field_types.get(ip)[field_idx] = field_type_val.toIntern(); |
| 21362 | | const byte_align = try field_alignment_val.toUnsignedIntSema(pt); |
| 21363 | | if (layout == .@"packed") { |
| 21364 | | if (byte_align != 0) return sema.fail(block, src, "alignment of a packed union field must be set to 0", .{}); |
| 21365 | | } else { |
| 21366 | | loaded_union.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align); |
| 21442 | const enum_field_name = enum_tag_ty.enumFieldName(field_idx, zcu); |
| 21443 | if (enum_field_name != field_name) { |
| 21444 | return sema.fail(block, field_names_src, "union field name '{f}' does not match enum field name '{f}'", .{ |
| 21445 | field_name.fmt(ip), enum_field_name.fmt(ip), |
| 21446 | }); |
| 21367 | 21447 | } |
| 21368 | 21448 | } |
| 21369 | | |
| 21370 | 21449 | if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: { |
| 21371 | | const msg = try sema.errMsg(src, "enum fields missing in union", .{}); |
| 21450 | const msg = try sema.errMsg(field_names_src, "{d} enum fields missing in union", .{ |
| 21451 | tag_ty_fields_len - fields_len, |
| 21452 | }); |
| 21372 | 21453 | errdefer msg.destroy(gpa); |
| 21373 | | var it = seen_tags.iterator(.{ .kind = .unset }); |
| 21374 | | while (it.next()) |enum_index| { |
| 21375 | | const field_name = enum_tag_ty.enumFieldName(enum_index, zcu); |
| 21376 | | try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{f}' missing, declared here", .{ |
| 21377 | | field_name.fmt(ip), |
| 21454 | for (fields_len..tag_ty_fields_len) |enum_field_idx| { |
| 21455 | try sema.addFieldErrNote(enum_tag_ty, enum_field_idx, msg, "field '{f}' missing, declared here", .{ |
| 21456 | enum_tag_ty.enumFieldName(enum_field_idx, zcu).fmt(ip), |
| 21378 | 21457 | }); |
| 21379 | 21458 | } |
| 21380 | 21459 | try sema.addDeclaredHereNote(msg, enum_tag_ty); |
| 21381 | 21460 | break :msg msg; |
| 21382 | 21461 | }); |
| 21383 | | |
| 21384 | | break :tag_ty .{ enum_tag_ty.toIntern(), true }; |
| 21385 | | } else tag_ty: { |
| 21462 | break :tag .{ enum_tag_ty.toIntern(), true }; |
| 21463 | } else tag: { |
| 21386 | 21464 | // We must track field names and set up the tag type ourselves. |
| 21387 | 21465 | var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty; |
| 21388 | 21466 | try field_names.ensureTotalCapacity(sema.arena, fields_len); |
| 21389 | 21467 | |
| 21390 | 21468 | for (0..fields_len) |field_idx| { |
| 21391 | | const field_info = try fields_val.elemValue(pt, field_idx); |
| 21392 | | |
| 21393 | | const field_name_val = try field_info.fieldValue(pt, 0); |
| 21394 | | const field_type_val = try field_info.fieldValue(pt, 1); |
| 21395 | | const field_alignment_val = try field_info.fieldValue(pt, 2); |
| 21396 | | |
| 21397 | | // Don't pass a reason; first loop acts as an assertion that this is valid. |
| 21398 | | const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined); |
| 21469 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 21470 | // Don't pass a reason; first loop acts as a check that this is valid. |
| 21471 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); |
| 21399 | 21472 | const gop = field_names.getOrPutAssumeCapacity(field_name); |
| 21400 | 21473 | if (gop.found_existing) { |
| 21401 | 21474 | // TODO: better source location |
| 21402 | | return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)}); |
| 21403 | | } |
| 21404 | | |
| 21405 | | loaded_union.field_types.get(ip)[field_idx] = field_type_val.toIntern(); |
| 21406 | | const byte_align = try field_alignment_val.toUnsignedIntSema(pt); |
| 21407 | | if (layout == .@"packed") { |
| 21408 | | if (byte_align != 0) return sema.fail(block, src, "alignment of a packed union field must be set to 0", .{}); |
| 21409 | | } else { |
| 21410 | | loaded_union.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align); |
| 21475 | return sema.fail(block, field_names_src, "duplicate union field {f}", .{field_name.fmt(ip)}); |
| 21411 | 21476 | } |
| 21412 | 21477 | } |
| 21413 | | |
| 21414 | 21478 | const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), wip_ty.index, type_name.name); |
| 21415 | | break :tag_ty .{ enum_tag_ty, false }; |
| 21479 | break :tag .{ enum_tag_ty, false }; |
| 21416 | 21480 | }; |
| 21417 | 21481 | errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error |
| 21418 | 21482 | |
| 21419 | | for (loaded_union.field_types.get(ip)) |field_ty_ip| { |
| 21420 | | const field_ty: Type = .fromInterned(field_ty_ip); |
| 21483 | for (0..fields_len) |field_idx| { |
| 21484 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); |
| 21485 | const field_attrs = try sema.interpretBuiltinType( |
| 21486 | block, |
| 21487 | field_attrs_src, |
| 21488 | try field_attrs_arr.elemValue(pt, field_idx), |
| 21489 | std.builtin.Type.UnionField.Attributes, |
| 21490 | ); |
| 21491 | |
| 21421 | 21492 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 21422 | 21493 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21423 | | const msg = try sema.errMsg(src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); |
| 21494 | const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); |
| 21424 | 21495 | errdefer msg.destroy(gpa); |
| 21425 | | |
| 21426 | 21496 | try sema.addDeclaredHereNote(msg, field_ty); |
| 21427 | 21497 | break :msg msg; |
| 21428 | 21498 | }); |
| 21429 | 21499 | } |
| 21430 | | if (layout == .@"extern" and !try sema.validateExternType(field_ty, .union_field)) { |
| 21431 | | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21432 | | const msg = try sema.errMsg(src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 21433 | | errdefer msg.destroy(gpa); |
| 21434 | 21500 | |
| 21435 | | try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .union_field); |
| 21501 | switch (layout) { |
| 21502 | .auto => {}, |
| 21503 | .@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) { |
| 21504 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21505 | const msg = try sema.errMsg(field_types_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 21506 | errdefer msg.destroy(gpa); |
| 21507 | |
| 21508 | try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .union_field); |
| 21436 | 21509 | |
| 21437 | | try sema.addDeclaredHereNote(msg, field_ty); |
| 21438 | | break :msg msg; |
| 21439 | | }); |
| 21440 | | } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) { |
| 21441 | | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21442 | | const msg = try sema.errMsg(src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 21443 | | errdefer msg.destroy(gpa); |
| 21510 | try sema.addDeclaredHereNote(msg, field_ty); |
| 21511 | break :msg msg; |
| 21512 | }); |
| 21513 | }, |
| 21514 | .@"packed" => if (!try sema.validatePackedType(field_ty)) { |
| 21515 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21516 | const msg = try sema.errMsg(field_types_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 21517 | errdefer msg.destroy(gpa); |
| 21444 | 21518 | |
| 21445 | | try sema.explainWhyTypeIsNotPacked(msg, src, field_ty); |
| 21519 | try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty); |
| 21446 | 21520 | |
| 21447 | | try sema.addDeclaredHereNote(msg, field_ty); |
| 21448 | | break :msg msg; |
| 21449 | | }); |
| 21521 | try sema.addDeclaredHereNote(msg, field_ty); |
| 21522 | break :msg msg; |
| 21523 | }); |
| 21524 | }, |
| 21525 | } |
| 21526 | |
| 21527 | loaded_union.field_types.get(ip)[field_idx] = field_ty.toIntern(); |
| 21528 | if (field_attrs.@"align") |bytes| { |
| 21529 | assert(layout != .@"packed"); |
| 21530 | const a = try sema.validateAlign(block, field_attrs_src, bytes); |
| 21531 | loaded_union.field_aligns.get(ip)[field_idx] = a; |
| 21532 | } else if (any_aligned_fields) { |
| 21533 | assert(layout != .@"packed"); |
| 21534 | loaded_union.field_aligns.get(ip)[field_idx] = .none; |
| 21450 | 21535 | } |
| 21451 | 21536 | } |
| 21452 | 21537 | |
| ... | ... | @@ -21471,116 +21556,94 @@ fn reifyUnion( |
| 21471 | 21556 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 21472 | 21557 | try sema.addTypeReferenceEntry(src, wip_ty.index); |
| 21473 | 21558 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); |
| 21474 | | return Air.internedToRef(wip_ty.finish(ip, new_namespace_index)); |
| 21559 | return .fromIntern(wip_ty.finish(ip, new_namespace_index)); |
| 21475 | 21560 | } |
| 21476 | 21561 | |
| 21477 | | fn reifyTuple( |
| 21562 | fn zirReifyEnum( |
| 21478 | 21563 | sema: *Sema, |
| 21479 | 21564 | block: *Block, |
| 21480 | | src: LazySrcLoc, |
| 21481 | | fields_val: Value, |
| 21565 | extended: Zir.Inst.Extended.InstData, |
| 21566 | inst: Zir.Inst.Index, |
| 21482 | 21567 | ) CompileError!Air.Inst.Ref { |
| 21483 | 21568 | const pt = sema.pt; |
| 21484 | 21569 | const zcu = pt.zcu; |
| 21485 | 21570 | const gpa = sema.gpa; |
| 21486 | 21571 | const ip = &zcu.intern_pool; |
| 21487 | 21572 | |
| 21488 | | const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu)); |
| 21489 | | |
| 21490 | | const types = try sema.arena.alloc(InternPool.Index, fields_len); |
| 21491 | | const inits = try sema.arena.alloc(InternPool.Index, fields_len); |
| 21492 | | |
| 21493 | | for (types, inits, 0..) |*field_ty, *field_init, field_idx| { |
| 21494 | | const field_info = try fields_val.elemValue(pt, field_idx); |
| 21495 | | |
| 21496 | | const field_name_val = try field_info.fieldValue(pt, 0); |
| 21497 | | const field_type_val = try field_info.fieldValue(pt, 1); |
| 21498 | | const field_default_value_val = try field_info.fieldValue(pt, 2); |
| 21499 | | const field_is_comptime_val = try field_info.fieldValue(pt, 3); |
| 21500 | | const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 4)); |
| 21501 | | |
| 21502 | | const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .tuple_field_name }); |
| 21503 | | const field_type = field_type_val.toType(); |
| 21504 | | const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(zcu)) |ptr_val| d: { |
| 21505 | | const ptr_ty = try pt.singleConstPtrType(field_type_val.toType()); |
| 21506 | | // We need to do this deref here, so we won't check for this error case later on. |
| 21507 | | const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime( |
| 21508 | | block, |
| 21509 | | src, |
| 21510 | | .{ .simple = .tuple_field_default_value }, |
| 21511 | | ); |
| 21512 | | if (val.canMutateComptimeVarState(zcu)) { |
| 21513 | | return sema.failWithContainsReferenceToComptimeVar(block, src, field_name, "field default value", val); |
| 21514 | | } |
| 21515 | | // Resolve the value so that lazy values do not create distinct types. |
| 21516 | | break :d (try sema.resolveLazyValue(val)).toIntern(); |
| 21517 | | } else .none; |
| 21573 | const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small); |
| 21574 | const extra = sema.code.extraData(Zir.Inst.ReifyEnum, extended.operand).data; |
| 21575 | const tracked_inst = try block.trackZir(inst); |
| 21576 | const src: LazySrcLoc = .{ |
| 21577 | .base_node_inst = tracked_inst, |
| 21578 | .offset = .nodeOffset(.zero), |
| 21579 | }; |
| 21518 | 21580 | |
| 21519 | | const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail( |
| 21520 | | block, |
| 21521 | | src, |
| 21522 | | "tuple cannot have non-numeric field '{f}'", |
| 21523 | | .{field_name.fmt(ip)}, |
| 21524 | | ); |
| 21525 | | if (field_name_index != field_idx) { |
| 21526 | | return sema.fail( |
| 21527 | | block, |
| 21528 | | src, |
| 21529 | | "tuple field name '{d}' does not match field index {d}", |
| 21530 | | .{ field_name_index, field_idx }, |
| 21531 | | ); |
| 21532 | | } |
| 21581 | const tag_ty_src: LazySrcLoc = .{ |
| 21582 | .base_node_inst = tracked_inst, |
| 21583 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 21584 | .builtin_call_node = .zero, |
| 21585 | .arg_index = 0, |
| 21586 | } }, |
| 21587 | }; |
| 21588 | const mode_src: LazySrcLoc = .{ |
| 21589 | .base_node_inst = tracked_inst, |
| 21590 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 21591 | .builtin_call_node = .zero, |
| 21592 | .arg_index = 1, |
| 21593 | } }, |
| 21594 | }; |
| 21595 | const field_names_src: LazySrcLoc = .{ |
| 21596 | .base_node_inst = tracked_inst, |
| 21597 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 21598 | .builtin_call_node = .zero, |
| 21599 | .arg_index = 2, |
| 21600 | } }, |
| 21601 | }; |
| 21602 | const field_values_src: LazySrcLoc = .{ |
| 21603 | .base_node_inst = tracked_inst, |
| 21604 | .offset = .{ .node_offset_builtin_call_arg = .{ |
| 21605 | .builtin_call_node = .zero, |
| 21606 | .arg_index = 3, |
| 21607 | } }, |
| 21608 | }; |
| 21533 | 21609 | |
| 21534 | | try sema.validateTupleFieldType(block, field_type, src); |
| 21610 | const enum_mode_ty = try sema.getBuiltinType(mode_src, .@"Type.Enum.Mode"); |
| 21535 | 21611 | |
| 21536 | | { |
| 21537 | | const alignment_ok = ok: { |
| 21538 | | if (field_alignment_val.toIntern() == .zero) break :ok true; |
| 21539 | | const given_align = try field_alignment_val.getUnsignedIntSema(pt) orelse break :ok false; |
| 21540 | | const abi_align = (try field_type.abiAlignmentSema(pt)).toByteUnits() orelse 0; |
| 21541 | | break :ok abi_align == given_align; |
| 21542 | | }; |
| 21543 | | if (!alignment_ok) { |
| 21544 | | return sema.fail(block, src, "tuple fields cannot specify alignment", .{}); |
| 21545 | | } |
| 21546 | | } |
| 21612 | const tag_ty = try sema.resolveType(block, tag_ty_src, extra.tag_ty); |
| 21613 | if (tag_ty.zigTypeTag(zcu) != .int) { |
| 21614 | return sema.fail(block, tag_ty_src, "tag type must be an integer type", .{}); |
| 21615 | } |
| 21547 | 21616 | |
| 21548 | | if (field_is_comptime_val.toBool() and field_default_value == .none) { |
| 21549 | | return sema.fail(block, src, "comptime field without default initialization value", .{}); |
| 21550 | | } |
| 21617 | const mode_uncoerced = try sema.resolveInst(extra.mode); |
| 21618 | const mode_coerced = try sema.coerce(block, enum_mode_ty, mode_uncoerced, mode_src); |
| 21619 | const mode_val = try sema.resolveConstDefinedValue(block, mode_src, mode_coerced, .{ .simple = .type }); |
| 21620 | const nonexhaustive = switch (try sema.interpretBuiltinType(block, mode_src, mode_val, std.builtin.Type.Enum.Mode)) { |
| 21621 | .exhaustive => false, |
| 21622 | .nonexhaustive => true, |
| 21623 | }; |
| 21551 | 21624 | |
| 21552 | | if (!field_is_comptime_val.toBool() and field_default_value != .none) { |
| 21553 | | return sema.fail(block, src, "non-comptime tuple fields cannot specify default initialization value", .{}); |
| 21554 | | } |
| 21625 | const field_names_uncoerced = try sema.resolveInst(extra.field_names); |
| 21626 | const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src); |
| 21627 | const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .enum_field_names }); |
| 21628 | const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .enum_field_names }); |
| 21555 | 21629 | |
| 21556 | | field_ty.* = field_type.toIntern(); |
| 21557 | | field_init.* = field_default_value; |
| 21558 | | } |
| 21630 | const fields_len = try sema.usizeCast(block, src, field_names_arr.typeOf(zcu).arrayLen(zcu)); |
| 21559 | 21631 | |
| 21560 | | return Air.internedToRef(try zcu.intern_pool.getTupleType(gpa, pt.tid, .{ |
| 21561 | | .types = types, |
| 21562 | | .values = inits, |
| 21632 | const field_values_ty = try pt.singleConstPtrType(try pt.arrayType(.{ |
| 21633 | .len = fields_len, |
| 21634 | .child = tag_ty.toIntern(), |
| 21563 | 21635 | })); |
| 21564 | | } |
| 21565 | | |
| 21566 | | fn reifyStruct( |
| 21567 | | sema: *Sema, |
| 21568 | | block: *Block, |
| 21569 | | inst: Zir.Inst.Index, |
| 21570 | | src: LazySrcLoc, |
| 21571 | | layout: std.builtin.Type.ContainerLayout, |
| 21572 | | opt_backing_int_val: Value, |
| 21573 | | fields_val: Value, |
| 21574 | | name_strategy: Zir.Inst.NameStrategy, |
| 21575 | | ) CompileError!Air.Inst.Ref { |
| 21576 | | const pt = sema.pt; |
| 21577 | | const zcu = pt.zcu; |
| 21578 | | const gpa = sema.gpa; |
| 21579 | | const ip = &zcu.intern_pool; |
| 21580 | 21636 | |
| 21581 | | // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`. |
| 21637 | const field_values_uncoerced = try sema.resolveInst(extra.field_values); |
| 21638 | const field_values_coerced = try sema.coerce(block, field_values_ty, field_values_uncoerced, field_values_src); |
| 21639 | const field_values_slice = try sema.resolveConstDefinedValue(block, field_values_src, field_values_coerced, .{ .simple = .enum_field_values }); |
| 21640 | const field_values_arr = try sema.derefSliceAsArray(block, field_values_src, field_values_slice, .{ .simple = .enum_field_values }); |
| 21582 | 21641 | |
| 21583 | | const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu)); |
| 21642 | // Before we begin, check for undefs... |
| 21643 | if (try sema.anyUndef(block, field_values_src, field_values_arr)) { |
| 21644 | return sema.failWithUseOfUndef(block, field_values_src, null); |
| 21645 | } |
| 21646 | // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us. |
| 21584 | 21647 | |
| 21585 | 21648 | // The validation work here is non-trivial, and it's possible the type already exists. |
| 21586 | 21649 | // So in this first pass, let's just construct a hash to optimize for this case. If the |
| ... | ... | @@ -21589,62 +21652,23 @@ fn reifyStruct( |
| 21589 | 21652 | // For deduplication purposes, we must create a hash including all details of this type. |
| 21590 | 21653 | // TODO: use a longer hash! |
| 21591 | 21654 | var hasher = std.hash.Wyhash.init(0); |
| 21592 | | std.hash.autoHash(&hasher, layout); |
| 21593 | | std.hash.autoHash(&hasher, opt_backing_int_val.toIntern()); |
| 21655 | std.hash.autoHash(&hasher, tag_ty.toIntern()); |
| 21656 | std.hash.autoHash(&hasher, nonexhaustive); |
| 21594 | 21657 | std.hash.autoHash(&hasher, fields_len); |
| 21595 | | |
| 21596 | | var any_comptime_fields = false; |
| 21597 | | var any_default_inits = false; |
| 21598 | | |
| 21658 | // `field_values_arr` is already deduplicated by the InternPool! |
| 21659 | std.hash.autoHash(&hasher, field_values_arr); |
| 21660 | // However, for field names, we need to iterate the individual fields, because the pointers (the |
| 21661 | // names are slices) mean that distinct values could ultimately result in the same enum type. |
| 21599 | 21662 | for (0..fields_len) |field_idx| { |
| 21600 | | const field_info = try fields_val.elemValue(pt, field_idx); |
| 21601 | | |
| 21602 | | const field_name_val = try field_info.fieldValue(pt, 0); |
| 21603 | | const field_type_val = try field_info.fieldValue(pt, 1); |
| 21604 | | const field_default_value_val = try field_info.fieldValue(pt, 2); |
| 21605 | | const field_is_comptime_val = try field_info.fieldValue(pt, 3); |
| 21606 | | const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 4)); |
| 21607 | | |
| 21608 | | const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .struct_field_name }); |
| 21609 | | const field_is_comptime = field_is_comptime_val.toBool(); |
| 21610 | | const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(zcu)) |ptr_val| d: { |
| 21611 | | const ptr_ty = try pt.singleConstPtrType(field_type_val.toType()); |
| 21612 | | // We need to do this deref here, so we won't check for this error case later on. |
| 21613 | | const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime( |
| 21614 | | block, |
| 21615 | | src, |
| 21616 | | .{ .simple = .struct_field_default_value }, |
| 21617 | | ); |
| 21618 | | if (val.canMutateComptimeVarState(zcu)) { |
| 21619 | | return sema.failWithContainsReferenceToComptimeVar(block, src, field_name, "field default value", val); |
| 21620 | | } |
| 21621 | | // Resolve the value so that lazy values do not create distinct types. |
| 21622 | | break :d (try sema.resolveLazyValue(val)).toIntern(); |
| 21623 | | } else .none; |
| 21624 | | |
| 21625 | | std.hash.autoHash(&hasher, .{ |
| 21626 | | field_name, |
| 21627 | | field_type_val.toIntern(), |
| 21628 | | field_default_value, |
| 21629 | | field_is_comptime, |
| 21630 | | field_alignment_val.toIntern(), |
| 21631 | | }); |
| 21632 | | |
| 21633 | | if (field_is_comptime) any_comptime_fields = true; |
| 21634 | | if (field_default_value != .none) any_default_inits = true; |
| 21663 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 21664 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, .{ .simple = .enum_field_names }); |
| 21665 | std.hash.autoHash(&hasher, field_name); |
| 21635 | 21666 | } |
| 21636 | 21667 | |
| 21637 | | const tracked_inst = try block.trackZir(inst); |
| 21638 | | |
| 21639 | | const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{ |
| 21640 | | .layout = layout, |
| 21641 | | .fields_len = fields_len, |
| 21642 | | .known_non_opv = false, |
| 21643 | | .requires_comptime = .unknown, |
| 21644 | | .any_comptime_fields = any_comptime_fields, |
| 21645 | | .any_default_inits = any_default_inits, |
| 21646 | | .any_aligned_fields = layout != .@"packed", |
| 21647 | | .inits_resolved = true, |
| 21668 | const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{ |
| 21669 | .has_values = true, |
| 21670 | .tag_mode = if (nonexhaustive) .nonexhaustive else .explicit, |
| 21671 | .fields_len = @intCast(fields_len), |
| 21648 | 21672 | .key = .{ .reified = .{ |
| 21649 | 21673 | .zir_index = tracked_inst, |
| 21650 | 21674 | .type_hash = hasher.final(), |
| ... | ... | @@ -21654,152 +21678,66 @@ fn reifyStruct( |
| 21654 | 21678 | .existing => |ty| { |
| 21655 | 21679 | try sema.declareDependency(.{ .interned = ty }); |
| 21656 | 21680 | try sema.addTypeReferenceEntry(src, ty); |
| 21657 | | return Air.internedToRef(ty); |
| 21681 | return .fromIntern(ty); |
| 21658 | 21682 | }, |
| 21659 | 21683 | }; |
| 21660 | | errdefer wip_ty.cancel(ip, pt.tid); |
| 21684 | var done = false; |
| 21685 | errdefer if (!done) wip_ty.cancel(ip, pt.tid); |
| 21661 | 21686 | |
| 21662 | 21687 | const type_name = try sema.createTypeName( |
| 21663 | 21688 | block, |
| 21664 | 21689 | name_strategy, |
| 21665 | | "struct", |
| 21690 | "enum", |
| 21666 | 21691 | inst, |
| 21667 | 21692 | wip_ty.index, |
| 21668 | 21693 | ); |
| 21669 | 21694 | wip_ty.setName(ip, type_name.name, type_name.nav); |
| 21670 | 21695 | |
| 21671 | | const struct_type = ip.loadStructType(wip_ty.index); |
| 21672 | | |
| 21673 | | for (0..fields_len) |field_idx| { |
| 21674 | | const field_info = try fields_val.elemValue(pt, field_idx); |
| 21675 | | |
| 21676 | | const field_name_val = try field_info.fieldValue(pt, 0); |
| 21677 | | const field_type_val = try field_info.fieldValue(pt, 1); |
| 21678 | | const field_default_value_val = try field_info.fieldValue(pt, 2); |
| 21679 | | const field_is_comptime_val = try field_info.fieldValue(pt, 3); |
| 21680 | | const field_alignment_val = try field_info.fieldValue(pt, 4); |
| 21681 | | |
| 21682 | | const field_ty = field_type_val.toType(); |
| 21683 | | // Don't pass a reason; first loop acts as an assertion that this is valid. |
| 21684 | | const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined); |
| 21685 | | if (struct_type.addFieldName(ip, field_name)) |prev_index| { |
| 21686 | | _ = prev_index; // TODO: better source location |
| 21687 | | return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)}); |
| 21688 | | } |
| 21689 | | |
| 21690 | | if (!try sema.intFitsInType(field_alignment_val, align_ty, null)) { |
| 21691 | | return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)}); |
| 21692 | | } |
| 21693 | | const byte_align = try field_alignment_val.toUnsignedIntSema(pt); |
| 21694 | | if (layout == .@"packed") { |
| 21695 | | if (byte_align != 0) return sema.fail(block, src, "alignment of a packed struct field must be set to 0", .{}); |
| 21696 | | } else { |
| 21697 | | struct_type.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align); |
| 21698 | | } |
| 21699 | | |
| 21700 | | const field_is_comptime = field_is_comptime_val.toBool(); |
| 21701 | | if (field_is_comptime) { |
| 21702 | | assert(any_comptime_fields); |
| 21703 | | switch (layout) { |
| 21704 | | .@"extern" => return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}), |
| 21705 | | .@"packed" => return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{}), |
| 21706 | | .auto => struct_type.setFieldComptime(ip, field_idx), |
| 21707 | | } |
| 21708 | | } |
| 21709 | | |
| 21710 | | const field_default: InternPool.Index = d: { |
| 21711 | | if (!any_default_inits) break :d .none; |
| 21712 | | const ptr_val = field_default_value_val.optionalValue(zcu) orelse break :d .none; |
| 21713 | | const ptr_ty = try pt.singleConstPtrType(field_ty); |
| 21714 | | // Asserted comptime-dereferencable above. |
| 21715 | | const val = (try sema.pointerDeref(block, src, ptr_val, ptr_ty)).?; |
| 21716 | | // We already resolved this for deduplication, so we may as well do it now. |
| 21717 | | break :d (try sema.resolveLazyValue(val)).toIntern(); |
| 21718 | | }; |
| 21719 | | |
| 21720 | | if (field_is_comptime and field_default == .none) { |
| 21721 | | return sema.fail(block, src, "comptime field without default initialization value", .{}); |
| 21722 | | } |
| 21723 | | |
| 21724 | | struct_type.field_types.get(ip)[field_idx] = field_type_val.toIntern(); |
| 21725 | | if (field_default != .none) { |
| 21726 | | struct_type.field_inits.get(ip)[field_idx] = field_default; |
| 21727 | | } |
| 21728 | | |
| 21729 | | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 21730 | | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21731 | | const msg = try sema.errMsg(src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 21732 | | errdefer msg.destroy(gpa); |
| 21733 | | |
| 21734 | | try sema.addDeclaredHereNote(msg, field_ty); |
| 21735 | | break :msg msg; |
| 21736 | | }); |
| 21737 | | } |
| 21738 | | if (field_ty.zigTypeTag(zcu) == .noreturn) { |
| 21739 | | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21740 | | const msg = try sema.errMsg(src, "struct fields cannot be 'noreturn'", .{}); |
| 21741 | | errdefer msg.destroy(gpa); |
| 21742 | | |
| 21743 | | try sema.addDeclaredHereNote(msg, field_ty); |
| 21744 | | break :msg msg; |
| 21745 | | }); |
| 21746 | | } |
| 21747 | | if (layout == .@"extern" and !try sema.validateExternType(field_ty, .struct_field)) { |
| 21748 | | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21749 | | const msg = try sema.errMsg(src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 21750 | | errdefer msg.destroy(gpa); |
| 21696 | const new_namespace_index = try pt.createNamespace(.{ |
| 21697 | .parent = block.namespace.toOptional(), |
| 21698 | .owner_type = wip_ty.index, |
| 21699 | .file_scope = block.getFileScopeIndex(zcu), |
| 21700 | .generation = zcu.generation, |
| 21701 | }); |
| 21751 | 21702 | |
| 21752 | | try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .struct_field); |
| 21703 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 21704 | try sema.addTypeReferenceEntry(src, wip_ty.index); |
| 21705 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); |
| 21706 | wip_ty.prepare(ip, new_namespace_index); |
| 21707 | wip_ty.setTagTy(ip, tag_ty.toIntern()); |
| 21708 | done = true; |
| 21753 | 21709 | |
| 21754 | | try sema.addDeclaredHereNote(msg, field_ty); |
| 21755 | | break :msg msg; |
| 21756 | | }); |
| 21757 | | } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) { |
| 21758 | | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21759 | | const msg = try sema.errMsg(src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 21760 | | errdefer msg.destroy(gpa); |
| 21710 | for (0..fields_len) |field_idx| { |
| 21711 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 21712 | // Don't pass a reason; first loop acts as a check that this is valid. |
| 21713 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); |
| 21761 | 21714 | |
| 21762 | | try sema.explainWhyTypeIsNotPacked(msg, src, field_ty); |
| 21715 | const field_val = try field_values_arr.elemValue(pt, field_idx); |
| 21763 | 21716 | |
| 21764 | | try sema.addDeclaredHereNote(msg, field_ty); |
| 21765 | | break :msg msg; |
| 21717 | if (wip_ty.nextField(ip, field_name, field_val.toIntern())) |conflict| { |
| 21718 | return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) { |
| 21719 | .name => msg: { |
| 21720 | const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}'", .{field_name.fmt(ip)}); |
| 21721 | errdefer msg.destroy(gpa); |
| 21722 | _ = conflict.prev_field_idx; // TODO: this note is incorrect |
| 21723 | try sema.errNote(field_names_src, msg, "other field here", .{}); |
| 21724 | break :msg msg; |
| 21725 | }, |
| 21726 | .value => msg: { |
| 21727 | const msg = try sema.errMsg(field_values_src, "enum tag value {f} already taken", .{field_val.fmtValueSema(pt, sema)}); |
| 21728 | errdefer msg.destroy(gpa); |
| 21729 | _ = conflict.prev_field_idx; // TODO: this note is incorrect |
| 21730 | try sema.errNote(field_values_src, msg, "other enum tag value here", .{}); |
| 21731 | break :msg msg; |
| 21732 | }, |
| 21766 | 21733 | }); |
| 21767 | 21734 | } |
| 21768 | 21735 | } |
| 21769 | 21736 | |
| 21770 | | if (layout == .@"packed") { |
| 21771 | | var fields_bit_sum: u64 = 0; |
| 21772 | | for (0..struct_type.field_types.len) |field_idx| { |
| 21773 | | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_idx]); |
| 21774 | | field_ty.resolveLayout(pt) catch |err| switch (err) { |
| 21775 | | error.AnalysisFail => { |
| 21776 | | const msg = sema.err orelse return err; |
| 21777 | | try sema.errNote(src, msg, "while checking a field of this struct", .{}); |
| 21778 | | return err; |
| 21779 | | }, |
| 21780 | | else => return err, |
| 21781 | | }; |
| 21782 | | fields_bit_sum += field_ty.bitSize(zcu); |
| 21783 | | } |
| 21784 | | |
| 21785 | | if (opt_backing_int_val.optionalValue(zcu)) |backing_int_val| { |
| 21786 | | const backing_int_ty = backing_int_val.toType(); |
| 21787 | | try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum); |
| 21788 | | struct_type.setBackingIntType(ip, backing_int_ty.toIntern()); |
| 21789 | | } else { |
| 21790 | | const backing_int_ty = try pt.intType(.unsigned, @intCast(fields_bit_sum)); |
| 21791 | | struct_type.setBackingIntType(ip, backing_int_ty.toIntern()); |
| 21792 | | } |
| 21737 | if (nonexhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) { |
| 21738 | return sema.fail(block, src, "non-exhaustive enum specified every value", .{}); |
| 21793 | 21739 | } |
| 21794 | 21740 | |
| 21795 | | const new_namespace_index = try pt.createNamespace(.{ |
| 21796 | | .parent = block.namespace.toOptional(), |
| 21797 | | .owner_type = wip_ty.index, |
| 21798 | | .file_scope = block.getFileScopeIndex(zcu), |
| 21799 | | .generation = zcu.generation, |
| 21800 | | }); |
| 21801 | | |
| 21802 | | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); |
| 21803 | 21741 | codegen_type: { |
| 21804 | 21742 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| 21805 | 21743 | if (block.ownerModule().strip) break :codegen_type; |
| ... | ... | @@ -21807,10 +21745,7 @@ fn reifyStruct( |
| 21807 | 21745 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); |
| 21808 | 21746 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); |
| 21809 | 21747 | } |
| 21810 | | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 21811 | | try sema.addTypeReferenceEntry(src, wip_ty.index); |
| 21812 | | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); |
| 21813 | | return Air.internedToRef(wip_ty.finish(ip, new_namespace_index)); |
| 21748 | return Air.internedToRef(wip_ty.index); |
| 21814 | 21749 | } |
| 21815 | 21750 | |
| 21816 | 21751 | fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -25541,7 +25476,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 25541 | 25476 | extra_index += body.len; |
| 25542 | 25477 | if (extra.data.bits.ret_ty_is_generic) break :blk .generic_poison; |
| 25543 | 25478 | |
| 25544 | | const val = try sema.resolveGenericBody(block, ret_src, body, inst, .type, .{ .simple = .function_ret_ty }); |
| 25479 | const val = try sema.resolveGenericBody(block, ret_src, body, inst, .type, .{ .simple = .fn_ret_ty }); |
| 25545 | 25480 | const ty = val.toType(); |
| 25546 | 25481 | break :blk ty; |
| 25547 | 25482 | } else if (extra.data.bits.has_ret_ty_ref) blk: { |
| ... | ... | @@ -25968,21 +25903,26 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 25968 | 25903 | const src = block.nodeOffset(src_node); |
| 25969 | 25904 | const value: Zir.Inst.BuiltinValue = @enumFromInt(extended.small); |
| 25970 | 25905 | |
| 25971 | | const ty = switch (value) { |
| 25906 | const builtin_type: Zcu.BuiltinDecl = switch (value) { |
| 25972 | 25907 | // zig fmt: off |
| 25973 | | .atomic_order => try sema.getBuiltinType(src, .AtomicOrder), |
| 25974 | | .atomic_rmw_op => try sema.getBuiltinType(src, .AtomicRmwOp), |
| 25975 | | .calling_convention => try sema.getBuiltinType(src, .CallingConvention), |
| 25976 | | .address_space => try sema.getBuiltinType(src, .AddressSpace), |
| 25977 | | .float_mode => try sema.getBuiltinType(src, .FloatMode), |
| 25978 | | .reduce_op => try sema.getBuiltinType(src, .ReduceOp), |
| 25979 | | .call_modifier => try sema.getBuiltinType(src, .CallModifier), |
| 25980 | | .prefetch_options => try sema.getBuiltinType(src, .PrefetchOptions), |
| 25981 | | .export_options => try sema.getBuiltinType(src, .ExportOptions), |
| 25982 | | .extern_options => try sema.getBuiltinType(src, .ExternOptions), |
| 25983 | | .type_info => try sema.getBuiltinType(src, .Type), |
| 25984 | | .branch_hint => try sema.getBuiltinType(src, .BranchHint), |
| 25985 | | .clobbers => try sema.getBuiltinType(src, .@"assembly.Clobbers"), |
| 25908 | .atomic_order => .AtomicOrder, |
| 25909 | .atomic_rmw_op => .AtomicRmwOp, |
| 25910 | .calling_convention => .CallingConvention, |
| 25911 | .address_space => .AddressSpace, |
| 25912 | .float_mode => .FloatMode, |
| 25913 | .signedness => .Signedness, |
| 25914 | .reduce_op => .ReduceOp, |
| 25915 | .call_modifier => .CallModifier, |
| 25916 | .prefetch_options => .PrefetchOptions, |
| 25917 | .export_options => .ExportOptions, |
| 25918 | .extern_options => .ExternOptions, |
| 25919 | .branch_hint => .BranchHint, |
| 25920 | .clobbers => .@"assembly.Clobbers", |
| 25921 | .pointer_size => .@"Type.Pointer.Size", |
| 25922 | .pointer_attributes => .@"Type.Pointer.Attributes", |
| 25923 | .fn_attributes, => .@"Type.Fn.Attributes", |
| 25924 | .container_layout => .@"Type.ContainerLayout", |
| 25925 | .enum_mode => .@"Type.Enum.Mode", |
| 25986 | 25926 | // zig fmt: on |
| 25987 | 25927 | |
| 25988 | 25928 | // Values are handled here. |
| ... | ... | @@ -26009,7 +25949,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 26009 | 25949 | return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src); |
| 26010 | 25950 | }, |
| 26011 | 25951 | }; |
| 26012 | | return Air.internedToRef(ty.toIntern()); |
| 25952 | return .fromType(try sema.getBuiltinType(src, builtin_type)); |
| 26013 | 25953 | } |
| 26014 | 25954 | |
| 26015 | 25955 | fn zirInplaceArithResultTy(sema: *Sema, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -35259,7 +35199,7 @@ fn structFields( |
| 35259 | 35199 | .base_node_inst = struct_type.zir_index, |
| 35260 | 35200 | .offset = .nodeOffset(.zero), |
| 35261 | 35201 | }, |
| 35262 | | .r = .{ .simple = .struct_fields }, |
| 35202 | .r = .{ .simple = .type }, |
| 35263 | 35203 | } }, |
| 35264 | 35204 | .src_base_inst = struct_type.zir_index, |
| 35265 | 35205 | .type_name_ctx = struct_type.name, |
| ... | ... | @@ -35614,7 +35554,7 @@ fn unionFields( |
| 35614 | 35554 | .inlining = null, |
| 35615 | 35555 | .comptime_reason = .{ .reason = .{ |
| 35616 | 35556 | .src = src, |
| 35617 | | .r = .{ .simple = .union_fields }, |
| 35557 | .r = .{ .simple = .type }, |
| 35618 | 35558 | } }, |
| 35619 | 35559 | .src_base_inst = union_type.zir_index, |
| 35620 | 35560 | .type_name_ctx = union_type.name, |
| ... | ... | @@ -36077,8 +36017,13 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 36077 | 36017 | .manyptr_u8_type, |
| 36078 | 36018 | .manyptr_const_u8_type, |
| 36079 | 36019 | .manyptr_const_u8_sentinel_0_type, |
| 36020 | .manyptr_const_slice_const_u8_type, |
| 36080 | 36021 | .slice_const_u8_type, |
| 36081 | 36022 | .slice_const_u8_sentinel_0_type, |
| 36023 | .slice_const_slice_const_u8_type, |
| 36024 | .optional_type_type, |
| 36025 | .manyptr_const_type_type, |
| 36026 | .slice_const_type_type, |
| 36082 | 36027 | .vector_8_i8_type, |
| 36083 | 36028 | .vector_16_i8_type, |
| 36084 | 36029 | .vector_32_i8_type, |
| ... | ... | @@ -37230,7 +37175,7 @@ fn sliceToIpString( |
| 37230 | 37175 | |
| 37231 | 37176 | /// Given a slice value, attempts to dereference it into a comptime-known array. |
| 37232 | 37177 | /// Emits a compile error if the contents of the slice are not comptime-known. |
| 37233 | | /// Asserts that `slice_val` is a slice. |
| 37178 | /// Asserts that `slice_val` is a slice or a pointer to an array. |
| 37234 | 37179 | fn derefSliceAsArray( |
| 37235 | 37180 | sema: *Sema, |
| 37236 | 37181 | block: *Block, |
| ... | ... | @@ -37247,7 +37192,7 @@ fn derefSliceAsArray( |
| 37247 | 37192 | |
| 37248 | 37193 | /// Given a slice value, attempts to dereference it into a comptime-known array. |
| 37249 | 37194 | /// Returns `null` if the contents of the slice are not comptime-known. |
| 37250 | | /// Asserts that `slice_val` is a slice. |
| 37195 | /// Asserts that `slice_val` is a slice or a pointer to an array. |
| 37251 | 37196 | fn maybeDerefSliceAsArray( |
| 37252 | 37197 | sema: *Sema, |
| 37253 | 37198 | block: *Block, |
| ... | ... | @@ -37257,7 +37202,13 @@ fn maybeDerefSliceAsArray( |
| 37257 | 37202 | const pt = sema.pt; |
| 37258 | 37203 | const zcu = pt.zcu; |
| 37259 | 37204 | const ip = &zcu.intern_pool; |
| 37260 | | assert(slice_val.typeOf(zcu).isSlice(zcu)); |
| 37205 | const slice_ty = slice_val.typeOf(zcu); |
| 37206 | assert(slice_ty.zigTypeTag(zcu) == .pointer); |
| 37207 | switch (slice_ty.ptrInfo(zcu).flags.size) { |
| 37208 | .slice => {}, |
| 37209 | .one => return sema.pointerDeref(block, src, slice_val, slice_ty), |
| 37210 | .many, .c => unreachable, |
| 37211 | } |
| 37261 | 37212 | const slice = switch (ip.indexToKey(slice_val.toIntern())) { |
| 37262 | 37213 | .undef => return sema.failWithUseOfUndef(block, src, null), |
| 37263 | 37214 | .slice => |slice| slice, |
| ... | ... | @@ -37393,7 +37344,7 @@ pub fn resolveDeclaredEnum( |
| 37393 | 37344 | .inlining = null, |
| 37394 | 37345 | .comptime_reason = .{ .reason = .{ |
| 37395 | 37346 | .src = src, |
| 37396 | | .r = .{ .simple = .enum_fields }, |
| 37347 | .r = .{ .simple = .enum_field_values }, |
| 37397 | 37348 | } }, |
| 37398 | 37349 | .src_base_inst = tracked_inst, |
| 37399 | 37350 | .type_name_ctx = type_name, |