authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-17 05:00:17-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-20 23:48:36-05:00
log7768d2024bfbb4aad143fb8a4143e324445bfd93
tree4e664cbecf7a49e2feabce10e7e92c5166ea91f9
parentd8fada6b6325e07015fddd68bb4c6369a66f23f3

CBE: use CType for type rendering


1 files changed, 287 insertions(+), 287 deletions(-)

src/codegen/c.zig+287-287
......@@ -1954,291 +1954,311 @@ pub const DeclGen = struct {
19541954 return name;
19551955 }
19561956
1957 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
1958 return dg.ctypes.indexToCType(idx);
1959 }
19571960 fn typeToCType(dg: *DeclGen, ty: Type) !CType {
19581961 return dg.ctypes.typeToCType(dg.gpa, ty, dg.module);
19591962 }
1960
1961 /// Renders a type as a single identifier, generating intermediate typedefs
1962 /// if necessary.
1963 ///
1964 /// This is guaranteed to be valid in both typedefs and declarations/definitions.
1965 ///
1966 /// There are three type formats in total that we support rendering:
1967 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
1968 /// |---------------------|-----------------|---------------------|
1969 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
1970 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
1971 /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" |
1972 ///
1973 fn renderType(
1963 fn typeToIndex(dg: *DeclGen, ty: Type) !CType.Index {
1964 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module);
1965 }
1966
1967 const CTypeFix = enum { prefix, suffix };
1968 const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });
1969 const CTypeRenderTrailing = enum {
1970 no_space,
1971 maybe_space,
1972
1973 pub fn format(
1974 self: @This(),
1975 comptime fmt: []const u8,
1976 _: std.fmt.FormatOptions,
1977 w: anytype,
1978 ) @TypeOf(w).Error!void {
1979 if (fmt.len != 0)
1980 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++
1981 @typeName(@This()) ++ "'");
1982 comptime assert(fmt.len == 0);
1983 switch (self) {
1984 .no_space => {},
1985 .maybe_space => try w.writeByte(' '),
1986 }
1987 }
1988 };
1989 fn renderTypePrefix(
19741990 dg: *DeclGen,
19751991 w: anytype,
1976 t: Type,
1977 kind: TypedefKind,
1978 ) error{ OutOfMemory, AnalysisFail }!void {
1979 _ = try dg.typeToCType(t);
1980
1981 const target = dg.module.getTarget();
1982
1983 switch (t.zigTypeTag()) {
1984 .Void => try w.writeAll("void"),
1985 .Bool => try w.writeAll("bool"),
1986 .NoReturn, .Float => {
1987 try w.writeAll("zig_");
1988 try t.print(w, dg.module);
1989 },
1990 .Int => {
1991 if (t.isNamedInt()) {
1992 try w.writeAll("zig_");
1993 try t.print(w, dg.module);
1994 } else {
1995 return renderTypeUnnamed(dg, w, t, kind);
1996 }
1997 },
1998 .ErrorSet => {
1999 return renderTypeUnnamed(dg, w, t, kind);
1992 idx: CType.Index,
1993 parent_fix: CTypeFix,
1994 qualifiers: CQualifiers,
1995 ) @TypeOf(w).Error!CTypeRenderTrailing {
1996 var trailing = CTypeRenderTrailing.maybe_space;
1997
1998 const cty = dg.indexToCType(idx);
1999 switch (cty.tag()) {
2000 .void,
2001 .char,
2002 .@"signed char",
2003 .short,
2004 .int,
2005 .long,
2006 .@"long long",
2007 ._Bool,
2008 .@"unsigned char",
2009 .@"unsigned short",
2010 .@"unsigned int",
2011 .@"unsigned long",
2012 .@"unsigned long long",
2013 .float,
2014 .double,
2015 .@"long double",
2016 .bool,
2017 .size_t,
2018 .ptrdiff_t,
2019 .zig_u8,
2020 .zig_i8,
2021 .zig_u16,
2022 .zig_i16,
2023 .zig_u32,
2024 .zig_i32,
2025 .zig_u64,
2026 .zig_i64,
2027 .zig_u128,
2028 .zig_i128,
2029 .zig_f16,
2030 .zig_f32,
2031 .zig_f64,
2032 .zig_f80,
2033 .zig_f128,
2034 => |tag| try w.writeAll(@tagName(tag)),
2035
2036 .pointer,
2037 .pointer_const,
2038 .pointer_volatile,
2039 .pointer_const_volatile,
2040 => |tag| {
2041 const child_idx = cty.cast(CType.Payload.Child).?.data;
2042 try w.print("{}*", .{try dg.renderTypePrefix(w, child_idx, .prefix, CQualifiers.init(.{
2043 .@"const" = switch (tag) {
2044 .pointer, .pointer_volatile => false,
2045 .pointer_const, .pointer_const_volatile => true,
2046 else => unreachable,
2047 },
2048 .@"volatile" = switch (tag) {
2049 .pointer, .pointer_const => false,
2050 .pointer_volatile, .pointer_const_volatile => true,
2051 else => unreachable,
2052 },
2053 }))});
2054 trailing = .no_space;
20002055 },
2001 .Pointer => {
2002 const ptr_info = t.ptrInfo().data;
2003 if (ptr_info.size == .Slice) {
2004 var slice_pl = Type.Payload.ElemType{
2005 .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice },
2006 .data = ptr_info.pointee_type,
2007 };
2008 const slice_ty = Type.initPayload(&slice_pl.base);
2009
2010 const name = dg.getTypedefName(slice_ty) orelse
2011 try dg.renderSliceTypedef(slice_ty);
20122056
2013 return w.writeAll(name);
2014 }
2015
2016 if (ptr_info.pointee_type.zigTypeTag() == .Fn) {
2017 const name = dg.getTypedefName(ptr_info.pointee_type) orelse
2018 try dg.renderPtrToFnTypedef(ptr_info.pointee_type);
2019
2020 return w.writeAll(name);
2057 .array,
2058 .vector,
2059 => {
2060 const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type;
2061 const child_trailing = try dg.renderTypePrefix(w, child_idx, .suffix, qualifiers);
2062 switch (parent_fix) {
2063 .prefix => {
2064 try w.print("{}(", .{child_trailing});
2065 return .no_space;
2066 },
2067 .suffix => return child_trailing,
20212068 }
2022
2023 if (ptr_info.host_size != 0) {
2024 var host_pl = Type.Payload.Bits{
2025 .base = .{ .tag = .int_unsigned },
2026 .data = ptr_info.host_size * 8,
2027 };
2028 const host_ty = Type.initPayload(&host_pl.base);
2029
2030 try dg.renderType(w, host_ty, .Forward);
2031 } else if (t.isCPtr() and ptr_info.pointee_type.eql(Type.u8, dg.module) and
2032 (dg.decl.val.tag() == .extern_fn or
2033 std.mem.eql(u8, std.mem.span(dg.decl.name), "main")))
2034 {
2035 // This is a hack, since the c compiler expects a lot of external
2036 // library functions to have char pointers in their signatures, but
2037 // u8 and i8 produce unsigned char and signed char respectively,
2038 // which in C are (not very usefully) different than char.
2039 try w.writeAll("char");
2040 } else try dg.renderType(w, switch (ptr_info.pointee_type.tag()) {
2041 .anyopaque => Type.void,
2042 else => ptr_info.pointee_type,
2043 }, .Forward);
2044 if (t.isConstPtr()) try w.writeAll(" const");
2045 if (t.isVolatilePtr()) try w.writeAll(" volatile");
2046 return w.writeAll(" *");
2047 },
2048 .Array, .Vector => {
2049 var array_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{
2050 .len = t.arrayLenIncludingSentinel(),
2051 .elem_type = t.childType(),
2052 } };
2053 const array_ty = Type.initPayload(&array_pl.base);
2054
2055 const name = dg.getTypedefName(array_ty) orelse
2056 try dg.renderArrayTypedef(array_ty);
2057
2058 return w.writeAll(name);
20592069 },
2060 .Optional => {
2061 var opt_buf: Type.Payload.ElemType = undefined;
2062 const child_ty = t.optionalChild(&opt_buf);
2063
2064 if (!child_ty.hasRuntimeBitsIgnoreComptime())
2065 return dg.renderType(w, Type.bool, kind);
2066
2067 if (t.optionalReprIsPayload())
2068 return dg.renderType(w, child_ty, kind);
20692070
2070 switch (kind) {
2071 .Complete => {
2072 const name = dg.getTypedefName(t) orelse
2073 try dg.renderOptionalTypedef(t);
2074
2075 try w.writeAll(name);
2076 },
2077 .Forward => {
2078 var ptr_pl = Type.Payload.ElemType{
2079 .base = .{ .tag = .single_const_pointer },
2080 .data = t,
2081 };
2082 const ptr_ty = Type.initPayload(&ptr_pl.base);
2083
2084 const name = dg.getTypedefName(ptr_ty) orelse
2085 try dg.renderFwdTypedef(ptr_ty);
2071 .fwd_struct,
2072 .fwd_union,
2073 .anon_struct,
2074 .packed_anon_struct,
2075 => |tag| try w.print("{s} {}__{d}", .{
2076 switch (tag) {
2077 .fwd_struct,
2078 .anon_struct,
2079 .packed_anon_struct,
2080 => "struct",
2081 .fwd_union => "union",
2082 else => unreachable,
2083 },
2084 fmtIdent(switch (tag) {
2085 .fwd_struct,
2086 .fwd_union,
2087 => mem.span(dg.module.declPtr(cty.cast(CType.Payload.FwdDecl).?.data).name),
2088 .anon_struct,
2089 .packed_anon_struct,
2090 => "anon",
2091 else => unreachable,
2092 }),
2093 idx,
2094 }),
20862095
2087 try w.writeAll(name);
2096 .@"struct",
2097 .packed_struct,
2098 .@"union",
2099 .packed_union,
2100 => return dg.renderTypePrefix(
2101 w,
2102 cty.cast(CType.Payload.Aggregate).?.data.fwd_decl,
2103 parent_fix,
2104 qualifiers,
2105 ),
2106
2107 .function,
2108 .varargs_function,
2109 => {
2110 const child_trailing = try dg.renderTypePrefix(
2111 w,
2112 cty.cast(CType.Payload.Function).?.data.return_type,
2113 .suffix,
2114 CQualifiers.initEmpty(),
2115 );
2116 switch (parent_fix) {
2117 .prefix => {
2118 try w.print("{}(", .{child_trailing});
2119 return .no_space;
20882120 },
2121 .suffix => return child_trailing,
20892122 }
20902123 },
2091 .ErrorUnion => {
2092 const payload_ty = t.errorUnionPayload();
2124 }
20932125
2094 if (!payload_ty.hasRuntimeBitsIgnoreComptime())
2095 return dg.renderType(w, Type.anyerror, kind);
2126 var qualifier_it = qualifiers.iterator();
2127 while (qualifier_it.next()) |qualifier| {
2128 try w.print("{}{s}", .{ trailing, @tagName(qualifier) });
2129 trailing = .maybe_space;
2130 }
20962131
2097 var error_union_pl = Type.Payload.ErrorUnion{
2098 .data = .{ .error_set = Type.anyerror, .payload = payload_ty },
2099 };
2100 const error_union_ty = Type.initPayload(&error_union_pl.base);
2132 return trailing;
2133 }
2134 fn renderTypeSuffix(
2135 dg: *DeclGen,
2136 w: anytype,
2137 idx: CType.Index,
2138 parent_fix: CTypeFix,
2139 ) @TypeOf(w).Error!void {
2140 const cty = dg.indexToCType(idx);
2141 switch (cty.tag()) {
2142 .void,
2143 .char,
2144 .@"signed char",
2145 .short,
2146 .int,
2147 .long,
2148 .@"long long",
2149 ._Bool,
2150 .@"unsigned char",
2151 .@"unsigned short",
2152 .@"unsigned int",
2153 .@"unsigned long",
2154 .@"unsigned long long",
2155 .float,
2156 .double,
2157 .@"long double",
2158 .bool,
2159 .size_t,
2160 .ptrdiff_t,
2161 .zig_u8,
2162 .zig_i8,
2163 .zig_u16,
2164 .zig_i16,
2165 .zig_u32,
2166 .zig_i32,
2167 .zig_u64,
2168 .zig_i64,
2169 .zig_u128,
2170 .zig_i128,
2171 .zig_f16,
2172 .zig_f32,
2173 .zig_f64,
2174 .zig_f80,
2175 .zig_f128,
2176 => {},
2177
2178 .pointer,
2179 .pointer_const,
2180 .pointer_volatile,
2181 .pointer_const_volatile,
2182 => try dg.renderTypeSuffix(w, cty.cast(CType.Payload.Child).?.data, .prefix),
2183
2184 .array,
2185 .vector,
2186 => {
2187 switch (parent_fix) {
2188 .prefix => try w.writeByte(')'),
2189 .suffix => {},
2190 }
21012191
2102 switch (kind) {
2103 .Complete => {
2104 const name = dg.getTypedefName(error_union_ty) orelse
2105 try dg.renderErrorUnionTypedef(error_union_ty);
2192 try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len});
2193 try dg.renderTypeSuffix(w, cty.cast(CType.Payload.Sequence).?.data.elem_type, .suffix);
2194 },
21062195
2107 try w.writeAll(name);
2108 },
2109 .Forward => {
2110 var ptr_pl = Type.Payload.ElemType{
2111 .base = .{ .tag = .single_const_pointer },
2112 .data = error_union_ty,
2113 };
2114 const ptr_ty = Type.initPayload(&ptr_pl.base);
2196 .fwd_struct,
2197 .fwd_union,
2198 .anon_struct,
2199 .packed_anon_struct,
2200 .@"struct",
2201 .@"union",
2202 .packed_struct,
2203 .packed_union,
2204 => {},
2205
2206 .function,
2207 .varargs_function,
2208 => |tag| {
2209 switch (parent_fix) {
2210 .prefix => try w.writeByte(')'),
2211 .suffix => {},
2212 }
21152213
2116 const name = dg.getTypedefName(ptr_ty) orelse
2117 try dg.renderFwdTypedef(ptr_ty);
2214 const data = cty.cast(CType.Payload.Function).?.data;
21182215
2119 try w.writeAll(name);
2120 },
2216 try w.writeByte('(');
2217 var need_comma = false;
2218 for (data.param_types) |param_type| {
2219 if (need_comma) try w.writeAll(", ");
2220 need_comma = true;
2221 _ = try dg.renderTypePrefix(w, param_type, .suffix, CQualifiers.initEmpty());
2222 try dg.renderTypeSuffix(w, param_type, .suffix);
21212223 }
2122 },
2123 .Struct, .Union => |tag| if (t.containerLayout() == .Packed) {
2124 if (t.castTag(.@"struct")) |struct_obj| {
2125 try dg.renderType(w, struct_obj.data.backing_int_ty, kind);
2126 } else {
2127 var buf: Type.Payload.Bits = .{
2128 .base = .{ .tag = .int_unsigned },
2129 .data = @intCast(u16, t.bitSize(target)),
2130 };
2131 try dg.renderType(w, Type.initPayload(&buf.base), kind);
2224 switch (tag) {
2225 .function => {},
2226 .varargs_function => {
2227 if (need_comma) try w.writeAll(", ");
2228 need_comma = true;
2229 try w.writeAll("...");
2230 },
2231 else => unreachable,
21322232 }
2133 } else if (t.isSimpleTupleOrAnonStruct()) {
2134 const ExpectedContents = struct { types: [8]Type, values: [8]Value };
2135 var stack align(@alignOf(ExpectedContents)) =
2136 std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);
2137 const allocator = stack.get();
2138
2139 var tuple_storage = std.MultiArrayList(struct { type: Type, value: Value }){};
2140 defer tuple_storage.deinit(allocator);
2141 try tuple_storage.ensureTotalCapacity(allocator, t.structFieldCount());
2142
2143 const fields = t.tupleFields();
2144 for (fields.values, 0..) |value, index|
2145 if (value.tag() == .unreachable_value)
2146 tuple_storage.appendAssumeCapacity(.{
2147 .type = fields.types[index],
2148 .value = value,
2149 });
2150
2151 const tuple_slice = tuple_storage.slice();
2152 var tuple_pl = Type.Payload.Tuple{ .data = .{
2153 .types = tuple_slice.items(.type),
2154 .values = tuple_slice.items(.value),
2155 } };
2156 const tuple_ty = Type.initPayload(&tuple_pl.base);
2157
2158 const name = dg.getTypedefName(tuple_ty) orelse
2159 try dg.renderTupleTypedef(tuple_ty);
2160
2161 try w.writeAll(name);
2162 } else switch (kind) {
2163 .Complete => {
2164 const name = dg.getTypedefName(t) orelse switch (tag) {
2165 .Struct => try dg.renderStructTypedef(t),
2166 .Union => try dg.renderUnionTypedef(t),
2167 else => unreachable,
2168 };
2169
2170 try w.writeAll(name);
2171 },
2172 .Forward => {
2173 var ptr_pl = Type.Payload.ElemType{
2174 .base = .{ .tag = .single_const_pointer },
2175 .data = t,
2176 };
2177 const ptr_ty = Type.initPayload(&ptr_pl.base);
2178
2179 const name = dg.getTypedefName(ptr_ty) orelse
2180 try dg.renderFwdTypedef(ptr_ty);
2181
2182 try w.writeAll(name);
2183 },
2184 },
2185 .Enum => {
2186 // For enums, we simply use the integer tag type.
2187 var int_tag_buf: Type.Payload.Bits = undefined;
2188 const int_tag_ty = t.intTagType(&int_tag_buf);
2233 if (!need_comma) try w.writeAll("void");
2234 try w.writeByte(')');
21892235
2190 try dg.renderType(w, int_tag_ty, kind);
2236 try dg.renderTypeSuffix(w, data.return_type, .suffix);
21912237 },
2192 .Opaque => switch (t.tag()) {
2193 .@"opaque" => {
2194 const name = dg.getTypedefName(t) orelse
2195 try dg.renderOpaqueTypedef(t);
2196
2197 try w.writeAll(name);
2198 },
2199 else => unreachable,
2200 },
2201
2202 .Frame,
2203 .AnyFrame,
2204 => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{
2205 @tagName(tag),
2206 }),
2207
2208 .Fn => unreachable, // This is a function body, not a function pointer.
2209
2210 .Null,
2211 .Undefined,
2212 .EnumLiteral,
2213 .ComptimeFloat,
2214 .ComptimeInt,
2215 .Type,
2216 => unreachable, // must be const or comptime
22172238 }
22182239 }
22192240
2220 fn renderTypeUnnamed(
2241 /// Renders a type as a single identifier, generating intermediate typedefs
2242 /// if necessary.
2243 ///
2244 /// This is guaranteed to be valid in both typedefs and declarations/definitions.
2245 ///
2246 /// There are three type formats in total that we support rendering:
2247 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
2248 /// |---------------------|-----------------|---------------------|
2249 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
2250 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
2251 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
2252 ///
2253 fn renderType(
22212254 dg: *DeclGen,
22222255 w: anytype,
22232256 t: Type,
2224 kind: TypedefKind,
2257 _: TypedefKind,
22252258 ) error{ OutOfMemory, AnalysisFail }!void {
2226 const target = dg.module.getTarget();
2227 const int_info = t.intInfo(target);
2228 if (toCIntBits(int_info.bits)) |c_bits|
2229 return w.print("zig_{c}{d}", .{ signAbbrev(int_info.signedness), c_bits })
2230 else if (loweredArrayInfo(t, target)) |array_info| {
2231 assert(array_info.sentinel == null);
2232 var array_pl = Type.Payload.Array{
2233 .base = .{ .tag = .array },
2234 .data = .{ .len = array_info.len, .elem_type = array_info.elem_type },
2235 };
2236 const array_ty = Type.initPayload(&array_pl.base);
2237
2238 return dg.renderType(w, array_ty, kind);
2239 } else return dg.fail("C backend: Unable to lower unnamed integer type {}", .{
2240 t.fmt(dg.module),
2241 });
2259 const idx = try dg.typeToIndex(t);
2260 _ = try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.initEmpty());
2261 try dg.renderTypeSuffix(w, idx, .suffix);
22422262 }
22432263
22442264 const IntCastContext = union(enum) {
......@@ -2348,10 +2368,10 @@ pub const DeclGen = struct {
23482368 /// |---------------------|-----------------|---------------------|
23492369 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
23502370 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
2351 /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" |
2371 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
23522372 ///
23532373 fn renderTypecast(dg: *DeclGen, w: anytype, ty: Type) error{ OutOfMemory, AnalysisFail }!void {
2354 return renderTypeAndName(dg, w, ty, .{ .bytes = "" }, .Mut, 0, .Complete);
2374 try dg.renderType(w, ty, undefined);
23552375 }
23562376
23572377 /// Renders a type and name in field declaration/definition format.
......@@ -2361,7 +2381,7 @@ pub const DeclGen = struct {
23612381 /// |---------------------|-----------------|---------------------|
23622382 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
23632383 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
2364 /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" |
2384 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
23652385 ///
23662386 fn renderTypeAndName(
23672387 dg: *DeclGen,
......@@ -2370,46 +2390,26 @@ pub const DeclGen = struct {
23702390 name: CValue,
23712391 mutability: Mutability,
23722392 alignment: u32,
2373 kind: TypedefKind,
2393 _: TypedefKind,
23742394 ) error{ OutOfMemory, AnalysisFail }!void {
2375 var suffix = std.ArrayList(u8).init(dg.gpa);
2376 defer suffix.deinit();
2377 const suffix_writer = suffix.writer();
2378
2379 // Any top-level array types are rendered here as a suffix, which
2380 // avoids creating typedefs for every array type
2381 const target = dg.module.getTarget();
2382 var render_ty = ty;
2383 var depth: u32 = 0;
2384 while (loweredArrayInfo(render_ty, target)) |array_info| {
2385 const c_len = array_info.len + @boolToInt(array_info.sentinel != null);
2386 var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len };
2387 const c_len_val = Value.initPayload(&c_len_pl.base);
2388
2389 try suffix_writer.writeByte('[');
2390 if (mutability == .ConstArgument and depth == 0) try suffix_writer.writeAll("zig_const_arr ");
2391 try suffix.writer().print("{}]", .{try dg.fmtIntLiteral(Type.usize, c_len_val)});
2392 render_ty = array_info.elem_type;
2393 depth += 1;
2394 }
2395
23962395 if (alignment != 0) {
2397 const abi_alignment = ty.abiAlignment(target);
2396 const abi_alignment = ty.abiAlignment(dg.module.getTarget());
23982397 if (alignment < abi_alignment) {
23992398 try w.print("zig_under_align({}) ", .{alignment});
24002399 } else if (alignment > abi_alignment) {
24012400 try w.print("zig_align({}) ", .{alignment});
24022401 }
24032402 }
2404 try dg.renderType(w, render_ty, kind);
24052403
2406 const const_prefix = switch (mutability) {
2407 .Const, .ConstArgument => "const ",
2408 .Mut => "",
2409 };
2410 try w.print(" {s}", .{const_prefix});
2404 const idx = try dg.typeToIndex(ty);
2405 try w.print("{}", .{try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.init(.{
2406 .@"const" = switch (mutability) {
2407 .Const, .ConstArgument => true,
2408 .Mut => false,
2409 },
2410 }))});
24112411 try dg.writeCValue(w, name);
2412 try w.writeAll(suffix.items);
2412 try dg.renderTypeSuffix(w, idx, .suffix);
24132413 }
24142414
24152415 fn renderTagNameFn(dg: *DeclGen, enum_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {