Commit c9ad1b5199

february cozzocrea <february.cozzocrea@gmail.com>
2024-03-03 02:14:41
aro translate-c: support for record types added
1 parent bcb534c
lib/compiler/aro/aro/Type.zig
@@ -1142,12 +1142,14 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
     };
 }
 
+pub const QualHandling = enum { standard, preserve_quals };
+
 /// Canonicalize a possibly-typeof() type. If the type is not a typeof() type, simply
 /// return it. Otherwise, determine the actual qualified type.
 /// The `qual_handling` parameter can be used to return the full set of qualifiers
 /// added by typeof() operations, which is useful when determining the elemType of
 /// arrays and pointers.
-pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals }) Type {
+pub fn canonicalize(ty: Type, qual_handling: QualHandling) Type {
     var cur = ty;
     if (cur.specifier == .attributed) {
         cur = cur.data.attributed.base;
lib/compiler/aro_translate_c.zig
@@ -52,18 +52,17 @@ fn getMangle(c: *Context) u32 {
     return c.mangle_count;
 }
 
-/// Convert a clang source location to a file:line:column string
-fn locStr(c: *Context, loc: TokenIndex) ![]const u8 {
-    _ = c;
-    _ = loc;
-    // const spelling_loc = c.source_manager.getSpellingLoc(loc);
-    // const filename_c = c.source_manager.getFilename(spelling_loc);
-    // const filename = if (filename_c) |s| try c.str(s) else @as([]const u8, "(no file)");
-
-    // const line = c.source_manager.getSpellingLineNumber(spelling_loc);
-    // const column = c.source_manager.getSpellingColumnNumber(spelling_loc);
-    // return std.fmt.allocPrint(c.arena, "{s}:{d}:{d}", .{ filename, line, column });
-    return "somewhere";
+/// Convert an aro TokenIndex to a 'file:line:column' string
+fn locStr(c: *Context, tok_idx: TokenIndex) ![]const u8 {
+    const token_loc = c.tree.tokens.items(.loc)[tok_idx];
+    const source = c.comp.getSource(token_loc.id);
+    const line_col = source.lineCol(token_loc);
+    const filename = source.path;
+
+    const line = source.physicalLine(token_loc);
+    const col = line_col.col;
+
+    return std.fmt.allocPrint(c.arena, "{s}:{d}:{d}", .{ filename, line, col });
 }
 
 fn maybeSuppressResult(c: *Context, used: ResultUsed, result: ZigNode) TransError!ZigNode {
@@ -184,26 +183,30 @@ fn prepopulateGlobalNameTable(c: *Context) !void {
     const node_data = c.tree.nodes.items(.data);
     for (c.tree.root_decls) |node| {
         const data = node_data[@intFromEnum(node)];
-        const decl_name = switch (node_tags[@intFromEnum(node)]) {
+        switch (node_tags[@intFromEnum(node)]) {
             .typedef => @panic("TODO"),
 
-            .static_assert,
             .struct_decl_two,
             .union_decl_two,
             .struct_decl,
             .union_decl,
-            => blk: {
-                const ty = node_types[@intFromEnum(node)];
-                const name_id = ty.data.record.name;
-                break :blk c.mapper.lookup(name_id);
-            },
-
+            .struct_forward_decl,
+            .union_forward_decl,
             .enum_decl_two,
             .enum_decl,
-            => blk: {
-                const ty = node_types[@intFromEnum(node)];
-                const name_id = ty.data.@"enum".name;
-                break :blk c.mapper.lookup(name_id);
+            .enum_forward_decl,
+            => {
+                const raw_ty = node_types[@intFromEnum(node)];
+                const ty = raw_ty.canonicalize(.standard);
+                const name_id = if (ty.isRecord()) ty.data.record.name else ty.data.@"enum".name;
+                const decl_name = c.mapper.lookup(name_id);
+                const container_prefix = if (ty.is(.@"struct")) "struct" else if (ty.is(.@"union")) "union" else "enum";
+                const prefixed_name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_prefix, decl_name });
+                // `decl_name` and `prefixed_name` are the preferred names for this type.
+                // However, we can name it anything else if necessary, so these are "weak names".
+                try c.weak_global_names.ensureUnusedCapacity(c.gpa, 2);
+                c.weak_global_names.putAssumeCapacity(decl_name, {});
+                c.weak_global_names.putAssumeCapacity(prefixed_name, {});
             },
 
             .fn_proto,
@@ -215,80 +218,256 @@ fn prepopulateGlobalNameTable(c: *Context) !void {
             .inline_fn_def,
             .inline_static_fn_def,
             .@"var",
+            .extern_var,
             .static_var,
             .threadlocal_var,
-            .threadlocal_static_var,
-            .extern_var,
             .threadlocal_extern_var,
-            => c.tree.tokSlice(data.decl.name),
+            .threadlocal_static_var,
+            => {
+                const decl_name = c.tree.tokSlice(data.decl.name);
+                try c.global_names.put(c.gpa, decl_name, {});
+            },
             else => unreachable,
-        };
-        try c.global_names.put(c.gpa, decl_name, {});
+        }
     }
 }
 
 fn transTopLevelDecls(c: *Context) !void {
+    for (c.tree.root_decls) |node| {
+        try transDecl(c, &c.global_scope.base, node);
+    }
+}
+
+fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
     const node_tags = c.tree.nodes.items(.tag);
     const node_data = c.tree.nodes.items(.data);
-    for (c.tree.root_decls) |node| {
-        const data = node_data[@intFromEnum(node)];
-        switch (node_tags[@intFromEnum(node)]) {
-            .typedef => {
-                try transTypeDef(c, &c.global_scope.base, node);
-            },
+    const data = node_data[@intFromEnum(decl)];
+    switch (node_tags[@intFromEnum(decl)]) {
+        .typedef => {
+            try transTypeDef(c, scope, decl);
+        },
 
-            .static_assert,
-            .struct_decl_two,
-            .union_decl_two,
-            .struct_decl,
-            .union_decl,
-            => {
-                try transRecordDecl(c, &c.global_scope.base, node);
-            },
+        .struct_decl_two,
+        .union_decl_two,
+        => {
+            var fields = [2]NodeIndex{ data.bin.lhs, data.bin.rhs };
+            var field_count: u2 = 0;
+            if (fields[0] != .none) field_count += 1;
+            if (fields[1] != .none) field_count += 1;
+            try transRecordDecl(c, scope, decl, fields[0..field_count]);
+        },
+        .struct_decl,
+        .union_decl,
+        => {
+            const fields = c.tree.data[data.range.start..data.range.end];
+            try transRecordDecl(c, scope, decl, fields);
+        },
 
-            .enum_decl_two => {
-                var fields = [2]NodeIndex{ data.bin.lhs, data.bin.rhs };
-                var field_count: u8 = 0;
-                if (fields[0] != .none) field_count += 1;
-                if (fields[1] != .none) field_count += 1;
-                try transEnumDecl(c, &c.global_scope.base, node, fields[0..field_count]);
-            },
-            .enum_decl => {
-                const fields = c.tree.data[data.range.start..data.range.end];
-                try transEnumDecl(c, &c.global_scope.base, node, fields);
-            },
+        .enum_decl_two => {
+            var fields = [2]NodeIndex{ data.bin.lhs, data.bin.rhs };
+            var field_count: u8 = 0;
+            if (fields[0] != .none) field_count += 1;
+            if (fields[1] != .none) field_count += 1;
+            try transEnumDecl(c, scope, decl, fields[0..field_count]);
+        },
+        .enum_decl => {
+            const fields = c.tree.data[data.range.start..data.range.end];
+            try transEnumDecl(c, scope, decl, fields);
+        },
 
-            .fn_proto,
-            .static_fn_proto,
-            .inline_fn_proto,
-            .inline_static_fn_proto,
-            .fn_def,
-            .static_fn_def,
-            .inline_fn_def,
-            .inline_static_fn_def,
-            => {
-                try transFnDecl(c, node);
-            },
+        .enum_field_decl,
+        .record_field_decl,
+        .indirect_record_field_decl,
+        .struct_forward_decl,
+        .union_forward_decl,
+        .enum_forward_decl,
+        => return,
+
+        .fn_proto,
+        .static_fn_proto,
+        .inline_fn_proto,
+        .inline_static_fn_proto,
+        .fn_def,
+        .static_fn_def,
+        .inline_fn_def,
+        .inline_static_fn_def,
+        => {
+            try transFnDecl(c, decl);
+        },
 
-            .@"var",
-            .static_var,
-            .threadlocal_var,
-            .threadlocal_static_var,
-            .extern_var,
-            .threadlocal_extern_var,
-            => {
-                try transVarDecl(c, node, null);
-            },
-            else => unreachable,
-        }
+        .@"var",
+        .extern_var,
+        .static_var,
+        .threadlocal_var,
+        .threadlocal_extern_var,
+        .threadlocal_static_var,
+        => {
+            try transVarDecl(c, decl, null);
+        },
+        else => unreachable,
     }
 }
 
 fn transTypeDef(_: *Context, _: *Scope, _: NodeIndex) Error!void {
     @panic("TODO");
 }
-fn transRecordDecl(_: *Context, _: *Scope, _: NodeIndex) Error!void {
-    @panic("TODO");
+
+fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 {
+    var cur_name = want_name;
+
+    if (!c.weak_global_names.contains(want_name)) {
+        // This type wasn't noticed by the name detection pass, so nothing has been treating this as
+        // a weak global name. We must mangle it to avoid conflicts with locals.
+        cur_name = try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ want_name, c.getMangle() });
+    }
+
+    while (c.global_names.contains(cur_name)) {
+        cur_name = try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ want_name, c.getMangle() });
+    }
+    return cur_name;
+}
+
+fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nodes: []const NodeIndex) Error!void {
+    const node_types = c.tree.nodes.items(.ty);
+    const raw_record_ty = node_types[@intFromEnum(record_node)];
+    const record_decl = raw_record_ty.getRecord().?;
+    if (c.decl_table.get(@intFromPtr(record_decl))) |_|
+        return; // Avoid processing this decl twice
+    const toplevel = scope.id == .root;
+    const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
+
+    const container_kind: ZigTag = if (raw_record_ty.is(.@"union")) .@"union" else .@"struct";
+    const container_kind_name: []const u8 = @tagName(container_kind);
+
+    var is_unnamed = false;
+    var bare_name: []const u8 = c.mapper.lookup(record_decl.name);
+    var name = bare_name;
+
+    if (c.unnamed_typedefs.get(@intFromPtr(record_decl))) |typedef_name| {
+        bare_name = typedef_name;
+        name = typedef_name;
+    } else {
+        if (raw_record_ty.isAnonymousRecord(c.comp)) {
+            bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
+            is_unnamed = true;
+        }
+        name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });
+        if (toplevel and !is_unnamed) {
+            name = try mangleWeakGlobalName(c, name);
+        }
+    }
+    if (!toplevel) name = try bs.makeMangledName(c, name);
+    try c.decl_table.putNoClobber(c.gpa, @intFromPtr(record_decl), name);
+
+    const is_pub = toplevel and !is_unnamed;
+    const init_node = blk: {
+        var fields = try std.ArrayList(ast.Payload.Record.Field).initCapacity(c.gpa, record_decl.fields.len);
+        defer fields.deinit();
+
+        // TODO: Add support for flexible array field functions
+        var functions = std.ArrayList(ZigNode).init(c.gpa);
+        defer functions.deinit();
+
+        var unnamed_field_count: u32 = 0;
+
+        // If a record doesn't have any attributes that would affect the alignment and
+        // layout, then we can just use a simple `extern` type. If it does have attributes,
+        // then we need to inspect the layout and assign an `align` value for each field.
+        const has_alignment_attributes = record_decl.field_attributes != null or
+            raw_record_ty.hasAttribute(.@"packed") or
+            raw_record_ty.hasAttribute(.aligned);
+        const head_field_alignment: ?c_uint = headFieldAlignment(record_decl);
+
+        // Iterate over field nodes so that we translate any type decls included in this record decl.
+        // TODO: Move this logic into `fn transType()` instead of handling decl translation here.
+        for (field_nodes) |field_node| {
+            const field_raw_ty = node_types[@intFromEnum(field_node)];
+            if (field_raw_ty.isEnumOrRecord()) try transDecl(c, scope, field_node);
+        }
+
+        for (record_decl.fields, 0..) |field, field_index| {
+            const field_loc = field.name_tok;
+
+            // Demote record to opaque if it contains a bitfield
+            if (!field.isRegularField()) {
+                try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl), {});
+                try warn(c, scope, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
+                break :blk ZigTag.opaque_literal.init();
+            }
+
+            var field_name = c.mapper.lookup(field.name);
+            if (!field.isNamed()) {
+                field_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{unnamed_field_count});
+                unnamed_field_count += 1;
+            }
+            const field_type = transType(c, scope, field.ty, .preserve_quals, field_loc) catch |err| switch (err) {
+                error.UnsupportedType => {
+                    try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl), {});
+                    try warn(c, scope, 0, "{s} demoted to opaque type - unable to translate type of field {s}", .{
+                        container_kind_name,
+                        field_name,
+                    });
+                    break :blk ZigTag.opaque_literal.init();
+                },
+                else => |e| return e,
+            };
+
+            const field_alignment = if (has_alignment_attributes)
+                alignmentForField(record_decl, head_field_alignment, field_index)
+            else
+                null;
+
+            // C99 introduced designated initializers for structs. Omitted fields are implicitly
+            // initialized to zero. Some C APIs are designed with this in mind. Defaulting to zero
+            // values for translated struct fields permits Zig code to comfortably use such an API.
+            const default_value = if (container_kind == .@"struct")
+                try ZigTag.std_mem_zeroes.create(c.arena, field_type)
+            else
+                null;
+
+            fields.appendAssumeCapacity(.{
+                .name = field_name,
+                .type = field_type,
+                .alignment = field_alignment,
+                .default_value = default_value,
+            });
+        }
+
+        const record_payload = try c.arena.create(ast.Payload.Record);
+        record_payload.* = .{
+            .base = .{ .tag = container_kind },
+            .data = .{
+                .layout = .@"extern",
+                .fields = try c.arena.dupe(ast.Payload.Record.Field, fields.items),
+                .functions = try c.arena.dupe(ZigNode, functions.items),
+                .variables = &.{},
+            },
+        };
+        break :blk ZigNode.initPayload(&record_payload.base);
+    };
+
+    const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
+    payload.* = .{
+        .base = .{ .tag = ([2]ZigTag{ .var_simple, .pub_var_simple })[@intFromBool(is_pub)] },
+        .data = .{
+            .name = name,
+            .init = init_node,
+        },
+    };
+    const node = ZigNode.initPayload(&payload.base);
+    if (toplevel) {
+        try addTopLevelDecl(c, name, node);
+        // Only add the alias if the name is available *and* it was caught by
+        // name detection. Don't bother performing a weak mangle, since a
+        // mangled name is of no real use here.
+        if (!is_unnamed and !c.global_names.contains(bare_name) and c.weak_global_names.contains(bare_name))
+            try c.alias_list.append(.{ .alias = bare_name, .name = name });
+    } else {
+        try scope.appendNode(node);
+        if (node.tag() != .pub_var_simple) {
+            try bs.discardVariable(c, name);
+        }
+    }
 }
 
 fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {
@@ -419,7 +598,7 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
                 enum_val_name = try bs.makeMangledName(c, enum_val_name);
             }
 
