| ... | @@ -1954,291 +1954,311 @@ pub const DeclGen = struct { | ... | @@ -1954,291 +1954,311 @@ pub const DeclGen = struct { |
| 1954 | return name; | 1954 | return name; |
| 1955 | } | 1955 | } |
| 1956 | | 1956 | |
| | 1957 | fn indexToCType(dg: *DeclGen, idx: CType.Index) CType { |
| | 1958 | return dg.ctypes.indexToCType(idx); |
| | 1959 | } |
| 1957 | fn typeToCType(dg: *DeclGen, ty: Type) !CType { | 1960 | fn typeToCType(dg: *DeclGen, ty: Type) !CType { |
| 1958 | return dg.ctypes.typeToCType(dg.gpa, ty, dg.module); | 1961 | return dg.ctypes.typeToCType(dg.gpa, ty, dg.module); |
| 1959 | } | 1962 | } |
| 1960 | | 1963 | fn typeToIndex(dg: *DeclGen, ty: Type) !CType.Index { |
| 1961 | /// Renders a type as a single identifier, generating intermediate typedefs | 1964 | return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module); |
| 1962 | /// if necessary. | 1965 | } |
| 1963 | /// | 1966 | |
| 1964 | /// This is guaranteed to be valid in both typedefs and declarations/definitions. | 1967 | const CTypeFix = enum { prefix, suffix }; |
| 1965 | /// | 1968 | const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict }); |
| 1966 | /// There are three type formats in total that we support rendering: | 1969 | const CTypeRenderTrailing = enum { |
| 1967 | /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) | | 1970 | no_space, |
| 1968 | /// |---------------------|-----------------|---------------------| | 1971 | maybe_space, |
| 1969 | /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" | | 1972 | |
| 1970 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | | 1973 | pub fn format( |
| 1971 | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | | 1974 | self: @This(), |
| 1972 | /// | 1975 | comptime fmt: []const u8, |
| 1973 | fn renderType( | 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 | dg: *DeclGen, | 1990 | dg: *DeclGen, |
| 1975 | w: anytype, | 1991 | w: anytype, |
| 1976 | t: Type, | 1992 | idx: CType.Index, |
| 1977 | kind: TypedefKind, | 1993 | parent_fix: CTypeFix, |
| 1978 | ) error{ OutOfMemory, AnalysisFail }!void { | 1994 | qualifiers: CQualifiers, |
| 1979 | _ = try dg.typeToCType(t); | 1995 | ) @TypeOf(w).Error!CTypeRenderTrailing { |
| 1980 | | 1996 | var trailing = CTypeRenderTrailing.maybe_space; |
| 1981 | const target = dg.module.getTarget(); | 1997 | |
| 1982 | | 1998 | const cty = dg.indexToCType(idx); |
| 1983 | switch (t.zigTypeTag()) { | 1999 | switch (cty.tag()) { |
| 1984 | .Void => try w.writeAll("void"), | 2000 | .void, |
| 1985 | .Bool => try w.writeAll("bool"), | 2001 | .char, |
| 1986 | .NoReturn, .Float => { | 2002 | .@"signed char", |
| 1987 | try w.writeAll("zig_"); | 2003 | .short, |
| 1988 | try t.print(w, dg.module); | 2004 | .int, |
| 1989 | }, | 2005 | .long, |
| 1990 | .Int => { | 2006 | .@"long long", |
| 1991 | if (t.isNamedInt()) { | 2007 | ._Bool, |
| 1992 | try w.writeAll("zig_"); | 2008 | .@"unsigned char", |
| 1993 | try t.print(w, dg.module); | 2009 | .@"unsigned short", |
| 1994 | } else { | 2010 | .@"unsigned int", |
| 1995 | return renderTypeUnnamed(dg, w, t, kind); | 2011 | .@"unsigned long", |
| 1996 | } | 2012 | .@"unsigned long long", |
| 1997 | }, | 2013 | .float, |
| 1998 | .ErrorSet => { | 2014 | .double, |
| 1999 | return renderTypeUnnamed(dg, w, t, kind); | 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); | 2057 | .array, |
| 2014 | } | 2058 | .vector, |
| 2015 | | 2059 | => { |
| 2016 | if (ptr_info.pointee_type.zigTypeTag() == .Fn) { | 2060 | const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type; |
| 2017 | const name = dg.getTypedefName(ptr_info.pointee_type) orelse | 2061 | const child_trailing = try dg.renderTypePrefix(w, child_idx, .suffix, qualifiers); |
| 2018 | try dg.renderPtrToFnTypedef(ptr_info.pointee_type); | 2062 | switch (parent_fix) { |
| 2019 | | 2063 | .prefix => { |
| 2020 | return w.writeAll(name); | 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 | .fwd_struct, |
| 2071 | .Complete => { | 2072 | .fwd_union, |
| 2072 | const name = dg.getTypedefName(t) orelse | 2073 | .anon_struct, |
| 2073 | try dg.renderOptionalTypedef(t); | 2074 | .packed_anon_struct, |
| 2074 | | 2075 | => |tag| try w.print("{s} {}__{d}", .{ |
| 2075 | try w.writeAll(name); | 2076 | switch (tag) { |
| 2076 | }, | 2077 | .fwd_struct, |
| 2077 | .Forward => { | 2078 | .anon_struct, |
| 2078 | var ptr_pl = Type.Payload.ElemType{ | 2079 | .packed_anon_struct, |
| 2079 | .base = .{ .tag = .single_const_pointer }, | 2080 | => "struct", |
| 2080 | .data = t, | 2081 | .fwd_union => "union", |
| 2081 | }; | 2082 | else => unreachable, |
| 2082 | const ptr_ty = Type.initPayload(&ptr_pl.base); | 2083 | }, |
| 2083 | | 2084 | fmtIdent(switch (tag) { |
| 2084 | const name = dg.getTypedefName(ptr_ty) orelse | 2085 | .fwd_struct, |
| 2085 | try dg.renderFwdTypedef(ptr_ty); | 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 => { | 2124 | } |
| 2092 | const payload_ty = t.errorUnionPayload(); | | |
| 2093 | | 2125 | |
| 2094 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) | 2126 | var qualifier_it = qualifiers.iterator(); |
| 2095 | return dg.renderType(w, Type.anyerror, kind); | 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{ | 2132 | return trailing; |
| 2098 | .data = .{ .error_set = Type.anyerror, .payload = payload_ty }, | 2133 | } |
| 2099 | }; | 2134 | fn renderTypeSuffix( |
| 2100 | const error_union_ty = Type.initPayload(&error_union_pl.base); | 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) { | 2192 | try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len}); |
| 2103 | .Complete => { | 2193 | try dg.renderTypeSuffix(w, cty.cast(CType.Payload.Sequence).?.data.elem_type, .suffix); |
| 2104 | const name = dg.getTypedefName(error_union_ty) orelse | 2194 | }, |
| 2105 | try dg.renderErrorUnionTypedef(error_union_ty); | | |
| 2106 | | 2195 | |
| 2107 | try w.writeAll(name); | 2196 | .fwd_struct, |
| 2108 | }, | 2197 | .fwd_union, |
| 2109 | .Forward => { | 2198 | .anon_struct, |
| 2110 | var ptr_pl = Type.Payload.ElemType{ | 2199 | .packed_anon_struct, |
| 2111 | .base = .{ .tag = .single_const_pointer }, | 2200 | .@"struct", |
| 2112 | .data = error_union_ty, | 2201 | .@"union", |
| 2113 | }; | 2202 | .packed_struct, |
| 2114 | const ptr_ty = Type.initPayload(&ptr_pl.base); | 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 | 2214 | const data = cty.cast(CType.Payload.Function).?.data; |
| 2117 | try dg.renderFwdTypedef(ptr_ty); | | |
| 2118 | | 2215 | |
| 2119 | try w.writeAll(name); | 2216 | try w.writeByte('('); |
| 2120 | }, | 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 | }, | 2224 | switch (tag) { |
| 2123 | .Struct, .Union => |tag| if (t.containerLayout() == .Packed) { | 2225 | .function => {}, |
| 2124 | if (t.castTag(.@"struct")) |struct_obj| { | 2226 | .varargs_function => { |
| 2125 | try dg.renderType(w, struct_obj.data.backing_int_ty, kind); | 2227 | if (need_comma) try w.writeAll(", "); |
| 2126 | } else { | 2228 | need_comma = true; |
| 2127 | var buf: Type.Payload.Bits = .{ | 2229 | try w.writeAll("..."); |
| 2128 | .base = .{ .tag = .int_unsigned }, | 2230 | }, |
| 2129 | .data = @intCast(u16, t.bitSize(target)), | 2231 | else => unreachable, |
| 2130 | }; | | |
| 2131 | try dg.renderType(w, Type.initPayload(&buf.base), kind); | | |
| 2132 | } | 2232 | } |
| 2133 | } else if (t.isSimpleTupleOrAnonStruct()) { | 2233 | if (!need_comma) try w.writeAll("void"); |
| 2134 | const ExpectedContents = struct { types: [8]Type, values: [8]Value }; | 2234 | try w.writeByte(')'); |
| 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); | | |
| 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 | dg: *DeclGen, | 2254 | dg: *DeclGen, |
| 2222 | w: anytype, | 2255 | w: anytype, |
| 2223 | t: Type, | 2256 | t: Type, |
| 2224 | kind: TypedefKind, | 2257 | _: TypedefKind, |
| 2225 | ) error{ OutOfMemory, AnalysisFail }!void { | 2258 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 2226 | const target = dg.module.getTarget(); | 2259 | const idx = try dg.typeToIndex(t); |
| 2227 | const int_info = t.intInfo(target); | 2260 | _ = try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.initEmpty()); |
| 2228 | if (toCIntBits(int_info.bits)) |c_bits| | 2261 | try dg.renderTypeSuffix(w, idx, .suffix); |
| 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 | }); | | |
| 2242 | } | 2262 | } |
| 2243 | | 2263 | |
| 2244 | const IntCastContext = union(enum) { | 2264 | const IntCastContext = union(enum) { |
| ... | @@ -2348,10 +2368,10 @@ pub const DeclGen = struct { | ... | @@ -2348,10 +2368,10 @@ pub const DeclGen = struct { |
| 2348 | /// |---------------------|-----------------|---------------------| | 2368 | /// |---------------------|-----------------|---------------------| |
| 2349 | /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" | | 2369 | /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" | |
| 2350 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | | 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 | fn renderTypecast(dg: *DeclGen, w: anytype, ty: Type) error{ OutOfMemory, AnalysisFail }!void { | 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 | /// Renders a type and name in field declaration/definition format. | 2377 | /// Renders a type and name in field declaration/definition format. |
| ... | @@ -2361,7 +2381,7 @@ pub const DeclGen = struct { | ... | @@ -2361,7 +2381,7 @@ pub const DeclGen = struct { |
| 2361 | /// |---------------------|-----------------|---------------------| | 2381 | /// |---------------------|-----------------|---------------------| |
| 2362 | /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" | | 2382 | /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" | |
| 2363 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | | 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 | fn renderTypeAndName( | 2386 | fn renderTypeAndName( |
| 2367 | dg: *DeclGen, | 2387 | dg: *DeclGen, |
| ... | @@ -2370,46 +2390,26 @@ pub const DeclGen = struct { | ... | @@ -2370,46 +2390,26 @@ pub const DeclGen = struct { |
| 2370 | name: CValue, | 2390 | name: CValue, |
| 2371 | mutability: Mutability, | 2391 | mutability: Mutability, |
| 2372 | alignment: u32, | 2392 | alignment: u32, |
| 2373 | kind: TypedefKind, | 2393 | _: TypedefKind, |
| 2374 | ) error{ OutOfMemory, AnalysisFail }!void { | 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 | if (alignment != 0) { | 2395 | if (alignment != 0) { |
| 2397 | const abi_alignment = ty.abiAlignment(target); | 2396 | const abi_alignment = ty.abiAlignment(dg.module.getTarget()); |
| 2398 | if (alignment < abi_alignment) { | 2397 | if (alignment < abi_alignment) { |
| 2399 | try w.print("zig_under_align({}) ", .{alignment}); | 2398 | try w.print("zig_under_align({}) ", .{alignment}); |
| 2400 | } else if (alignment > abi_alignment) { | 2399 | } else if (alignment > abi_alignment) { |
| 2401 | try w.print("zig_align({}) ", .{alignment}); | 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) { | 2404 | const idx = try dg.typeToIndex(ty); |
| 2407 | .Const, .ConstArgument => "const ", | 2405 | try w.print("{}", .{try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.init(.{ |
| 2408 | .Mut => "", | 2406 | .@"const" = switch (mutability) { |
| 2409 | }; | 2407 | .Const, .ConstArgument => true, |
| 2410 | try w.print(" {s}", .{const_prefix}); | 2408 | .Mut => false, |
| | 2409 | }, |
| | 2410 | }))}); |
| 2411 | try dg.writeCValue(w, name); | 2411 | try dg.writeCValue(w, name); |
| 2412 | try w.writeAll(suffix.items); | 2412 | try dg.renderTypeSuffix(w, idx, .suffix); |
| 2413 | } | 2413 | } |
| 2414 | | 2414 | |
| 2415 | fn renderTagNameFn(dg: *DeclGen, enum_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { | 2415 | fn renderTagNameFn(dg: *DeclGen, enum_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |