| ... | ... | @@ -2394,11 +2394,15 @@ pub const Type = extern union { |
| 2394 | 2394 | _ = try sk.sema.typeRequiresComptime(sk.block, sk.src, ty); |
| 2395 | 2395 | } |
| 2396 | 2396 | switch (struct_obj.requires_comptime) { |
| 2397 | | .wip => unreachable, |
| 2398 | 2397 | .yes => return false, |
| 2399 | | .no => if (struct_obj.known_non_opv) return true, |
| 2398 | .wip, .no => if (struct_obj.known_non_opv) return true, |
| 2400 | 2399 | .unknown => {}, |
| 2401 | 2400 | } |
| 2401 | if (struct_obj.status == .field_types_wip) { |
| 2402 | // In this case, we guess that hasRuntimeBits() for this type is true, |
| 2403 | // and then later if our guess was incorrect, we emit a compile error. |
| 2404 | return true; |
| 2405 | } |
| 2402 | 2406 | if (sema_kit) |sk| { |
| 2403 | 2407 | _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); |
| 2404 | 2408 | } |
| ... | ... | @@ -2735,6 +2739,12 @@ pub const Type = extern union { |
| 2735 | 2739 | val: Value, |
| 2736 | 2740 | }; |
| 2737 | 2741 | |
| 2742 | const AbiAlignmentAdvancedStrat = union(enum) { |
| 2743 | eager, |
| 2744 | lazy: Allocator, |
| 2745 | sema_kit: Module.WipAnalysis, |
| 2746 | }; |
| 2747 | |
| 2738 | 2748 | /// If you pass `eager` you will get back `scalar` and assert the type is resolved. |
| 2739 | 2749 | /// In this case there will be no error, guaranteed. |
| 2740 | 2750 | /// If you pass `lazy` you may get back `scalar` or `val`. |
| ... | ... | @@ -2744,11 +2754,7 @@ pub const Type = extern union { |
| 2744 | 2754 | pub fn abiAlignmentAdvanced( |
| 2745 | 2755 | ty: Type, |
| 2746 | 2756 | target: Target, |
| 2747 | | strat: union(enum) { |
| 2748 | | eager, |
| 2749 | | lazy: Allocator, |
| 2750 | | sema_kit: Module.WipAnalysis, |
| 2751 | | }, |
| 2757 | strat: AbiAlignmentAdvancedStrat, |
| 2752 | 2758 | ) Module.CompileError!AbiAlignmentAdvanced { |
| 2753 | 2759 | const sema_kit = switch (strat) { |
| 2754 | 2760 | .sema_kit => |sk| sk, |
| ... | ... | @@ -2928,21 +2934,24 @@ pub const Type = extern union { |
| 2928 | 2934 | }, |
| 2929 | 2935 | |
| 2930 | 2936 | .@"struct" => { |
| 2937 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 2931 | 2938 | if (sema_kit) |sk| { |
| 2932 | | try sk.sema.resolveTypeLayout(sk.block, sk.src, ty); |
| 2933 | | } |
| 2934 | | if (ty.castTag(.@"struct")) |payload| { |
| 2935 | | const struct_obj = payload.data; |
| 2936 | | if (!struct_obj.haveLayout()) switch (strat) { |
| 2937 | | .eager => unreachable, // struct layout not resolved |
| 2938 | | .sema_kit => unreachable, // handled above |
| 2939 | | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 2940 | | }; |
| 2941 | | if (struct_obj.layout == .Packed) { |
| 2942 | | var buf: Type.Payload.Bits = undefined; |
| 2943 | | const int_ty = struct_obj.packedIntegerType(target, &buf); |
| 2944 | | return AbiAlignmentAdvanced{ .scalar = int_ty.abiAlignment(target) }; |
| 2939 | if (struct_obj.status == .field_types_wip) { |
| 2940 | // We'll guess "pointer-aligned" and if we guess wrong, emit |
| 2941 | // a compile error later. |
| 2942 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }; |
| 2945 | 2943 | } |
| 2944 | _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); |
| 2945 | } |
| 2946 | if (!struct_obj.haveFieldTypes()) switch (strat) { |
| 2947 | .eager => unreachable, // struct layout not resolved |
| 2948 | .sema_kit => unreachable, // handled above |
| 2949 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 2950 | }; |
| 2951 | if (struct_obj.layout == .Packed) { |
| 2952 | var buf: Type.Payload.Bits = undefined; |
| 2953 | const int_ty = struct_obj.packedIntegerType(target, &buf); |
| 2954 | return AbiAlignmentAdvanced{ .scalar = int_ty.abiAlignment(target) }; |
| 2946 | 2955 | } |
| 2947 | 2956 | |
| 2948 | 2957 | const fields = ty.structFields(); |
| ... | ... | @@ -2950,7 +2959,16 @@ pub const Type = extern union { |
| 2950 | 2959 | for (fields.values()) |field| { |
| 2951 | 2960 | if (!(try field.ty.hasRuntimeBitsAdvanced(false, sema_kit))) continue; |
| 2952 | 2961 | |
| 2953 | | const field_align = field.normalAlignment(target); |
| 2962 | const field_align = if (field.abi_align != 0) |
| 2963 | field.abi_align |
| 2964 | else switch (try field.ty.abiAlignmentAdvanced(target, strat)) { |
| 2965 | .scalar => |a| a, |
| 2966 | .val => switch (strat) { |
| 2967 | .eager => unreachable, // struct layout not resolved |
| 2968 | .sema_kit => unreachable, // handled above |
| 2969 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 2970 | }, |
| 2971 | }; |
| 2954 | 2972 | big_align = @maximum(big_align, field_align); |
| 2955 | 2973 | } |
| 2956 | 2974 | return AbiAlignmentAdvanced{ .scalar = big_align }; |
| ... | ... | @@ -2980,24 +2998,14 @@ pub const Type = extern union { |
| 2980 | 2998 | const int_tag_ty = ty.intTagType(&buffer); |
| 2981 | 2999 | return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(target) }; |
| 2982 | 3000 | }, |
| 2983 | | .@"union" => switch (strat) { |
| 2984 | | .eager, .sema_kit => { |
| 2985 | | if (sema_kit) |sk| { |
| 2986 | | try sk.sema.resolveTypeLayout(sk.block, sk.src, ty); |
| 2987 | | } |
| 2988 | | // TODO pass `true` for have_tag when unions have a safety tag |
| 2989 | | return AbiAlignmentAdvanced{ .scalar = ty.castTag(.@"union").?.data.abiAlignment(target, false) }; |
| 2990 | | }, |
| 2991 | | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 3001 | .@"union" => { |
| 3002 | const union_obj = ty.castTag(.@"union").?.data; |
| 3003 | // TODO pass `true` for have_tag when unions have a safety tag |
| 3004 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, false); |
| 2992 | 3005 | }, |
| 2993 | | .union_tagged => switch (strat) { |
| 2994 | | .eager, .sema_kit => { |
| 2995 | | if (sema_kit) |sk| { |
| 2996 | | try sk.sema.resolveTypeLayout(sk.block, sk.src, ty); |
| 2997 | | } |
| 2998 | | return AbiAlignmentAdvanced{ .scalar = ty.castTag(.union_tagged).?.data.abiAlignment(target, true) }; |
| 2999 | | }, |
| 3000 | | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 3006 | .union_tagged => { |
| 3007 | const union_obj = ty.castTag(.union_tagged).?.data; |
| 3008 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, true); |
| 3001 | 3009 | }, |
| 3002 | 3010 | |
| 3003 | 3011 | .empty_struct, |
| ... | ... | @@ -3023,6 +3031,51 @@ pub const Type = extern union { |
| 3023 | 3031 | }; |
| 3024 | 3032 | } |
| 3025 | 3033 | |
| 3034 | pub fn abiAlignmentAdvancedUnion( |
| 3035 | ty: Type, |
| 3036 | target: Target, |
| 3037 | strat: AbiAlignmentAdvancedStrat, |
| 3038 | union_obj: *Module.Union, |
| 3039 | have_tag: bool, |
| 3040 | ) Module.CompileError!AbiAlignmentAdvanced { |
| 3041 | const sema_kit = switch (strat) { |
| 3042 | .sema_kit => |sk| sk, |
| 3043 | else => null, |
| 3044 | }; |
| 3045 | if (sema_kit) |sk| { |
| 3046 | if (union_obj.status == .field_types_wip) { |
| 3047 | // We'll guess "pointer-aligned" and if we guess wrong, emit |
| 3048 | // a compile error later. |
| 3049 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }; |
| 3050 | } |
| 3051 | _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); |
| 3052 | } |
| 3053 | if (!union_obj.haveFieldTypes()) switch (strat) { |
| 3054 | .eager => unreachable, // union layout not resolved |
| 3055 | .sema_kit => unreachable, // handled above |
| 3056 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 3057 | }; |
| 3058 | |
| 3059 | var max_align: u32 = 0; |
| 3060 | if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target); |
| 3061 | for (union_obj.fields.values()) |field| { |
| 3062 | if (!(try field.ty.hasRuntimeBitsAdvanced(false, sema_kit))) continue; |
| 3063 | |
| 3064 | const field_align = if (field.abi_align != 0) |
| 3065 | field.abi_align |
| 3066 | else switch (try field.ty.abiAlignmentAdvanced(target, strat)) { |
| 3067 | .scalar => |a| a, |
| 3068 | .val => switch (strat) { |
| 3069 | .eager => unreachable, // struct layout not resolved |
| 3070 | .sema_kit => unreachable, // handled above |
| 3071 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 3072 | }, |
| 3073 | }; |
| 3074 | max_align = @maximum(max_align, field_align); |
| 3075 | } |
| 3076 | return AbiAlignmentAdvanced{ .scalar = max_align }; |
| 3077 | } |
| 3078 | |
| 3026 | 3079 | /// Asserts the type has the ABI size already resolved. |
| 3027 | 3080 | /// Types that return false for hasRuntimeBits() return 0. |
| 3028 | 3081 | pub fn abiSize(self: Type, target: Target) u64 { |