-            const enum_const_type_node: ?ZigNode = transType(c, scope, field.ty, field.name_tok) catch |err| switch (err) {
+            const enum_const_type_node: ?ZigNode = transType(c, scope, field.ty, .standard, field.name_tok) catch |err| switch (err) {
                 error.UnsupportedType => null,
                 else => |e| return e,
             };
@@ -439,7 +618,7 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
             }
         }
 
-        break :blk transType(c, scope, ty.data.@"enum".tag_ty, 0) catch |err| switch (err) {
+        break :blk transType(c, scope, ty.data.@"enum".tag_ty, .standard, 0) catch |err| switch (err) {
             error.UnsupportedType => {
                 return failDecl(c, 0, name, "unable to translate enum integer type", .{});
             },
@@ -472,8 +651,8 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
     }
 }
 
-fn transType(c: *Context, scope: *Scope, raw_ty: Type, source_loc: TokenIndex) TypeError!ZigNode {
-    const ty = raw_ty.canonicalize(.standard);
+fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode {
+    const ty = raw_ty.canonicalize(qual_handling);
     switch (ty.specifier) {
         .void => return ZigTag.type.create(c.arena, "anyopaque"),
         .bool => return ZigTag.type.create(c.arena, "bool"),
@@ -496,16 +675,152 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, source_loc: TokenIndex) T
         .long_double => return ZigTag.type.create(c.arena, "c_longdouble"),
         .float80 => return ZigTag.type.create(c.arena, "f80"),
         .float128 => return ZigTag.type.create(c.arena, "f128"),
+        .@"enum" => @panic("TODO"),
+        .pointer,
+        .unspecified_variable_len_array,
+        .array,
+        .static_array,
+        .incomplete_array,
+        => @panic("TODO"),
         .func,
         .var_args_func,
         .old_style_func,
-        => return transFnType(c, scope, raw_ty, ty, source_loc, .{}),
+        => return transFnType(c, scope, ty, ty, source_loc, .{}),
+        .@"struct",
+        .@"union",
+        => {
+            var trans_scope = scope;
+            if (ty.isAnonymousRecord(c.comp)) {
+                const record_decl = ty.data.record;
+                const name_id = c.mapper.lookup(record_decl.name);
+                if (c.weak_global_names.contains(name_id)) trans_scope = &c.global_scope.base;
+            }
+            const name = c.decl_table.get(@intFromPtr(ty.data.record)).?;
+            return ZigTag.identifier.create(c.arena, name);
+        },
+        .attributed,
+        .typeof_type,
+        .typeof_expr,
+        => unreachable,
         else => return error.UnsupportedType,
     }
 }
 
