| ... | ... | @@ -48,6 +48,11 @@ const BlockData = struct { |
| 48 | 48 | result: CValue, |
| 49 | 49 | }; |
| 50 | 50 | |
| 51 | const TypedefKind = enum { |
| 52 | Forward, |
| 53 | Complete, |
| 54 | }; |
| 55 | |
| 51 | 56 | pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue); |
| 52 | 57 | pub const TypedefMap = std.ArrayHashMap( |
| 53 | 58 | Type, |
| ... | ... | @@ -249,13 +254,7 @@ pub const Function = struct { |
| 249 | 254 | const decl_c_value = f.allocLocalValue(); |
| 250 | 255 | gop.value_ptr.* = decl_c_value; |
| 251 | 256 | try writer.writeAll("static "); |
| 252 | | try f.object.dg.renderTypeAndName( |
| 253 | | writer, |
| 254 | | ty, |
| 255 | | decl_c_value, |
| 256 | | .Const, |
| 257 | | 0, |
| 258 | | ); |
| 257 | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete); |
| 259 | 258 | try writer.writeAll(" = "); |
| 260 | 259 | try f.object.dg.renderValue(writer, ty, val, .Initializer); |
| 261 | 260 | try writer.writeAll(";\n "); |
| ... | ... | @@ -294,6 +293,7 @@ pub const Function = struct { |
| 294 | 293 | local_value, |
| 295 | 294 | mutability, |
| 296 | 295 | alignment, |
| 296 | .Complete, |
| 297 | 297 | ); |
| 298 | 298 | return local_value; |
| 299 | 299 | } |
| ... | ... | @@ -328,7 +328,7 @@ pub const Function = struct { |
| 328 | 328 | } |
| 329 | 329 | |
| 330 | 330 | fn renderType(f: *Function, w: anytype, t: Type) !void { |
| 331 | | return f.object.dg.renderType(w, t); |
| 331 | return f.object.dg.renderType(w, t, .Complete); |
| 332 | 332 | } |
| 333 | 333 | |
| 334 | 334 | fn renderTypecast(f: *Function, w: anytype, t: Type) !void { |
| ... | ... | @@ -1024,10 +1024,7 @@ pub const DeclGen = struct { |
| 1024 | 1024 | } |
| 1025 | 1025 | } |
| 1026 | 1026 | |
| 1027 | | fn renderFunctionSignature(dg: *DeclGen, w: anytype, is_global: bool) !void { |
| 1028 | | if (!is_global) { |
| 1029 | | try w.writeAll("static "); |
| 1030 | | } |
| 1027 | fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind) !void { |
| 1031 | 1028 | const fn_info = dg.decl.ty.fnInfo(); |
| 1032 | 1029 | if (fn_info.cc == .Naked) { |
| 1033 | 1030 | try w.writeAll("ZIG_NAKED "); |
| ... | ... | @@ -1039,9 +1036,9 @@ pub const DeclGen = struct { |
| 1039 | 1036 | } |
| 1040 | 1037 | } |
| 1041 | 1038 | if (fn_info.return_type.hasRuntimeBits()) { |
| 1042 | | try dg.renderType(w, fn_info.return_type); |
| 1039 | try dg.renderType(w, fn_info.return_type, kind); |
| 1043 | 1040 | } else if (fn_info.return_type.isError()) { |
| 1044 | | try dg.renderType(w, Type.anyerror); |
| 1041 | try dg.renderType(w, Type.anyerror, kind); |
| 1045 | 1042 | } else if (fn_info.return_type.zigTypeTag() == .NoReturn) { |
| 1046 | 1043 | try w.writeAll("zig_noreturn void"); |
| 1047 | 1044 | } else { |
| ... | ... | @@ -1058,7 +1055,7 @@ pub const DeclGen = struct { |
| 1058 | 1055 | try w.writeAll(", "); |
| 1059 | 1056 | } |
| 1060 | 1057 | const name = CValue{ .arg = index }; |
| 1061 | | try dg.renderTypeAndName(w, param_type, name, .Const, 0); |
| 1058 | try dg.renderTypeAndName(w, param_type, name, .Const, 0, kind); |
| 1062 | 1059 | index += 1; |
| 1063 | 1060 | } |
| 1064 | 1061 | |
| ... | ... | @@ -1071,15 +1068,15 @@ pub const DeclGen = struct { |
| 1071 | 1068 | try w.writeByte(')'); |
| 1072 | 1069 | } |
| 1073 | 1070 | |
| 1074 | | fn renderPtrToFnTypedef(dg: *DeclGen, t: Type, fn_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1071 | fn renderPtrToFnTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1075 | 1072 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1076 | 1073 | defer buffer.deinit(); |
| 1077 | 1074 | const bw = buffer.writer(); |
| 1078 | 1075 | |
| 1079 | | const fn_info = fn_ty.fnInfo(); |
| 1076 | const fn_info = t.fnInfo(); |
| 1080 | 1077 | |
| 1081 | 1078 | try bw.writeAll("typedef "); |
| 1082 | | try dg.renderType(bw, fn_info.return_type); |
| 1079 | try dg.renderType(bw, fn_info.return_type, .Forward); |
| 1083 | 1080 | try bw.writeAll(" (*"); |
| 1084 | 1081 | |
| 1085 | 1082 | const name_begin = buffer.items.len; |
| ... | ... | @@ -1092,11 +1089,12 @@ pub const DeclGen = struct { |
| 1092 | 1089 | var params_written: usize = 0; |
| 1093 | 1090 | var index: usize = 0; |
| 1094 | 1091 | while (index < param_len) : (index += 1) { |
| 1095 | | if (!fn_info.param_types[index].hasRuntimeBitsIgnoreComptime()) continue; |
| 1092 | const param_ty = fn_info.param_types[index]; |
| 1093 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1096 | 1094 | if (params_written > 0) { |
| 1097 | 1095 | try bw.writeAll(", "); |
| 1098 | 1096 | } |
| 1099 | | try dg.renderTypecast(bw, fn_info.param_types[index]); |
| 1097 | try dg.renderTypeAndName(bw, param_ty, .{ .bytes = "" }, .Mut, 0, .Forward); |
| 1100 | 1098 | params_written += 1; |
| 1101 | 1099 | } |
| 1102 | 1100 | |
| ... | ... | @@ -1133,7 +1131,7 @@ pub const DeclGen = struct { |
| 1133 | 1131 | var ptr_type_buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1134 | 1132 | const ptr_type = t.slicePtrFieldType(&ptr_type_buf); |
| 1135 | 1133 | const ptr_name = CValue{ .bytes = "ptr" }; |
| 1136 | | try dg.renderTypeAndName(bw, ptr_type, ptr_name, .Mut, 0); |
| 1134 | try dg.renderTypeAndName(bw, ptr_type, ptr_name, .Mut, 0, .Complete); |
| 1137 | 1135 | |
| 1138 | 1136 | try bw.writeAll("; size_t len; } "); |
| 1139 | 1137 | const name_begin = buffer.items.len; |
| ... | ... | @@ -1157,27 +1155,33 @@ pub const DeclGen = struct { |
| 1157 | 1155 | return name; |
| 1158 | 1156 | } |
| 1159 | 1157 | |
| 1160 | | fn renderStructTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1161 | | const struct_obj = t.castTag(.@"struct").?.data; // Handle 0 bit types elsewhere. |
| 1162 | | const fqn = try struct_obj.getFullyQualifiedName(dg.module); |
| 1163 | | defer dg.typedefs.allocator.free(fqn); |
| 1158 | fn renderFwdTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1159 | // The forward declaration for T is stored with a key of *const T. |
| 1160 | const child_ty = t.childType(); |
| 1161 | |
| 1162 | var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1163 | defer fqn_buf.deinit(); |
| 1164 | |
| 1165 | const owner_decl = dg.module.declPtr(child_ty.getOwnerDecl()); |
| 1166 | try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer()); |
| 1164 | 1167 | |
| 1165 | 1168 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1166 | 1169 | defer buffer.deinit(); |
| 1167 | 1170 | |
| 1168 | | const tag = "struct"; |
| 1169 | | const tagged_name_begin = buffer.items.len + "typedef ".len + tag.len + " ".len; |
| 1170 | | try buffer.writer().print("typedef " ++ tag ++ " zig_S_{} ", .{fmtIdent(fqn)}); |
| 1171 | | const tagged_name_end = buffer.items.len - " ".len; |
| 1172 | | try buffer.ensureUnusedCapacity(tagged_name_end - tagged_name_begin + ";\n".len); |
| 1173 | | const name_begin = buffer.items.len; |
| 1174 | | buffer.appendSliceAssumeCapacity(buffer.items[tagged_name_begin..tagged_name_end]); |
| 1175 | | const name_end = buffer.items.len; |
| 1171 | const tag = switch (child_ty.zigTypeTag()) { |
| 1172 | .Struct => "struct ", |
| 1173 | .Union => if (child_ty.unionTagTypeSafety()) |_| "struct " else "union ", |
| 1174 | else => unreachable, |
| 1175 | }; |
| 1176 | const name_begin = buffer.items.len + "typedef ".len + tag.len; |
| 1177 | try buffer.writer().print("typedef {s}zig_S_{} ", .{ tag, fmtIdent(fqn_buf.items) }); |
| 1178 | const name_end = buffer.items.len - " ".len; |
| 1179 | try buffer.ensureUnusedCapacity((name_end - name_begin) + ";\n".len); |
| 1180 | buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]); |
| 1176 | 1181 | buffer.appendSliceAssumeCapacity(";\n"); |
| 1177 | 1182 | |
| 1178 | 1183 | const rendered = buffer.toOwnedSlice(); |
| 1179 | 1184 | errdefer dg.typedefs.allocator.free(rendered); |
| 1180 | | const tagged_name = rendered[tagged_name_begin..tagged_name_end]; |
| 1181 | 1185 | const name = rendered[name_begin..name_end]; |
| 1182 | 1186 | |
| 1183 | 1187 | try dg.typedefs.ensureUnusedCapacity(1); |
| ... | ... | @@ -1186,20 +1190,32 @@ pub const DeclGen = struct { |
| 1186 | 1190 | .{ .name = name, .rendered = rendered }, |
| 1187 | 1191 | ); |
| 1188 | 1192 | |
| 1189 | | try buffer.appendSlice(tag ++ " "); |
| 1190 | | try buffer.appendSlice(tagged_name); |
| 1193 | return name; |
| 1194 | } |
| 1195 | |
| 1196 | fn renderStructTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1197 | var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t }; |
| 1198 | const ptr_ty = Type.initPayload(&ptr_pl.base); |
| 1199 | const name = dg.getTypedefName(ptr_ty) orelse |
| 1200 | try dg.renderFwdTypedef(ptr_ty); |
| 1201 | |
| 1202 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1203 | defer buffer.deinit(); |
| 1204 | |
| 1205 | try buffer.appendSlice("struct "); |
| 1206 | try buffer.appendSlice(name); |
| 1191 | 1207 | try buffer.appendSlice(" {\n"); |
| 1192 | 1208 | { |
| 1193 | | var it = struct_obj.fields.iterator(); |
| 1209 | var it = t.structFields().iterator(); |
| 1194 | 1210 | var empty = true; |
| 1195 | | while (it.next()) |entry| { |
| 1196 | | const field_ty = entry.value_ptr.ty; |
| 1211 | while (it.next()) |field| { |
| 1212 | const field_ty = field.value_ptr.ty; |
| 1197 | 1213 | if (!field_ty.hasRuntimeBits()) continue; |
| 1198 | 1214 | |
| 1199 | | const alignment = entry.value_ptr.abi_align; |
| 1200 | | const field_name: CValue = .{ .identifier = entry.key_ptr.* }; |
| 1215 | const alignment = field.value_ptr.abi_align; |
| 1216 | const field_name = CValue{ .identifier = field.key_ptr.* }; |
| 1201 | 1217 | try buffer.append(' '); |
| 1202 | | try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment); |
| 1218 | try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete); |
| 1203 | 1219 | try buffer.appendSlice(";\n"); |
| 1204 | 1220 | |
| 1205 | 1221 | empty = false; |
| ... | ... | @@ -1208,16 +1224,13 @@ pub const DeclGen = struct { |
| 1208 | 1224 | } |
| 1209 | 1225 | try buffer.appendSlice("};\n"); |
| 1210 | 1226 | |
| 1211 | | const rendered_body = buffer.toOwnedSlice(); |
| 1212 | | errdefer dg.typedefs.allocator.free(rendered_body); |
| 1227 | const rendered = buffer.toOwnedSlice(); |
| 1228 | errdefer dg.typedefs.allocator.free(rendered); |
| 1213 | 1229 | |
| 1214 | | // We need to add another item to the TypedefMap, so we need a distinct |
| 1215 | | // type that is not used anywhere, but is still uniquely associated with |
| 1216 | | // this type, so use an empty struct which references our unique decls. |
| 1217 | 1230 | try dg.typedefs.ensureUnusedCapacity(1); |
| 1218 | 1231 | dg.typedefs.putAssumeCapacityNoClobber( |
| 1219 | | try Type.Tag.empty_struct.create(dg.typedefs_arena, &struct_obj.namespace), |
| 1220 | | .{ .name = undefined, .rendered = rendered_body }, |
| 1232 | try t.copy(dg.typedefs_arena), |
| 1233 | .{ .name = name, .rendered = rendered }, |
| 1221 | 1234 | ); |
| 1222 | 1235 | |
| 1223 | 1236 | return name; |
| ... | ... | @@ -1240,7 +1253,7 @@ pub const DeclGen = struct { |
| 1240 | 1253 | defer dg.typedefs.allocator.free(field_name); |
| 1241 | 1254 | |
| 1242 | 1255 | try buffer.append(' '); |
| 1243 | | try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0); |
| 1256 | try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete); |
| 1244 | 1257 | try buffer.appendSlice(";\n"); |
| 1245 | 1258 | |
| 1246 | 1259 | empty = false; |
| ... | ... | @@ -1265,37 +1278,16 @@ pub const DeclGen = struct { |
| 1265 | 1278 | } |
| 1266 | 1279 | |
| 1267 | 1280 | fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1268 | | const union_obj = t.cast(Type.Payload.Union).?.data; |
| 1269 | | const fqn = try union_obj.getFullyQualifiedName(dg.module); |
| 1270 | | defer dg.typedefs.allocator.free(fqn); |
| 1281 | var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t }; |
| 1282 | const ptr_ty = Type.initPayload(&ptr_pl.base); |
| 1283 | const name = dg.getTypedefName(ptr_ty) orelse |
| 1284 | try dg.renderFwdTypedef(ptr_ty); |
| 1271 | 1285 | |
| 1272 | 1286 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1273 | 1287 | defer buffer.deinit(); |
| 1274 | 1288 | |
| 1275 | | const tag: []const u8 = if (t.unionTagTypeSafety()) |_| "struct" else "union"; |
| 1276 | | const tagged_name_begin = buffer.items.len + "typedef ".len + tag.len + " ".len; |
| 1277 | | try buffer.writer().print("typedef {s} zig_S_{} ", .{ tag, fmtIdent(fqn) }); |
| 1278 | | const tagged_name_end = buffer.items.len - " ".len; |
| 1279 | | try buffer.ensureUnusedCapacity(tagged_name_end - tagged_name_begin + ";\n".len); |
| 1280 | | const name_begin = buffer.items.len; |
| 1281 | | buffer.appendSliceAssumeCapacity(buffer.items[tagged_name_begin..tagged_name_end]); |
| 1282 | | const name_end = buffer.items.len; |
| 1283 | | buffer.appendSliceAssumeCapacity(";\n"); |
| 1284 | | |
| 1285 | | const rendered = buffer.toOwnedSlice(); |
| 1286 | | errdefer dg.typedefs.allocator.free(rendered); |
| 1287 | | const tagged_name = rendered[tagged_name_begin..tagged_name_end]; |
| 1288 | | const name = rendered[name_begin..name_end]; |
| 1289 | | |
| 1290 | | try dg.typedefs.ensureUnusedCapacity(1); |
| 1291 | | dg.typedefs.putAssumeCapacityNoClobber( |
| 1292 | | try t.copy(dg.typedefs_arena), |
| 1293 | | .{ .name = name, .rendered = rendered }, |
| 1294 | | ); |
| 1295 | | |
| 1296 | | try buffer.appendSlice(tag); |
| 1297 | | try buffer.append(' '); |
| 1298 | | try buffer.appendSlice(tagged_name); |
| 1289 | try buffer.appendSlice(if (t.unionTagTypeSafety()) |_| "struct " else "union "); |
| 1290 | try buffer.appendSlice(name); |
| 1299 | 1291 | try buffer.appendSlice(" {\n"); |
| 1300 | 1292 | |
| 1301 | 1293 | const indent = if (t.unionTagTypeSafety()) |tag_ty| indent: { |
| ... | ... | @@ -1303,7 +1295,7 @@ pub const DeclGen = struct { |
| 1303 | 1295 | const layout = t.unionGetLayout(target); |
| 1304 | 1296 | if (layout.tag_size != 0) { |
| 1305 | 1297 | try buffer.append(' '); |
| 1306 | | try dg.renderTypeAndName(buffer.writer(), tag_ty, .{ .identifier = "tag" }, .Mut, 0); |
| 1298 | try dg.renderTypeAndName(buffer.writer(), tag_ty, .{ .identifier = "tag" }, .Mut, 0, .Complete); |
| 1307 | 1299 | try buffer.appendSlice(";\n"); |
| 1308 | 1300 | } |
| 1309 | 1301 | try buffer.appendSlice(" union {\n"); |
| ... | ... | @@ -1313,14 +1305,14 @@ pub const DeclGen = struct { |
| 1313 | 1305 | { |
| 1314 | 1306 | var it = t.unionFields().iterator(); |
| 1315 | 1307 | var empty = true; |
| 1316 | | while (it.next()) |entry| { |
| 1317 | | const field_ty = entry.value_ptr.ty; |
| 1308 | while (it.next()) |field| { |
| 1309 | const field_ty = field.value_ptr.ty; |
| 1318 | 1310 | if (!field_ty.hasRuntimeBits()) continue; |
| 1319 | 1311 | |
| 1320 | | const alignment = entry.value_ptr.abi_align; |
| 1321 | | const field_name: CValue = .{ .identifier = entry.key_ptr.* }; |
| 1312 | const alignment = field.value_ptr.abi_align; |
| 1313 | const field_name = CValue{ .identifier = field.key_ptr.* }; |
| 1322 | 1314 | try buffer.appendSlice(indent); |
| 1323 | | try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment); |
| 1315 | try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete); |
| 1324 | 1316 | try buffer.appendSlice(";\n"); |
| 1325 | 1317 | |
| 1326 | 1318 | empty = false; |
| ... | ... | @@ -1334,16 +1326,13 @@ pub const DeclGen = struct { |
| 1334 | 1326 | if (t.unionTagTypeSafety()) |_| try buffer.appendSlice(" } payload;\n"); |
| 1335 | 1327 | try buffer.appendSlice("};\n"); |
| 1336 | 1328 | |
| 1337 | | const rendered_body = buffer.toOwnedSlice(); |
| 1338 | | errdefer dg.typedefs.allocator.free(rendered_body); |
| 1329 | const rendered = buffer.toOwnedSlice(); |
| 1330 | errdefer dg.typedefs.allocator.free(rendered); |
| 1339 | 1331 | |
| 1340 | | // We need to add another item to the TypedefMap, so we need a distinct |
| 1341 | | // type that is not used anywhere, but is still uniquely associated with |
| 1342 | | // this type, so use an empty struct which references our unique decls. |
| 1343 | 1332 | try dg.typedefs.ensureUnusedCapacity(1); |
| 1344 | 1333 | dg.typedefs.putAssumeCapacityNoClobber( |
| 1345 | | try Type.Tag.empty_struct.create(dg.typedefs_arena, &union_obj.namespace), |
| 1346 | | .{ .name = undefined, .rendered = rendered_body }, |
| 1334 | try t.copy(dg.typedefs_arena), |
| 1335 | .{ .name = name, .rendered = rendered }, |
| 1347 | 1336 | ); |
| 1348 | 1337 | |
| 1349 | 1338 | return name; |
| ... | ... | @@ -1363,11 +1352,11 @@ pub const DeclGen = struct { |
| 1363 | 1352 | const error_align = Type.anyerror.abiAlignment(target); |
| 1364 | 1353 | if (error_align > payload_align) { |
| 1365 | 1354 | try bw.writeAll("typedef struct { "); |
| 1366 | | try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0); |
| 1355 | try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete); |
| 1367 | 1356 | try bw.writeAll("; uint16_t error; } "); |
| 1368 | 1357 | } else { |
| 1369 | 1358 | try bw.writeAll("typedef struct { uint16_t error; "); |
| 1370 | | try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0); |
| 1359 | try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete); |
| 1371 | 1360 | try bw.writeAll("; } "); |
| 1372 | 1361 | } |
| 1373 | 1362 | |
| ... | ... | @@ -1398,7 +1387,7 @@ pub const DeclGen = struct { |
| 1398 | 1387 | const bw = buffer.writer(); |
| 1399 | 1388 | |
| 1400 | 1389 | try bw.writeAll("typedef "); |
| 1401 | | try dg.renderType(bw, info.elem_type); |
| 1390 | try dg.renderType(bw, info.elem_type, .Complete); |
| 1402 | 1391 | |
| 1403 | 1392 | const name_begin = buffer.items.len + " ".len; |
| 1404 | 1393 | try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len }); |
| ... | ... | @@ -1426,7 +1415,7 @@ pub const DeclGen = struct { |
| 1426 | 1415 | |
| 1427 | 1416 | try bw.writeAll("typedef struct { "); |
| 1428 | 1417 | const payload_name = CValue{ .bytes = "payload" }; |
| 1429 | | try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); |
| 1418 | try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0, .Complete); |
| 1430 | 1419 | try bw.writeAll("; bool is_null; } "); |
| 1431 | 1420 | |
| 1432 | 1421 | const name_begin = buffer.items.len; |
| ... | ... | @@ -1488,7 +1477,12 @@ pub const DeclGen = struct { |
| 1488 | 1477 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | |
| 1489 | 1478 | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | |
| 1490 | 1479 | /// |
| 1491 | | fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void { |
| 1480 | fn renderType( |
| 1481 | dg: *DeclGen, |
| 1482 | w: anytype, |
| 1483 | t: Type, |
| 1484 | kind: TypedefKind, |
| 1485 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1492 | 1486 | const target = dg.module.getTarget(); |
| 1493 | 1487 | |
| 1494 | 1488 | switch (t.zigTypeTag()) { |
| ... | ... | @@ -1540,10 +1534,11 @@ pub const DeclGen = struct { |
| 1540 | 1534 | } |
| 1541 | 1535 | }, |
| 1542 | 1536 | .Pointer => { |
| 1537 | const child_ty = t.childType(); |
| 1543 | 1538 | if (t.isSlice()) { |
| 1544 | 1539 | var slice_pl = Type.Payload.ElemType{ |
| 1545 | 1540 | .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice }, |
| 1546 | | .data = t.childType(), |
| 1541 | .data = child_ty, |
| 1547 | 1542 | }; |
| 1548 | 1543 | const slice_ty = Type.initPayload(&slice_pl.base); |
| 1549 | 1544 | |
| ... | ... | @@ -1553,31 +1548,27 @@ pub const DeclGen = struct { |
| 1553 | 1548 | return w.writeAll(name); |
| 1554 | 1549 | } |
| 1555 | 1550 | |
| 1556 | | if (t.castPtrToFn()) |fn_ty| { |
| 1557 | | const name = dg.getTypedefName(t) orelse |
| 1558 | | try dg.renderPtrToFnTypedef(t, fn_ty); |
| 1551 | if (child_ty.zigTypeTag() == .Fn) { |
| 1552 | const name = dg.getTypedefName(child_ty) orelse |
| 1553 | try dg.renderPtrToFnTypedef(child_ty); |
| 1559 | 1554 | |
| 1560 | 1555 | return w.writeAll(name); |
| 1561 | 1556 | } |
| 1562 | 1557 | |
| 1563 | | const child_ty = t.childType(); |
| 1564 | 1558 | if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and |
| 1565 | | (dg.decl.val.tag() == .extern_fn or std.mem.eql(u8, std.mem.span(dg.decl.name), "main"))) |
| 1559 | (dg.decl.val.tag() == .extern_fn or |
| 1560 | std.mem.eql(u8, std.mem.span(dg.decl.name), "main"))) |
| 1566 | 1561 | { |
| 1567 | 1562 | // This is a hack, since the c compiler expects a lot of external |
| 1568 | 1563 | // library functions to have char pointers in their signatures, but |
| 1569 | 1564 | // u8 and i8 produce unsigned char and signed char respectively, |
| 1570 | | // which in C are not very usefully different than char. |
| 1565 | // which in C are (not very usefully) different than char. |
| 1571 | 1566 | try w.writeAll("char"); |
| 1572 | 1567 | } else { |
| 1573 | | try dg.renderType(w, child_ty); |
| 1574 | | } |
| 1575 | | if (t.isConstPtr()) { |
| 1576 | | try w.writeAll(" const"); |
| 1577 | | } |
| 1578 | | if (t.isVolatilePtr()) { |
| 1579 | | try w.writeAll(" volatile"); |
| 1568 | try dg.renderType(w, child_ty, .Forward); |
| 1580 | 1569 | } |
| 1570 | if (t.isConstPtr()) try w.writeAll(" const"); |
| 1571 | if (t.isVolatilePtr()) try w.writeAll(" volatile"); |
| 1581 | 1572 | return w.writeAll(" *"); |
| 1582 | 1573 | }, |
| 1583 | 1574 | .Array => { |
| ... | ... | @@ -1601,7 +1592,7 @@ pub const DeclGen = struct { |
| 1601 | 1592 | } |
| 1602 | 1593 | |
| 1603 | 1594 | if (t.optionalReprIsPayload()) { |
| 1604 | | return dg.renderType(w, child_type); |
| 1595 | return dg.renderType(w, child_type, .Complete); |
| 1605 | 1596 | } |
| 1606 | 1597 | |
| 1607 | 1598 | const name = dg.getTypedefName(t) orelse |
| ... | ... | @@ -1617,7 +1608,7 @@ pub const DeclGen = struct { |
| 1617 | 1608 | const payload_ty = t.errorUnionPayload(); |
| 1618 | 1609 | |
| 1619 | 1610 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1620 | | return dg.renderType(w, Type.anyerror); |
| 1611 | return dg.renderType(w, Type.anyerror, .Complete); |
| 1621 | 1612 | } |
| 1622 | 1613 | |
| 1623 | 1614 | var error_union_pl = Type.Payload.ErrorUnion{ |
| ... | ... | @@ -1630,17 +1621,26 @@ pub const DeclGen = struct { |
| 1630 | 1621 | |
| 1631 | 1622 | return w.writeAll(name); |
| 1632 | 1623 | }, |
| 1633 | | .Struct => { |
| 1634 | | const name = dg.getTypedefName(t) orelse if (t.isTupleOrAnonStruct()) |
| 1635 | | try dg.renderTupleTypedef(t) |
| 1636 | | else |
| 1637 | | try dg.renderStructTypedef(t); |
| 1624 | .Struct, .Union => |tag| if (kind == .Complete or t.isTupleOrAnonStruct()) { |
| 1625 | const name = dg.getTypedefName(t) orelse switch (tag) { |
| 1626 | .Struct => if (t.isTupleOrAnonStruct()) |
| 1627 | try dg.renderTupleTypedef(t) |
| 1628 | else |
| 1629 | try dg.renderStructTypedef(t), |
| 1630 | .Union => try dg.renderUnionTypedef(t), |
| 1631 | else => unreachable, |
| 1632 | }; |
| 1638 | 1633 | |
| 1639 | 1634 | return w.writeAll(name); |
| 1640 | | }, |
| 1641 | | .Union => { |
| 1642 | | const name = dg.getTypedefName(t) orelse |
| 1643 | | try dg.renderUnionTypedef(t); |
| 1635 | } else { |
| 1636 | var ptr_pl = Type.Payload.ElemType{ |
| 1637 | .base = .{ .tag = .single_const_pointer }, |
| 1638 | .data = t, |
| 1639 | }; |
| 1640 | const ptr_ty = Type.initPayload(&ptr_pl.base); |
| 1641 | |
| 1642 | const name = dg.getTypedefName(ptr_ty) orelse |
| 1643 | try dg.renderFwdTypedef(ptr_ty); |
| 1644 | 1644 | |
| 1645 | 1645 | return w.writeAll(name); |
| 1646 | 1646 | }, |
| ... | ... | @@ -1649,7 +1649,7 @@ pub const DeclGen = struct { |
| 1649 | 1649 | var int_tag_buf: Type.Payload.Bits = undefined; |
| 1650 | 1650 | const int_tag_ty = t.intTagType(&int_tag_buf); |
| 1651 | 1651 | |
| 1652 | | try dg.renderType(w, int_tag_ty); |
| 1652 | try dg.renderType(w, int_tag_ty, kind); |
| 1653 | 1653 | }, |
| 1654 | 1654 | .Opaque => switch (t.tag()) { |
| 1655 | 1655 | .anyopaque => try w.writeAll("void"), |
| ... | ... | @@ -1701,7 +1701,7 @@ pub const DeclGen = struct { |
| 1701 | 1701 | ty: Type, |
| 1702 | 1702 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1703 | 1703 | const name = CValue{ .bytes = "" }; |
| 1704 | | return renderTypeAndName(dg, w, ty, name, .Mut, 0); |
| 1704 | return renderTypeAndName(dg, w, ty, name, .Mut, 0, .Complete); |
| 1705 | 1705 | } |
| 1706 | 1706 | |
| 1707 | 1707 | /// Renders a type and name in field declaration/definition format. |
| ... | ... | @@ -1720,6 +1720,7 @@ pub const DeclGen = struct { |
| 1720 | 1720 | name: CValue, |
| 1721 | 1721 | mutability: Mutability, |
| 1722 | 1722 | alignment: u32, |
| 1723 | kind: TypedefKind, |
| 1723 | 1724 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1724 | 1725 | var suffix = std.ArrayList(u8).init(dg.gpa); |
| 1725 | 1726 | defer suffix.deinit(); |
| ... | ... | @@ -1736,7 +1737,7 @@ pub const DeclGen = struct { |
| 1736 | 1737 | |
| 1737 | 1738 | if (alignment != 0) |
| 1738 | 1739 | try w.print("ZIG_ALIGN({}) ", .{alignment}); |
| 1739 | | try dg.renderType(w, render_ty); |
| 1740 | try dg.renderType(w, render_ty, kind); |
| 1740 | 1741 | |
| 1741 | 1742 | const const_prefix = switch (mutability) { |
| 1742 | 1743 | .Const => "const ", |
| ... | ... | @@ -1755,11 +1756,11 @@ pub const DeclGen = struct { |
| 1755 | 1756 | const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0); |
| 1756 | 1757 | |
| 1757 | 1758 | try buffer.appendSlice("static "); |
| 1758 | | try dg.renderType(bw, name_slice_ty); |
| 1759 | try dg.renderType(bw, name_slice_ty, .Complete); |
| 1759 | 1760 | const name_begin = buffer.items.len + " ".len; |
| 1760 | 1761 | try bw.print(" zig_tagName_{}(", .{typeToCIdentifier(enum_ty, dg.module)}); |
| 1761 | 1762 | const name_end = buffer.items.len - "(".len; |
| 1762 | | try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0); |
| 1763 | try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0, .Complete); |
| 1763 | 1764 | try buffer.appendSlice(") {\n switch (tag) {\n"); |
| 1764 | 1765 | for (enum_ty.enumFields().keys()) |name, index| { |
| 1765 | 1766 | const name_z = try dg.typedefs.allocator.dupeZ(u8, name); |
| ... | ... | @@ -1785,7 +1786,7 @@ pub const DeclGen = struct { |
| 1785 | 1786 | const len_val = Value.initPayload(&len_pl.base); |
| 1786 | 1787 | |
| 1787 | 1788 | try bw.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)}); |
| 1788 | | try dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, .Const, 0); |
| 1789 | try dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, .Const, 0, .Complete); |
| 1789 | 1790 | try buffer.appendSlice(" = "); |
| 1790 | 1791 | try dg.renderValue(bw, name_ty, name_val, .Initializer); |
| 1791 | 1792 | try buffer.appendSlice(";\n return ("); |
| ... | ... | @@ -1948,7 +1949,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 1948 | 1949 | const name_val = Value.initPayload(&name_pl.base); |
| 1949 | 1950 | |
| 1950 | 1951 | try writer.writeAll("static "); |
| 1951 | | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0); |
| 1952 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete); |
| 1952 | 1953 | try writer.writeAll(" = "); |
| 1953 | 1954 | try o.dg.renderValue(writer, name_ty, name_val, .Initializer); |
| 1954 | 1955 | try writer.writeAll(";\n"); |
| ... | ... | @@ -1961,7 +1962,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 1961 | 1962 | const name_array_ty = Type.initPayload(&name_array_ty_pl.base); |
| 1962 | 1963 | |
| 1963 | 1964 | try writer.writeAll("static "); |
| 1964 | | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .Const, 0); |
| 1965 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .Const, 0, .Complete); |
| 1965 | 1966 | try writer.writeAll(" = {"); |
| 1966 | 1967 | for (o.dg.module.error_name_list.items) |name, value| { |
| 1967 | 1968 | if (value != 0) try writer.writeByte(','); |
| ... | ... | @@ -1988,14 +1989,13 @@ pub fn genFunc(f: *Function) !void { |
| 1988 | 1989 | |
| 1989 | 1990 | const is_global = o.dg.module.decl_exports.contains(f.func.owner_decl); |
| 1990 | 1991 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 1991 | | if (is_global) { |
| 1992 | | try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); |
| 1993 | | } |
| 1994 | | try o.dg.renderFunctionSignature(fwd_decl_writer, is_global); |
| 1992 | try fwd_decl_writer.writeAll(if (is_global) "ZIG_EXTERN_C " else "static "); |
| 1993 | try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward); |
| 1995 | 1994 | try fwd_decl_writer.writeAll(";\n"); |
| 1996 | 1995 | |
| 1997 | 1996 | try o.indent_writer.insertNewline(); |
| 1998 | | try o.dg.renderFunctionSignature(o.writer(), is_global); |
| 1997 | if (!is_global) try o.writer().writeAll("static "); |
| 1998 | try o.dg.renderFunctionSignature(o.writer(), .Complete); |
| 1999 | 1999 | try o.writer().writeByte(' '); |
| 2000 | 2000 | |
| 2001 | 2001 | // In case we need to use the header, populate it with a copy of the function |
| ... | ... | @@ -2029,7 +2029,7 @@ pub fn genDecl(o: *Object) !void { |
| 2029 | 2029 | if (tv.val.tag() == .extern_fn) { |
| 2030 | 2030 | const writer = o.writer(); |
| 2031 | 2031 | try writer.writeAll("ZIG_EXTERN_C "); |
| 2032 | | try o.dg.renderFunctionSignature(writer, true); |
| 2032 | try o.dg.renderFunctionSignature(writer, .Forward); |
| 2033 | 2033 | try writer.writeAll(";\n"); |
| 2034 | 2034 | } else if (tv.val.castTag(.variable)) |var_payload| { |
| 2035 | 2035 | const variable: *Module.Var = var_payload.data; |
| ... | ... | @@ -2048,7 +2048,7 @@ pub fn genDecl(o: *Object) !void { |
| 2048 | 2048 | .decl = o.dg.decl_index, |
| 2049 | 2049 | }; |
| 2050 | 2050 | |
| 2051 | | try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align"); |
| 2051 | try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2052 | 2052 | try fwd_decl_writer.writeAll(";\n"); |
| 2053 | 2053 | |
| 2054 | 2054 | if (variable.is_extern or variable.init.isUndefDeep()) { |
| ... | ... | @@ -2057,7 +2057,7 @@ pub fn genDecl(o: *Object) !void { |
| 2057 | 2057 | |
| 2058 | 2058 | try o.indent_writer.insertNewline(); |
| 2059 | 2059 | const w = o.writer(); |
| 2060 | | try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align"); |
| 2060 | try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2061 | 2061 | try w.writeAll(" = "); |
| 2062 | 2062 | if (variable.init.tag() != .unreachable_value) { |
| 2063 | 2063 | try o.dg.renderValue(w, tv.ty, variable.init, .Initializer); |
| ... | ... | @@ -2072,7 +2072,7 @@ pub fn genDecl(o: *Object) !void { |
| 2072 | 2072 | // https://github.com/ziglang/zig/issues/7582 |
| 2073 | 2073 | |
| 2074 | 2074 | const decl_c_value: CValue = .{ .decl = o.dg.decl_index }; |
| 2075 | | try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align"); |
| 2075 | try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2076 | 2076 | |
| 2077 | 2077 | try writer.writeAll(" = "); |
| 2078 | 2078 | try o.dg.renderValue(writer, tv.ty, tv.val, .Initializer); |
| ... | ... | @@ -2095,7 +2095,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { |
| 2095 | 2095 | const is_global = dg.declIsGlobal(tv); |
| 2096 | 2096 | if (is_global) { |
| 2097 | 2097 | try writer.writeAll("ZIG_EXTERN_C "); |
| 2098 | | try dg.renderFunctionSignature(writer, is_global); |
| 2098 | try dg.renderFunctionSignature(writer, .Complete); |
| 2099 | 2099 | try dg.fwd_decl.appendSlice(";\n"); |
| 2100 | 2100 | } |
| 2101 | 2101 | }, |
| ... | ... | @@ -2760,8 +2760,10 @@ fn airWrapOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, fn_name: |
| 2760 | 2760 | const bits = int_info.bits; |
| 2761 | 2761 | |
| 2762 | 2762 | // if it's an unsigned int with non-arbitrary bit size then we can just add |
| 2763 | | if (int_info.signedness == .unsigned and bits == toCIntBits(bits)) { |
| 2764 | | return try airBinOp(f, inst, operator); |
| 2763 | if (toCIntBits(bits)) |c_bits| { |
| 2764 | if (int_info.signedness == .unsigned and bits == c_bits) { |
| 2765 | return try airBinOp(f, inst, operator); |
| 2766 | } |
| 2765 | 2767 | } |
| 2766 | 2768 | |
| 2767 | 2769 | if (bits > 64) return f.fail("TODO: C backend: airWrapOp for large integers", .{}); |
| ... | ... | @@ -3899,9 +3901,11 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 3899 | 3901 | } |
| 3900 | 3902 | const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; |
| 3901 | 3903 | |
| 3904 | // Ensure complete type definition is visible before accessing fields. |
| 3905 | try f.renderType(std.io.null_writer, struct_ty); |
| 3906 | |
| 3902 | 3907 | const inst_ty = f.air.typeOfIndex(inst); |
| 3903 | 3908 | const local = try f.allocLocal(inst_ty, .Const); |
| 3904 | | |
| 3905 | 3909 | if (field_val_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3906 | 3910 | try writer.writeAll(" = &"); |
| 3907 | 3911 | try f.writeCValueDeref(writer, struct_ptr); |
| ... | ... | @@ -3941,6 +3945,9 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3941 | 3945 | }; |
| 3942 | 3946 | const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; |
| 3943 | 3947 | |
| 3948 | // Ensure complete type definition is visible before accessing fields. |
| 3949 | try f.renderType(std.io.null_writer, struct_ty); |
| 3950 | |
| 3944 | 3951 | const inst_ty = f.air.typeOfIndex(inst); |
| 3945 | 3952 | const is_array = inst_ty.zigTypeTag() == .Array; |
| 3946 | 3953 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| ... | ... | @@ -4326,7 +4333,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 4326 | 4333 | try writer.writeAll("if ("); |
| 4327 | 4334 | } |
| 4328 | 4335 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 4329 | | try f.object.dg.renderTypecast(writer, ptr_ty.elemType()); |
| 4336 | try f.renderTypecast(writer, ptr_ty.elemType()); |
| 4330 | 4337 | try writer.writeByte(')'); |
| 4331 | 4338 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 4332 | 4339 | try writer.writeAll(" *)"); |
| ... | ... | @@ -4371,12 +4378,12 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4371 | 4378 | switch (extra.op()) { |
| 4372 | 4379 | else => { |
| 4373 | 4380 | try writer.writeAll("zig_atomic("); |
| 4374 | | try f.object.dg.renderTypecast(writer, ptr_ty.elemType()); |
| 4381 | try f.renderTypecast(writer, ptr_ty.elemType()); |
| 4375 | 4382 | try writer.writeByte(')'); |
| 4376 | 4383 | }, |
| 4377 | 4384 | .Nand, .Min, .Max => { |
| 4378 | 4385 | // These are missing from stdatomic.h, so no atomic types for now. |
| 4379 | | try f.object.dg.renderTypecast(writer, ptr_ty.elemType()); |
| 4386 | try f.renderTypecast(writer, ptr_ty.elemType()); |
| 4380 | 4387 | }, |
| 4381 | 4388 | } |
| 4382 | 4389 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| ... | ... | @@ -4403,7 +4410,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4403 | 4410 | const writer = f.object.writer(); |
| 4404 | 4411 | |
| 4405 | 4412 | try writer.writeAll(" = zig_atomic_load((zig_atomic("); |
| 4406 | | try f.object.dg.renderTypecast(writer, ptr_ty.elemType()); |
| 4413 | try f.renderTypecast(writer, ptr_ty.elemType()); |
| 4407 | 4414 | try writer.writeByte(')'); |
| 4408 | 4415 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 4409 | 4416 | try writer.writeAll(" *)"); |
| ... | ... | @@ -4423,7 +4430,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa |
| 4423 | 4430 | const writer = f.object.writer(); |
| 4424 | 4431 | |
| 4425 | 4432 | try writer.writeAll("zig_atomic_store((zig_atomic("); |
| 4426 | | try f.object.dg.renderTypecast(writer, ptr_ty.elemType()); |
| 4433 | try f.renderTypecast(writer, ptr_ty.elemType()); |
| 4427 | 4434 | try writer.writeByte(')'); |
| 4428 | 4435 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 4429 | 4436 | try writer.writeAll(" *)"); |