authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-04-26 10:30:46-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-04-26 17:30:46+03:00
logbc4d9f3aa93ad58f9cbc75021dc297f29dcf2961
tree3b4a79951526d1e603018144c93e467ef412fc87
parent7285eedcd26b92afb03c313a167133103a78ded5
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

translate-c: fix codegen when C source has variables named the same as mangling prefixes

If the C code had variables that were named the same as the prefixes used for name mangling, such as "tmp" or "ref", then the codegen would generate incorrect code in some cases. This was because these aliases were immediately visible to expressions that actually needed to use the original name. I introduced the concept of reserving aliases without enabling them. An alias that isn't enabled isn't visible to expression translation, but is still reserved so that sub-expressions generate aliases that don't overlap. Add test cases to cover the cases that would break before this change. Co-authored-by: Veikka Tuominen <git@vexu.eu>

2 files changed, 180 insertions(+), 9 deletions(-)

src/translate_c.zig+25-9
......@@ -128,14 +128,29 @@ const Scope = struct {
128128
129129 /// Given the desired name, return a name that does not shadow anything from outer scopes.
130130 /// Inserts the returned name into the scope.
131 /// The name will not be visible to callers of getAlias.
132 fn reserveMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 {
133 return scope.createMangledName(c, name, true);
134 }
135
136 /// Same as reserveMangledName, but enables the alias immediately.
131137 fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 {
138 return scope.createMangledName(c, name, false);
139 }
140
141 fn createMangledName(scope: *Block, c: *Context, name: []const u8, reservation: bool) ![]const u8 {
132142 const name_copy = try c.arena.dupe(u8, name);
133143 var proposed_name = name_copy;
134144 while (scope.contains(proposed_name)) {
135145 scope.mangle_count += 1;
136146 proposed_name = try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ name, scope.mangle_count });
137147 }
138 try scope.variables.append(.{ .name = name_copy, .alias = proposed_name });
148 const new_mangle = try scope.variables.addOne();
149 if (reservation) {
150 new_mangle.* = .{ .name = name_copy, .alias = name_copy };
151 } else {
152 new_mangle.* = .{ .name = name_copy, .alias = proposed_name };
153 }
139154 return proposed_name;
140155 }
141156
......@@ -3806,8 +3821,8 @@ fn transCreatePreCrement(
38063821 // zig: })
38073822 var block_scope = try Scope.Block.init(c, scope, true);
38083823 defer block_scope.deinit();
3809 const ref = try block_scope.makeMangledName(c, "ref");
38103824
3825 const ref = try block_scope.reserveMangledName(c, "ref");
38113826 const expr = try transExpr(c, &block_scope.base, op_expr, .used);
38123827 const addr_of = try Tag.address_of.create(c.arena, expr);
38133828 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });
......@@ -3853,7 +3868,8 @@ fn transCreatePostCrement(
38533868 // zig: })
38543869 var block_scope = try Scope.Block.init(c, scope, true);
38553870 defer block_scope.deinit();
3856 const ref = try block_scope.makeMangledName(c, "ref");
3871 const ref = try block_scope.reserveMangledName(c, "ref");
3872 const tmp = try block_scope.reserveMangledName(c, "tmp");
38573873
38583874 const expr = try transExpr(c, &block_scope.base, op_expr, .used);
38593875 const addr_of = try Tag.address_of.create(c.arena, expr);
......@@ -3863,7 +3879,6 @@ fn transCreatePostCrement(
38633879 const lhs_node = try Tag.identifier.create(c.arena, ref);
38643880 const ref_node = try Tag.deref.create(c.arena, lhs_node);
38653881
3866 const tmp = try block_scope.makeMangledName(c, "tmp");
38673882 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node });
38683883 try block_scope.statements.append(tmp_decl);
38693884
......@@ -3968,7 +3983,7 @@ fn transCreateCompoundAssign(
39683983 // zig: })
39693984 var block_scope = try Scope.Block.init(c, scope, true);
39703985 defer block_scope.deinit();
3971 const ref = try block_scope.makeMangledName(c, "ref");
3986 const ref = try block_scope.reserveMangledName(c, "ref");
39723987
39733988 const expr = try transExpr(c, &block_scope.base, lhs, .used);
39743989 const addr_of = try Tag.address_of.create(c.arena, expr);
......@@ -4098,9 +4113,9 @@ fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang
40984113 var block_scope = try Scope.Block.init(c, scope, true);
40994114 defer block_scope.deinit();
41004115
4101 const mangled_name = try block_scope.makeMangledName(c, "cond_temp");
4116 const cond_temp = try block_scope.reserveMangledName(c, "cond_temp");
41024117 const init_node = try transExpr(c, &block_scope.base, cond_expr, .used);
4103 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = mangled_name, .init = init_node });
4118 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = cond_temp, .init = init_node });
41044119 try block_scope.statements.append(ref_decl);
41054120
41064121 var cond_scope = Scope.Condition{
......@@ -4111,7 +4126,7 @@ fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang
41114126 };
41124127 defer cond_scope.deinit();
41134128
4114 const cond_ident = try Tag.identifier.create(c.arena, mangled_name);
4129 const cond_ident = try Tag.identifier.create(c.arena, cond_temp);
41154130 const ty = getExprQualType(c, cond_expr).getTypePtr();
41164131 const cond_node = try finishBoolExpr(c, &cond_scope.base, cond_expr.getBeginLoc(), ty, cond_ident, .used);
41174132 var then_body = cond_ident;
......@@ -4552,11 +4567,12 @@ fn transCreateNodeAssign(
45524567 var block_scope = try Scope.Block.init(c, scope, true);
45534568 defer block_scope.deinit();
45544569
4555 const tmp = try block_scope.makeMangledName(c, "tmp");
4570 const tmp = try block_scope.reserveMangledName(c, "tmp");
45564571 var rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
45574572 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
45584573 rhs_node = try Tag.bool_to_int.create(c.arena, rhs_node);
45594574 }
4575
45604576 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = rhs_node });
45614577 try block_scope.statements.append(tmp_decl);
45624578
test/translate_c.zig+155
......@@ -3962,4 +3962,159 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
39623962 , &[_][]const u8{
39633963 \\pub const foo: [3:0]u8 = "bar";
39643964 });
3965
3966 cases.add("worst-case assign from mangle prefix",
3967 \\void foo() {
3968 \\ int n, tmp = 1;
3969 \\ if (n = tmp) {}
3970 \\}
3971 , &[_][]const u8{
3972 \\pub export fn foo() void {
3973 \\ var n: c_int = undefined;
3974 \\ var tmp: c_int = 1;
3975 \\ if ((blk: {
3976 \\ const tmp_1 = tmp;
3977 \\ n = tmp_1;
3978 \\ break :blk tmp_1;
3979 \\ }) != 0) {}
3980 \\}
3981 });
3982
3983 cases.add("worst-case assign to mangle prefix",
3984 \\void foo() {
3985 \\ int tmp, n = 1;
3986 \\ if (tmp = n) {}
3987 \\}
3988 , &[_][]const u8{
3989 \\pub export fn foo() void {
3990 \\ var tmp: c_int = undefined;
3991 \\ var n: c_int = 1;
3992 \\ if ((blk: {
3993 \\ const tmp_1 = n;
3994 \\ tmp = tmp_1;
3995 \\ break :blk tmp_1;
3996 \\ }) != 0) {}
3997 \\}
3998 });
3999
4000 cases.add("worst-case precrement mangle prefix",
4001 \\void foo() {
4002 \\ int n, ref = 1;
4003 \\ if (n = ++ref) {}
4004 \\}
4005 , &[_][]const u8{
4006 \\pub export fn foo() void {
4007 \\ var n: c_int = undefined;
4008 \\ var ref: c_int = 1;
4009 \\ if ((blk: {
4010 \\ const tmp = blk_1: {
4011 \\ const ref_2 = &ref;
4012 \\ ref_2.* += 1;
4013 \\ break :blk_1 ref_2.*;
4014 \\ };
4015 \\ n = tmp;
4016 \\ break :blk tmp;
4017 \\ }) != 0) {}
4018 \\}
4019 });
4020
4021 cases.add("worst-case postcrement mangle prefix",
4022 \\void foo() {
4023 \\ int n, ref = 1;
4024 \\ if (n = ref++) {}
4025 \\}
4026 , &[_][]const u8{
4027 \\pub export fn foo() void {
4028 \\ var n: c_int = undefined;
4029 \\ var ref: c_int = 1;
4030 \\ if ((blk: {
4031 \\ const tmp = blk_1: {
4032 \\ const ref_2 = &ref;
4033 \\ const tmp_3 = ref_2.*;
4034 \\ ref_2.* += 1;
4035 \\ break :blk_1 tmp_3;
4036 \\ };
4037 \\ n = tmp;
4038 \\ break :blk tmp;
4039 \\ }) != 0) {}
4040 \\}
4041 });
4042
4043 cases.add("worst-case compound assign from mangle prefix",
4044 \\void foo() {
4045 \\ int n, ref = 1;
4046 \\ if (n += ref) {}
4047 \\}
4048 , &[_][]const u8{
4049 \\pub export fn foo() void {
4050 \\ var n: c_int = undefined;
4051 \\ var ref: c_int = 1;
4052 \\ if ((blk: {
4053 \\ const ref_1 = &n;
4054 \\ ref_1.* += ref;
4055 \\ break :blk ref_1.*;
4056 \\ }) != 0) {}
4057 \\}
4058 });
4059
4060 cases.add("worst-case compound assign to mangle prefix",
4061 \\void foo() {
4062 \\ int ref, n = 1;
4063 \\ if (ref += n) {}
4064 \\}
4065 , &[_][]const u8{
4066 \\pub export fn foo() void {
4067 \\ var ref: c_int = undefined;
4068 \\ var n: c_int = 1;
4069 \\ if ((blk: {
4070 \\ const ref_1 = &ref;
4071 \\ ref_1.* += n;
4072 \\ break :blk ref_1.*;
4073 \\ }) != 0) {}
4074 \\}
4075 });
4076
4077 cases.add("binary conditional operator where condition is the mangle prefix",
4078 \\void foo() {
4079 \\ int f = 1;
4080 \\ int n, cond_temp = 1;
4081 \\ if (n = (cond_temp)?:(f)) {}
4082 \\}
4083 , &[_][]const u8{
4084 \\pub export fn foo() void {
4085 \\ var f: c_int = 1;
4086 \\ var n: c_int = undefined;
4087 \\ var cond_temp: c_int = 1;
4088 \\ if ((blk: {
4089 \\ const tmp = blk_1: {
4090 \\ const cond_temp_2 = cond_temp;
4091 \\ break :blk_1 if (cond_temp_2 != 0) cond_temp_2 else f;
4092 \\ };
4093 \\ n = tmp;
4094 \\ break :blk tmp;
4095 \\ }) != 0) {}
4096 \\}
4097 });
4098
4099 cases.add("binary conditional operator where false_expr is the mangle prefix",
4100 \\void foo() {
4101 \\ int cond_temp = 1;
4102 \\ int n, f = 1;
4103 \\ if (n = (f)?:(cond_temp)) {}
4104 \\}
4105 , &[_][]const u8{
4106 \\pub export fn foo() void {
4107 \\ var cond_temp: c_int = 1;
4108 \\ var n: c_int = undefined;
4109 \\ var f: c_int = 1;
4110 \\ if ((blk: {
4111 \\ const tmp = blk_1: {
4112 \\ const cond_temp_2 = f;
4113 \\ break :blk_1 if (cond_temp_2 != 0) cond_temp_2 else cond_temp;
4114 \\ };
4115 \\ n = tmp;
4116 \\ break :blk tmp;
4117 \\ }) != 0) {}
4118 \\}
4119 });
39654120}