-fn zigAlignment(bit_alignment: u29) u32 {
-    return bit_alignment / 8;
+/// Look ahead through the fields of the record to determine what the alignment of the record
+/// would be without any align/packed/etc. attributes. This helps us determine whether or not
+/// the fields with 0 offset need an `align` qualifier. Strictly speaking, we could just
+/// pedantically assign those fields the same alignment as the parent's pointer alignment,
+/// but this helps the generated code to be a little less verbose.
+fn headFieldAlignment(record_decl: *const Type.Record) ?c_uint {
+    const bits_per_byte = 8;
+    const parent_ptr_alignment_bits = record_decl.type_layout.pointer_alignment_bits;
+    const parent_ptr_alignment = parent_ptr_alignment_bits / bits_per_byte;
+    var max_field_alignment_bits: u64 = 0;
+    for (record_decl.fields) |field| {
+        if (field.ty.getRecord()) |field_record_decl| {
+            const child_record_alignment = field_record_decl.type_layout.field_alignment_bits;
+            if (child_record_alignment > max_field_alignment_bits)
+                max_field_alignment_bits = child_record_alignment;
+        } else {
+            const field_size = field.layout.size_bits;
+            if (field_size > max_field_alignment_bits)
+                max_field_alignment_bits = field_size;
+        }
+    }
+    if (max_field_alignment_bits != parent_ptr_alignment_bits) {
+        return parent_ptr_alignment;
+    } else {
+        return null;
+    }
+}
+
+/// This function returns a ?c_uint to match Clang's behaviour of using c_uint.
+/// This can be changed to a u29 after the Clang frontend for translate-c is removed.
+fn alignmentForField(
+    record_decl: *const Type.Record,
+    head_field_alignment: ?c_uint,
+    field_index: usize,
+) ?c_uint {
+    const fields = record_decl.fields;
+    assert(fields.len != 0);
+    const field = fields[field_index];
+
+    const bits_per_byte = 8;
+    const parent_ptr_alignment_bits = record_decl.type_layout.pointer_alignment_bits;
+    const parent_ptr_alignment = parent_ptr_alignment_bits / bits_per_byte;
+
+    // bitfields aren't supported yet. Until support is added, records with bitfields
+    // should be demoted to opaque, and this function shouldn't be called for them.
+    if (!field.isRegularField()) {
+        @panic("TODO: add bitfield support for records");
+    }
+
+    const field_offset_bits: u64 = field.layout.offset_bits;
+    const field_size_bits: u64 = field.layout.size_bits;
+
+    // Fields with zero width always have an alignment of 1
+    if (field_size_bits == 0) {
+        return 1;
+    }
+
+    // Fields with 0 offset inherit the parent's pointer alignment.
+    if (field_offset_bits == 0) {
+        return head_field_alignment;
+    }
+
+    // Records have a natural alignment when used as a field, and their size is
+    // a multiple of this alignment value. For all other types, the natural alignment
+    // is their size.
+    const field_natural_alignment_bits: u64 = if (field.ty.getRecord()) |record| record.type_layout.field_alignment_bits else field_size_bits;
+    const rem_bits = field_offset_bits % field_natural_alignment_bits;
+
+    // If there's a remainder, then the alignment is smaller than the field's
+    // natural alignment
+    if (rem_bits > 0) {
+        const rem_alignment = rem_bits / bits_per_byte;
+        if (rem_alignment > 0 and std.math.isPowerOfTwo(rem_alignment)) {
+            const actual_alignment = @min(rem_alignment, parent_ptr_alignment);
+            return @as(c_uint, @truncate(actual_alignment));
+        } else {
+            return 1;
+        }
+    }
+
+    // A field may have an offset which positions it to be naturally aligned, but the
+    // parent's pointer alignment determines if this is actually true, so we take the minimum
+    // value.
+    // For example, a float field (4 bytes wide) with a 4 byte offset is positioned to have natural
+    // alignment, but if the parent pointer alignment is 2, then the actual alignment of the
+    // float is 2.
+    const field_natural_alignment: u64 = field_natural_alignment_bits / bits_per_byte;
+    const offset_alignment = field_offset_bits / bits_per_byte;
+    const possible_alignment = @min(parent_ptr_alignment, offset_alignment);
+    if (possible_alignment == field_natural_alignment) {
+        return null;
+    } else if (possible_alignment < field_natural_alignment) {
+        if (std.math.isPowerOfTwo(possible_alignment)) {
+            return possible_alignment;
+        } else {
+            return 1;
+        }
+    } else { // possible_alignment > field_natural_alignment
+        // Here, the field is positioned be at a higher alignment than it's natural alignment. This means we
+        // need to determine whether it's a specified alignment. We can determine that from the padding preceding
+        // the field.
+        const padding_from_prev_field: u64 = blk: {
+            if (field_offset_bits != 0) {
+                const previous_field = fields[field_index - 1];
+                break :blk (field_offset_bits - previous_field.layout.offset_bits) - previous_field.layout.size_bits;
+            } else {
+                break :blk 0;
+            }
+        };
+        if (padding_from_prev_field < field_natural_alignment_bits) {
+            return null;
+        } else {
+            return possible_alignment;
+        }
+    }
 }
 
 const FnProtoContext = struct {
@@ -536,7 +851,7 @@ fn transFnType(
         else
             c.mapper.lookup(param_info.name);
 
-        const type_node = try transType(c, scope, param_ty, param_info.name_tok);
+        const type_node = try transType(c, scope, param_ty, .standard, param_info.name_tok);
         param_node.* = .{
             .is_noalias = is_noalias,
             .name = param_name,
@@ -551,7 +866,7 @@ fn transFnType(
         break :blk null;
     };
 
-    const alignment = if (raw_ty.requestedAlignment(c.comp)) |alignment| zigAlignment(alignment) else null;
+    const alignment: ?c_uint = raw_ty.requestedAlignment(c.comp) orelse null;
 
     const explicit_callconv = null;
     // const explicit_callconv = if ((ctx.is_inline or ctx.is_export or ctx.is_extern) and ctx.cc == .C) null else ctx.cc;
@@ -565,7 +880,7 @@ fn transFnType(
                 // convert primitive anyopaque to actual void (only for return type)
                 break :blk ZigTag.void_type.init();
             } else {
-                break :blk transType(c, scope, return_ty, source_loc) catch |err| switch (err) {
+                break :blk transType(c, scope, return_ty, .standard, source_loc) catch |err| switch (err) {
                     error.UnsupportedType => {
                         try warn(c, scope, source_loc, "unsupported function proto return type", .{});
                         return err;
@@ -642,7 +957,7 @@ fn transExpr(c: *Context, node: NodeIndex, result_used: ResultUsed) TransError!Z
         // TODO handle other values
         const int = try transCreateNodeAPInt(c, val);
         const as_node = try ZigTag.as.create(c.arena, .{
-            .lhs = try transType(c, undefined, ty, undefined),
+            .lhs = try transType(c, undefined, ty, .standard, undefined),
             .rhs = int,
         });
         return maybeSuppressResult(c, result_used, as_node);
test/cases/translate_c/circular_struct_definitions.c
@@ -0,0 +1,20 @@
+struct Bar;
+
+struct Foo {
+    struct Bar *next;
+};
+
+struct Bar {
+    struct Foo *next;
+};
+
+// translate-c
+// c_frontend=clang
+//
+// pub const struct_Bar = extern struct {
+//     next: [*c]struct_Foo = @import("std").mem.zeroes([*c]struct_Foo),
+// };
+// 
+// pub const struct_Foo = extern struct {
+//     next: [*c]struct_Bar = @import("std").mem.zeroes([*c]struct_Bar),
+// };
test/cases/translate_c/double_define_struct.c
@@ -0,0 +1,25 @@
+typedef struct Bar Bar;
+typedef struct Foo Foo;
+
+struct Foo {
+    Foo *a;
+};
+
+struct Bar {
+    Foo *a;
+};
+
+// translate-c
+// c_frontend=clang
+//
+// pub const struct_Foo = extern struct {
+//     a: [*c]Foo = @import("std").mem.zeroes([*c]Foo),
+// };
+// 
+// pub const Foo = struct_Foo;
+// 
+// pub const struct_Bar = extern struct {
+//     a: [*c]Foo = @import("std").mem.zeroes([*c]Foo),
+// };
+// 
+// pub const Bar = struct_Bar;
test/cases/translate_c/field_access_is_grouped_if_necessary.c
@@ -0,0 +1,18 @@
+unsigned long foo(unsigned long x) {
+    return ((union{unsigned long _x}){x})._x;
+}
+
+// translate-c
+// c_frontend=clang
+//
+// pub export fn foo(arg_x: c_ulong) c_ulong {
+//     var x = arg_x;
+//     _ = &x;
+//     const union_unnamed_1 = extern union {
+//         _x: c_ulong,
+//     };
+//     _ = &union_unnamed_1;
+//     return (union_unnamed_1{
+//         ._x = x,
+//     })._x;
+// }
test/cases/translate_c/global_struct_whose_default_name_conflicts_with_global_is_mangled.c
@@ -0,0 +1,15 @@
+struct foo {
+    int x;
+};
+const char *struct_foo = "hello world";
+
+// translate-c
+// c_frontend=clang
+//
+// pub const struct_foo_1 = extern struct {
+//     x: c_int = @import("std").mem.zeroes(c_int),
+// };
+// 
+// pub const foo = struct_foo_1;
+// 
+// pub export var struct_foo: [*c]const u8 = "hello world";
test/cases/translate_c/large_packed_struct.c
@@ -0,0 +1,20 @@
+struct __attribute__((packed)) bar {
+  short a;
+  float b;
+  double c;
+  short x;
+  float y;
+  double z;
+};
+
+// translate-c
+// c_frontend=aro,clang
+//
+// pub const struct_bar = extern struct {
+//     a: c_short align(1) = @import("std").mem.zeroes(c_short),
+//     b: f32 align(1) = @import("std").mem.zeroes(f32),
+//     c: f64 align(1) = @import("std").mem.zeroes(f64),
+//     x: c_short align(1) = @import("std").mem.zeroes(c_short),
+//     y: f32 align(1) = @import("std").mem.zeroes(f32),
+//     z: f64 align(1) = @import("std").mem.zeroes(f64),
+// };
test/cases/translate_c/packed_union_nested_unpacked.c
@@ -0,0 +1,25 @@
+// NOTE: The nested struct is *not* packed/aligned,
+// even though the parent struct is
+// this is consistent with GCC docs
+union Foo{
+  short x;
+  double y;
+  struct {
+      int b;
+  } z;
+} __attribute__((packed));
+
+// translate-c
+// c_frontend=aro,clang
+//
+// const struct_unnamed_1 = extern struct {
+//     b: c_int = @import("std").mem.zeroes(c_int),
+// };
+// 
+// pub const union_Foo = extern union {
+//     x: c_short align(1),
+//     y: f64 align(1),
+//     z: struct_unnamed_1 align(1),
+// };
+// 
+// pub const Foo = union_Foo;
test/cases/translate_c/packed_union_simple.c
@@ -0,0 +1,14 @@
+union Foo {
+  short x;
+  double y;
+} __attribute__((packed));
+
+// translate-c
+// c_frontend=aro,clang
+//
+// pub const union_Foo = extern union {
+//     x: c_short align(1),
+//     y: f64 align(1),
+// };
+// 
+// pub const Foo = union_Foo;
test/cases/translate_c/pointer_to_struct_demoted_opaque_due_to_bit_fields.c
@@ -0,0 +1,15 @@
+struct Foo {
+    unsigned int: 1;
+};
+struct Bar {
+    struct Foo *foo;
+};
+
+// translate-c
+// c_frontend=clang
+//
+// pub const struct_Foo = opaque {};
+// 
+// pub const struct_Bar = extern struct {
+//     foo: ?*struct_Foo = @import("std").mem.zeroes(?*struct_Foo),
+// };
test/cases/translate_c/qualified_struct_and_enum.c
@@ -0,0 +1,25 @@
+struct Foo {
+    int x;
+    int y;
+};
+enum Bar {
+    BarA,
+    BarB,
+};
+void func(struct Foo *a, enum Bar **b);
+
+// translate-c
+// c_frontend=clang
+// target=x86_64-linux,x86_64-macos
+//
+// pub const struct_Foo = extern struct {
+//     x: c_int = @import("std").mem.zeroes(c_int),
+//     y: c_int = @import("std").mem.zeroes(c_int),
+// };
+// pub const BarA: c_int = 0;
+// pub const BarB: c_int = 1;
+// pub const enum_Bar = c_uint;
+// pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
+//
+// pub const Foo = struct_Foo;
+// pub const Bar = enum_Bar;
test/cases/translate_c/qualified_struct_and_enum_msvc.c
@@ -0,0 +1,25 @@
+struct Foo {
+    int x;
+    int y;
+};
+enum Bar {
+    BarA,
+    BarB,
+};
+void func(struct Foo *a, enum Bar **b);
+
+// translate-c
+// c_frontend=clang
+// target=x86_64-windows-msvc
+//
+// pub const struct_Foo = extern struct {
+//     x: c_int = @import("std").mem.zeroes(c_int),
+//     y: c_int = @import("std").mem.zeroes(c_int),
+// };
+// pub const BarA: c_int = 0;
+// pub const BarB: c_int = 1;
+// pub const enum_Bar = c_int;
+// pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
+//
+// pub const Foo = struct_Foo;
+// pub const Bar = enum_Bar;
test/cases/translate_c/scoped_record.c
@@ -0,0 +1,49 @@
+void foo() {
+	struct Foo {
+		int A;
+		int B;
+		int C;
+	};
+	struct Foo a = {0};
+	{
+		struct Foo {
+			int A;
+			int B;
+			int C;
+		};
+		struct Foo a = {0};
+	}
+}
+
+// translate-c
+// c_frontend=clang
+//
+// pub export fn foo() void {
+//     const struct_Foo = extern struct {
+//         A: c_int = @import("std").mem.zeroes(c_int),
+//         B: c_int = @import("std").mem.zeroes(c_int),
+//         C: c_int = @import("std").mem.zeroes(c_int),
+//     };
+//     _ = &struct_Foo;
+//     var a: struct_Foo = struct_Foo{
+//         .A = @as(c_int, 0),
+//         .B = 0,
+//         .C = 0,
+//     };
+//     _ = &a;
+//     {
+//         const struct_Foo_1 = extern struct {
+//             A: c_int = @import("std").mem.zeroes(c_int),
+//             B: c_int = @import("std").mem.zeroes(c_int),
+//             C: c_int = @import("std").mem.zeroes(c_int),
+//         };
+//         _ = &struct_Foo_1;
+//         var a_2: struct_Foo_1 = struct_Foo_1{
+//             .A = @as(c_int, 0),
+//             .B = 0,
+//             .C = 0,
+//         };
+//         _ = &a_2;
+//     }
+// }
+
test/cases/translate_c/simple_struct.c
@@ -0,0 +1,12 @@
+struct Foo {
+    int x;
+};
+
+// translate-c
+// c_frontend=aro,clang
+//
+// const struct_Foo = extern struct {
+//     x: c_int = @import("std").mem.zeroes(c_int),
+// };
+// 
+// pub const Foo = struct_Foo;
test/cases/translate_c/simple_union.c
@@ -0,0 +1,12 @@
+union Foo {
+    int x;
+};
+
+// translate-c
+// c_frontend=aro,clang
+//
+// pub const union_Foo = extern union {
+//     x: c_int,
+// };
+// 
+// pub const Foo = union_Foo;
test/cases/translate_c/struct_in_struct_init_to_zero.c
@@ -0,0 +1,24 @@
+struct Foo {
+    int a;
+    struct Bar {
+        int a;
+    } b;
+} a = {};
+#define PTR void *
+
+// translate-c
+// c_frontend=clang
+//
+// pub const struct_Bar_1 = extern struct {
+//     a: c_int = @import("std").mem.zeroes(c_int),
+// };
+// pub const struct_Foo = extern struct {
+//     a: c_int = @import("std").mem.zeroes(c_int),
+//     b: struct_Bar_1 = @import("std").mem.zeroes(struct_Bar_1),
+// };
+// pub export var a: struct_Foo = struct_Foo{
+//     .a = 0,
+//     .b = @import("std").mem.zeroes(struct_Bar_1),
+// };
+// 
+// pub const PTR = ?*anyopaque;
test/cases/translate_c/struct_with_aligned_fields.c
@@ -0,0 +1,10 @@
+struct foo {
+    __attribute__((aligned(4))) short bar;
+};
+
+// translate-c
+// c_frontend=aro,clang
+// 
+// pub const struct_foo = extern struct {
+//     bar: c_short align(4) = @import("std").mem.zeroes(c_short),
+// };
test/cases/translate_c/struct_with_invalid_field_alignment.c
@@ -0,0 +1,35 @@
+// The aligned attribute cannot decrease the alignment of a field. The packed attribute is required 
+// for decreasing the alignment. gcc and clang will compile these structs without error 
+// (and possibly without warning), but checking the alignment will reveal a different value than 
+// what was requested. This is consistent with the gcc documentation on type attributes.
+//
+// This test is currently broken for the clang frontend. See issue #19307.
+
+struct foo {
+  __attribute__((aligned(1)))int x;
+};
+
+struct bar {
+  __attribute__((aligned(2)))float y;
+};
+
+struct baz {
+  __attribute__((aligned(4)))double z;
+};
+
+// translate-c
+// c_frontend=aro
+// target=x86_64-linux
+//
+// pub const struct_foo = extern struct {
+//     x: c_int = @import("std").mem.zeroes(c_int),
+// };
+//
+// pub const struct_bar = extern struct {
+//     y: f32 = @import("std").mem.zeroes(f32),
+// };
+//
+// pub const struct_baz = extern struct {
+//     z: f64 = @import("std").mem.zeroes(f64),
+// };
+//
test/cases/translate_c/type_referenced_struct.c
@@ -0,0 +1,19 @@
+// When clang uses the <arch>-windows-none, triple it behaves as MSVC and
+// interprets the inner `struct Bar` as an anonymous structure
+struct Foo {
+    struct Bar{
+        int b;
+    };
+    struct Bar c;
+};
+
+// translate-c
+// c_frontend=aro,clang
+// target=x86_64-linux-gnu
+//
+// pub const struct_Bar_1 = extern struct {
+//     b: c_int = @import("std").mem.zeroes(c_int),
+// };
+// pub const struct_Foo = extern struct {
+//     c: struct_Bar_1 = @import("std").mem.zeroes(struct_Bar_1),
+// };
test/cases/translate_c/union_initializer.c
@@ -0,0 +1,22 @@
+union { int x; char c[4]; }
+  ua = {1},
+  ub = {.c={'a','b','b','a'}};
+
+// translate-c
+// c_frontend=clang
+//
+// const union_unnamed_1 = extern union {
+//     x: c_int,
+//     c: [4]u8,
+// };
+// pub export var ua: union_unnamed_1 = union_unnamed_1{
+//     .x = @as(c_int, 1),
+// };
+// pub export var ub: union_unnamed_1 = union_unnamed_1{
+//     .c = [4]u8{
+//         'a',
+//         'b',
+//         'b',
+//         'a',
+//     },
+// };
test/cases/translate_c/union_struct_forward_decl.c
@@ -0,0 +1,37 @@
+struct A;
+union B;
+enum C;
+
+struct A {
+  short x;
+  double y;
+};
+
+union B {
+  short x;
+  double y;
+};
+
+struct Foo {
+  struct A a;
+  union B b;
+};
+
+
+// translate-c
+// c_frontend=aro,clang
+//
+// pub const struct_A = extern struct {
+//     x: c_short = @import("std").mem.zeroes(c_short),
+//     y: f64 = @import("std").mem.zeroes(f64),
+// };
+//
+// pub const union_B = extern union {
+//     x: c_short,
+//     y: f64,
+// };
+// 
+// pub const struct_Foo = extern struct {
+//     a: struct_A = @import("std").mem.zeroes(struct_A),
+//     b: union_B = @import("std").mem.zeroes(union_B),
+// };
test/cases/translate_c/unnamed_fields_have_predictable_names.c
@@ -0,0 +1,22 @@
+struct a {
+    struct { int x; };
+};
+struct b {
+    struct { int y; };
+};
+
+// translate-c
+// c_frontend=aro,clang
+//
+// const struct_unnamed_1 = extern struct {
+//     x: c_int = @import("std").mem.zeroes(c_int),
+// };
+// pub const struct_a = extern struct {
+//     unnamed_0: struct_unnamed_1 = @import("std").mem.zeroes(struct_unnamed_1),
+// };
+// const struct_unnamed_2 = extern struct {
+//     y: c_int = @import("std").mem.zeroes(c_int),
+// };
+// pub const struct_b = extern struct {
+//     unnamed_0: struct_unnamed_2 = @import("std").mem.zeroes(struct_unnamed_2),
+// };
test/cases/translate_c/zero_width_field_alignment.c
@@ -0,0 +1,18 @@
+struct __attribute__((packed)) foo {
+  int x;
+  struct {};
+  float y;
+  union {};
+};
+
+// translate-c
+// c_frontend=aro
+//
+// const struct_unnamed_1 = extern struct {};
+// const union_unnamed_2 = extern union {};
+// pub const struct_foo = extern struct {
+//     x: c_int align(1) = @import("std").mem.zeroes(c_int),
+//     unnamed_0: struct_unnamed_1 align(1) = @import("std").mem.zeroes(struct_unnamed_1),
+//     y: f32 align(1) = @import("std").mem.zeroes(f32),
+//     unnamed_1: union_unnamed_2 align(1) = @import("std").mem.zeroes(union_unnamed_2),
+// };
test/cases/translate_c/zig_keywords_in_c_code.c
@@ -0,0 +1,12 @@
+struct comptime {
+    int defer;
+};
+
+// translate-c
+// c_frontend=aro,clang
+//
+// pub const struct_comptime = extern struct {
+//     @"defer": c_int = @import("std").mem.zeroes(c_int),
+// };
+// 
+// pub const @"comptime" = struct_comptime;
test/translate_c.zig
@@ -74,24 +74,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub extern fn main() c_int;
     });
 
-    cases.add("field access is grouped if necessary",
-        \\unsigned long foo(unsigned long x) {
-        \\    return ((union{unsigned long _x}){x})._x;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo(arg_x: c_ulong) c_ulong {
-        \\    var x = arg_x;
-        \\    _ = &x;
-        \\    const union_unnamed_1 = extern union {
-        \\        _x: c_ulong,
-        \\    };
-        \\    _ = &union_unnamed_1;
-        \\    return (union_unnamed_1{
-        \\        ._x = x,
-        \\    })._x;
-        \\}
-    });
-
     cases.add("unnamed child types of typedef receive typedef's name",
         \\typedef enum {
         \\    FooA,
@@ -149,78 +131,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("struct in struct init to zero",
-        \\struct Foo {
-        \\    int a;
-        \\    struct Bar {
-        \\        int a;
-        \\    } b;
-        \\} a = {};
-        \\#define PTR void *
-    , &[_][]const u8{
-        \\pub const struct_Bar_1 = extern struct {
-        \\    a: c_int = @import("std").mem.zeroes(c_int),
-        \\};
-        \\pub const struct_Foo = extern struct {
-        \\    a: c_int = @import("std").mem.zeroes(c_int),
-        \\    b: struct_Bar_1 = @import("std").mem.zeroes(struct_Bar_1),
-        \\};
-        \\pub export var a: struct_Foo = struct_Foo{
-        \\    .a = 0,
-        \\    .b = @import("std").mem.zeroes(struct_Bar_1),
-        \\};
-        ,
-        \\pub const PTR = ?*anyopaque;
-    });
-
-    cases.add("scoped record",
-        \\void foo() {
-        \\	struct Foo {
-        \\		int A;
-        \\		int B;
-        \\		int C;
-        \\	};
-        \\	struct Foo a = {0};
-        \\	{
-        \\		struct Foo {
-        \\			int A;
-        \\			int B;
-        \\			int C;
-        \\		};
-        \\		struct Foo a = {0};
-        \\	}
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo() void {
-        \\    const struct_Foo = extern struct {
-        \\        A: c_int = @import("std").mem.zeroes(c_int),
-        \\        B: c_int = @import("std").mem.zeroes(c_int),
-        \\        C: c_int = @import("std").mem.zeroes(c_int),
-        \\    };
-        \\    _ = &struct_Foo;
-        \\    var a: struct_Foo = struct_Foo{
-        \\        .A = @as(c_int, 0),
-        \\        .B = 0,
-        \\        .C = 0,
-        \\    };
-        \\    _ = &a;
-        \\    {
-        \\        const struct_Foo_1 = extern struct {
-        \\            A: c_int = @import("std").mem.zeroes(c_int),
-        \\            B: c_int = @import("std").mem.zeroes(c_int),
-        \\            C: c_int = @import("std").mem.zeroes(c_int),
-        \\        };
-        \\        _ = &struct_Foo_1;
-        \\        var a_2: struct_Foo_1 = struct_Foo_1{
-        \\            .A = @as(c_int, 0),
-        \\            .B = 0,
-        \\            .C = 0,
-        \\        };
-        \\        _ = &a_2;
-        \\    }
-        \\}
-    });
-
     cases.add("scoped typedef",
         \\void foo() {
         \\	typedef union {
@@ -466,16 +376,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const BAR = (@as(c_int, 1) != 0) and (@as(c_int, 2) > @as(c_int, 4));
     });
 
-    cases.add("struct with aligned fields",
-        \\struct foo {
-        \\    __attribute__((aligned(1))) short bar;
-        \\};
-    , &[_][]const u8{
-        \\pub const struct_foo = extern struct {
-        \\    bar: c_short align(1) = @import("std").mem.zeroes(c_short),
-        \\};
-    });
-
     cases.add("struct with flexible array",
         \\struct foo { int x; int y[]; };
         \\struct bar { int x; int y[0]; };
@@ -661,28 +561,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("union initializer",
-        \\union { int x; char c[4]; }
-        \\  ua = {1},
-        \\  ub = {.c={'a','b','b','a'}};
-    , &[_][]const u8{
-        \\const union_unnamed_1 = extern union {
-        \\    x: c_int,
-        \\    c: [4]u8,
-        \\};
-        \\pub export var ua: union_unnamed_1 = union_unnamed_1{
-        \\    .x = @as(c_int, 1),
-        \\};
-        \\pub export var ub: union_unnamed_1 = union_unnamed_1{
-        \\    .c = [4]u8{
-        \\        'a',
-        \\        'b',
-        \\        'b',
-        \\        'a',
-        \\    },
-        \\};
-    });
-
     cases.add("struct initializer - simple",
         \\typedef struct { int x; } foo;
         \\struct {double x,y,z;} s0 = {1.2, 1.3};
@@ -992,21 +870,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\};
     });
 
-    cases.add("pointer to struct demoted to opaque due to bit fields",
-        \\struct Foo {
-        \\    unsigned int: 1;
-        \\};
-        \\struct Bar {
-        \\    struct Foo *foo;
-        \\};
-    , &[_][]const u8{
-        \\pub const struct_Foo = opaque {};
-        ,
-        \\pub const struct_Bar = extern struct {
-        \\    foo: ?*struct_Foo = @import("std").mem.zeroes(?*struct_Foo),
-        \\};
-    });
-
     cases.add("macro with left shift",
         \\#define REDISMODULE_READ (1<<0)
     , &[_][]const u8{
@@ -1022,45 +885,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const FLASH_BANK_SIZE = FLASH_SIZE >> @as(c_int, 1);
     });
 
-    cases.add("double define struct",
-        \\typedef struct Bar Bar;
-        \\typedef struct Foo Foo;
-        \\
-        \\struct Foo {
-        \\    Foo *a;
-        \\};
-        \\
-        \\struct Bar {
-        \\    Foo *a;
-        \\};
-    , &[_][]const u8{
-        \\pub const struct_Foo = extern struct {
-        \\    a: [*c]Foo = @import("std").mem.zeroes([*c]Foo),
-        \\};
-        ,
-        \\pub const Foo = struct_Foo;
-        ,
-        \\pub const struct_Bar = extern struct {
-        \\    a: [*c]Foo = @import("std").mem.zeroes([*c]Foo),
-        \\};
-        ,
-        \\pub const Bar = struct_Bar;
-    });
-
-    cases.add("simple struct",
-        \\struct Foo {
-        \\    int x;
-        \\    char *y;
-        \\};
-    , &[_][]const u8{
-        \\const struct_Foo = extern struct {
-        \\    x: c_int = @import("std").mem.zeroes(c_int),
-        \\    y: [*c]u8 = @import("std").mem.zeroes([*c]u8),
-        \\};
-        ,
-        \\pub const Foo = struct_Foo;
-    });
-
     cases.add("self referential struct with function pointer",
         \\struct Foo {
         \\    void (*derp)(struct Foo *foo);
@@ -1099,44 +923,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const THING2 = THING1;
     });
 
-    cases.add("circular struct definitions",
-        \\struct Bar;
-        \\
-        \\struct Foo {
-        \\    struct Bar *next;
-        \\};
-        \\
-        \\struct Bar {
-        \\    struct Foo *next;
-        \\};
-    , &[_][]const u8{
-        \\pub const struct_Bar = extern struct {
-        \\    next: [*c]struct_Foo = @import("std").mem.zeroes([*c]struct_Foo),
-        \\};
-        ,
-        \\pub const struct_Foo = extern struct {
-        \\    next: [*c]struct_Bar = @import("std").mem.zeroes([*c]struct_Bar),
-        \\};
-    });
-
     cases.add("#define string",
         \\#define  foo  "a string"
     , &[_][]const u8{
         \\pub const foo = "a string";
     });
 
-    cases.add("zig keywords in C code",
-        \\struct comptime {
-        \\    int defer;
-        \\};
-    , &[_][]const u8{
-        \\pub const struct_comptime = extern struct {
-        \\    @"defer": c_int = @import("std").mem.zeroes(c_int),
-        \\};
-        ,
-        \\pub const @"comptime" = struct_comptime;
-    });
-
     cases.add("macro with parens around negative number",
         \\#define LUA_GLOBALSINDEX        (-10002)
     , &[_][]const u8{
@@ -1393,88 +1185,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("simple union",
-        \\union Foo {
-        \\    int x;
-        \\    double y;
-        \\};
-    , &[_][]const u8{
-        \\pub const union_Foo = extern union {
-        \\    x: c_int,
-        \\    y: f64,
-        \\};
-        ,
-        \\pub const Foo = union_Foo;
-    });
-
-    cases.add("packed union - simple",
-        \\union Foo {
-        \\  char x;
-        \\  double y;
-        \\} __attribute__((packed));
-    , &[_][]const u8{
-        \\pub const union_Foo = extern union {
-        \\    x: u8 align(1),
-        \\    y: f64 align(1),
-        \\};
-        ,
-        \\pub const Foo = union_Foo;
-    });
-
-    cases.add("packed union - nested unpacked",
-        \\union Foo{
-        \\  char x;
-        \\  double y;
-        \\  struct {
-        \\      char a;
-        \\      int b;
-        \\  } z;
-        \\} __attribute__((packed));
-    , &[_][]const u8{
-        // NOTE: The nested struct is *not* packed/aligned,
-        // even though the parent struct is
-        // this is consistent with GCC docs
-        \\const struct_unnamed_1 = extern struct {
-        \\    a: u8 = @import("std").mem.zeroes(u8),
-        \\    b: c_int = @import("std").mem.zeroes(c_int),
-        \\};
-        ,
-        \\pub const union_Foo = extern union {
-        \\    x: u8 align(1),
-        \\    y: f64 align(1),
-        \\    z: struct_unnamed_1 align(1),
-        \\};
-        ,
-        \\pub const Foo = union_Foo;
-    });
-
-    cases.add("packed union - nested packed",
-        \\union Foo{
-        \\  char x;
-        \\  double y;
-        \\  struct {
-        \\      char a;
-        \\      int b;
-        \\  } __attribute__((packed)) z;
-        \\} __attribute__((packed));
-    , &[_][]const u8{
-        // in order for the nested struct to be packed, it must
-        // have an independent packed declaration on
-        // the nested type (see GCC docs for details)
-        \\const struct_unnamed_1 = extern struct {
-        \\    a: u8 align(1) = @import("std").mem.zeroes(u8),
-        \\    b: c_int align(1) = @import("std").mem.zeroes(c_int),
-        \\};
-        ,
-        \\pub const union_Foo = extern union {
-        \\    x: u8 align(1),
-        \\    y: f64 align(1),
-        \\    z: struct_unnamed_1 align(1),
-        \\};
-        ,
-        \\pub const Foo = union_Foo;
-    });
-
     cases.add("string literal",
         \\const char *foo(void) {
         \\    return "bar";
@@ -2395,27 +2105,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    }
         \\}
     });
-
-    if (builtin.os.tag != .windows) {
-        // When clang uses the <arch>-windows-none triple it behaves as MSVC and
-        // interprets the inner `struct Bar` as an anonymous structure
-        cases.add("type referenced struct",
-            \\struct Foo {
-            \\    struct Bar{
-            \\        int b;
-            \\    };
-            \\    struct Bar c;
-            \\};
-        , &[_][]const u8{
-            \\pub const struct_Bar_1 = extern struct {
-            \\    b: c_int = @import("std").mem.zeroes(c_int),
-            \\};
-            \\pub const struct_Foo = extern struct {
-            \\    c: struct_Bar_1 = @import("std").mem.zeroes(struct_Bar_1),
-            \\};
-        });
-    }
-
     cases.add("undefined array global",
         \\int array[100] = {};
     , &[_][]const u8{
@@ -2634,32 +2323,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const Foo = enum_Foo;
     });
 
-    cases.add("qualified struct and enum",
-        \\struct Foo {
-        \\    int x;
-        \\    int y;
-        \\};
-        \\enum Bar {
-        \\    BarA,
-        \\    BarB,
-        \\};
-        \\void func(struct Foo *a, enum Bar **b);
-    , &[_][]const u8{
-        \\pub const struct_Foo = extern struct {
-        \\    x: c_int = @import("std").mem.zeroes(c_int),
-        \\    y: c_int = @import("std").mem.zeroes(c_int),
-        \\};
-        \\pub const BarA: c_int = 0;
-        \\pub const BarB: c_int = 1;
-        \\pub const enum_Bar =
-        ++ " " ++ default_enum_type ++
-            \\;
-            \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
-        ,
-        \\pub const Foo = struct_Foo;
-        \\pub const Bar = enum_Bar;
-    });
-
     cases.add("bitwise binary operators, simpler parens",
         \\int max(int a, int b) {
         \\    return (a & b) ^ (a | b);
@@ -3756,24 +3419,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         });
     }
 
-    cases.add("unnamed fields have predictable names",
-        \\struct a {
-        \\    struct {};
-        \\};
-        \\struct b {
-        \\    struct {};
-        \\};
-    , &[_][]const u8{
-        \\const struct_unnamed_1 = extern struct {};
-        \\pub const struct_a = extern struct {
-        \\    unnamed_0: struct_unnamed_1 = @import("std").mem.zeroes(struct_unnamed_1),
-        \\};
-        \\const struct_unnamed_2 = extern struct {};
-        \\pub const struct_b = extern struct {
-        \\    unnamed_0: struct_unnamed_2 = @import("std").mem.zeroes(struct_unnamed_2),
-        \\};
-    });
-
     cases.add("integer literal promotion",
         \\#define GUARANTEED_TO_FIT_1 1024
         \\#define GUARANTEED_TO_FIT_2 10241024L
@@ -4283,21 +3928,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const FOO = @compileError("unable to translate macro: untranslatable usage of arg `x`");
     });
 
-    cases.add("global struct whose default name conflicts with global is mangled",
-        \\struct foo {
-        \\    int x;
-        \\};
-        \\const char *struct_foo = "hello world";
-    , &[_][]const u8{
-        \\pub const struct_foo_1 = extern struct {
-        \\    x: c_int = @import("std").mem.zeroes(c_int),
-        \\};
-        ,
-        \\pub const foo = struct_foo_1;
-        ,
-        \\pub export var struct_foo: [*c]const u8 = "hello world";
-    });
-
     cases.add("unsupport declare statement at the last of a compound statement which belongs to a statement expr",
         \\void somefunc(void) {
         \\  int y;