| ... | ... | @@ -1954,291 +1954,311 @@ pub const DeclGen = struct { |
| 1954 | 1954 | return name; |
| 1955 | 1955 | } |
| 1956 | 1956 | |
| 1957 | fn indexToCType(dg: *DeclGen, idx: CType.Index) CType { |
| 1958 | return dg.ctypes.indexToCType(idx); |
| 1959 | } |
| 1957 | 1960 | fn typeToCType(dg: *DeclGen, ty: Type) !CType { |
| 1958 | 1961 | return dg.ctypes.typeToCType(dg.gpa, ty, dg.module); |
| 1959 | 1962 | } |
| 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( |
| 1974 | 1990 | dg: *DeclGen, |
| 1975 | 1991 | 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; |
| 2000 | 2055 | }, |
| 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); |
| 2012 | 2056 | |
| 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, |
| 2021 | 2068 | } |
| 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); |
| 2059 | 2069 | }, |
| 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); |
| 2069 | 2070 | |
| 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 | }), |
| 2086 | 2095 | |
| 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; |
| 2088 | 2120 | }, |
| 2121 | .suffix => return child_trailing, |
| 2089 | 2122 | } |
| 2090 | 2123 | }, |
| 2091 | | .ErrorUnion => { |
| 2092 | | const payload_ty = t.errorUnionPayload(); |
| 2124 | } |
| 2093 | 2125 | |
| 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 | } |
| 2096 | 2131 | |
| 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 | } |
| 2101 | 2191 | |
| 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 | }, |
| 2106 | 2195 | |
| 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 | } |
| 2115 | 2213 | |
| 2116 | | const name = dg.getTypedefName(ptr_ty) orelse |
| 2117 | | try dg.renderFwdTypedef(ptr_ty); |
| 2214 | const data = cty.cast(CType.Payload.Function).?.data; |
| 2118 | 2215 | |
| 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); |
| 2121 | 2223 | } |
| 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, |
| 2132 | 2232 | } |
| 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(')'); |
| 2189 | 2235 | |
| 2190 | | try dg.renderType(w, int_tag_ty, kind); |
| 2236 | try dg.renderTypeSuffix(w, data.return_type, .suffix); |
| 2191 | 2237 | }, |
| 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 |
| 2217 | 2238 | } |
| 2218 | 2239 | } |
| 2219 | 2240 | |
| 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( |
| 2221 | 2254 | dg: *DeclGen, |
| 2222 | 2255 | w: anytype, |
| 2223 | 2256 | t: Type, |
| 2224 | | kind: TypedefKind, |
| 2257 | _: TypedefKind, |
| 2225 | 2258 | ) 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); |
| 2242 | 2262 | } |
| 2243 | 2263 | |
| 2244 | 2264 | const IntCastContext = union(enum) { |
| ... | ... | @@ -2348,10 +2368,10 @@ pub const DeclGen = struct { |
| 2348 | 2368 | /// |---------------------|-----------------|---------------------| |
| 2349 | 2369 | /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" | |
| 2350 | 2370 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | |
| 2351 | | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | |
| 2371 | /// | `renderType` | "uint8_t *" | "uint8_t *[10]" | |
| 2352 | 2372 | /// |
| 2353 | 2373 | 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); |
| 2355 | 2375 | } |
| 2356 | 2376 | |
| 2357 | 2377 | /// Renders a type and name in field declaration/definition format. |
| ... | ... | @@ -2361,7 +2381,7 @@ pub const DeclGen = struct { |
| 2361 | 2381 | /// |---------------------|-----------------|---------------------| |
| 2362 | 2382 | /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" | |
| 2363 | 2383 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | |
| 2364 | | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | |
| 2384 | /// | `renderType` | "uint8_t *" | "uint8_t *[10]" | |
| 2365 | 2385 | /// |
| 2366 | 2386 | fn renderTypeAndName( |
| 2367 | 2387 | dg: *DeclGen, |
| ... | ... | @@ -2370,46 +2390,26 @@ pub const DeclGen = struct { |
| 2370 | 2390 | name: CValue, |
| 2371 | 2391 | mutability: Mutability, |
| 2372 | 2392 | alignment: u32, |
| 2373 | | kind: TypedefKind, |
| 2393 | _: TypedefKind, |
| 2374 | 2394 | ) 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 | | |
| 2396 | 2395 | if (alignment != 0) { |
| 2397 | | const abi_alignment = ty.abiAlignment(target); |
| 2396 | const abi_alignment = ty.abiAlignment(dg.module.getTarget()); |
| 2398 | 2397 | if (alignment < abi_alignment) { |
| 2399 | 2398 | try w.print("zig_under_align({}) ", .{alignment}); |
| 2400 | 2399 | } else if (alignment > abi_alignment) { |
| 2401 | 2400 | try w.print("zig_align({}) ", .{alignment}); |
| 2402 | 2401 | } |
| 2403 | 2402 | } |
| 2404 | | try dg.renderType(w, render_ty, kind); |
| 2405 | 2403 | |
| 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 | }))}); |
| 2411 | 2411 | try dg.writeCValue(w, name); |
| 2412 | | try w.writeAll(suffix.items); |
| 2412 | try dg.renderTypeSuffix(w, idx, .suffix); |
| 2413 | 2413 | } |
| 2414 | 2414 | |
| 2415 | 2415 | fn renderTagNameFn(dg: *DeclGen, enum_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |