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 {...@@ -128,14 +128,29 @@ const Scope = struct {
128128
129 /// Given the desired name, return a name that does not shadow anything from outer scopes.129 /// Given the desired name, return a name that does not shadow anything from outer scopes.
130 /// Inserts the returned name into the scope.130 /// 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.
131 fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 {137 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 {
132 const name_copy = try c.arena.dupe(u8, name);142 const name_copy = try c.arena.dupe(u8, name);
133 var proposed_name = name_copy;143 var proposed_name = name_copy;
134 while (scope.contains(proposed_name)) {144 while (scope.contains(proposed_name)) {
135 scope.mangle_count += 1;145 scope.mangle_count += 1;
136 proposed_name = try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ name, scope.mangle_count });146 proposed_name = try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ name, scope.mangle_count });
137 }147 }
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 }
139 return proposed_name;154 return proposed_name;
140 }155 }
141156
...@@ -3806,8 +3821,8 @@ fn transCreatePreCrement(...@@ -3806,8 +3821,8 @@ fn transCreatePreCrement(
3806 // zig: })3821 // zig: })
3807 var block_scope = try Scope.Block.init(c, scope, true);3822 var block_scope = try Scope.Block.init(c, scope, true);
3808 defer block_scope.deinit();3823 defer block_scope.deinit();
3809 const ref = try block_scope.makeMangledName(c, "ref");
38103824
3825 const ref = try block_scope.reserveMangledName(c, "ref");
3811 const expr = try transExpr(c, &block_scope.base, op_expr, .used);3826 const expr = try transExpr(c, &block_scope.base, op_expr, .used);
3812 const addr_of = try Tag.address_of.create(c.arena, expr);3827 const addr_of = try Tag.address_of.create(c.arena, expr);
3813 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });3828 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });
...@@ -3853,7 +3868,8 @@ fn transCreatePostCrement(...@@ -3853,7 +3868,8 @@ fn transCreatePostCrement(
3853 // zig: })3868 // zig: })
3854 var block_scope = try Scope.Block.init(c, scope, true);3869 var block_scope = try Scope.Block.init(c, scope, true);
3855 defer block_scope.deinit();3870 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
3858 const expr = try transExpr(c, &block_scope.base, op_expr, .used);3874 const expr = try transExpr(c, &block_scope.base, op_expr, .used);
3859 const addr_of = try Tag.address_of.create(c.arena, expr);3875 const addr_of = try Tag.address_of.create(c.arena, expr);
...@@ -3863,7 +3879,6 @@ fn transCreatePostCrement(...@@ -3863,7 +3879,6 @@ fn transCreatePostCrement(
3863 const lhs_node = try Tag.identifier.create(c.arena, ref);3879 const lhs_node = try Tag.identifier.create(c.arena, ref);
3864 const ref_node = try Tag.deref.create(c.arena, lhs_node);3880 const ref_node = try Tag.deref.create(c.arena, lhs_node);
38653881
3866 const tmp = try block_scope.makeMangledName(c, "tmp");
3867 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node });3882 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node });
3868 try block_scope.statements.append(tmp_decl);3883 try block_scope.statements.append(tmp_decl);
38693884
...@@ -3968,7 +3983,7 @@ fn transCreateCompoundAssign(...@@ -3968,7 +3983,7 @@ fn transCreateCompoundAssign(
3968 // zig: })3983 // zig: })
3969 var block_scope = try Scope.Block.init(c, scope, true);3984 var block_scope = try Scope.Block.init(c, scope, true);
3970 defer block_scope.deinit();3985 defer block_scope.deinit();
3971 const ref = try block_scope.makeMangledName(c, "ref");3986 const ref = try block_scope.reserveMangledName(c, "ref");
39723987
3973 const expr = try transExpr(c, &block_scope.base, lhs, .used);3988 const expr = try transExpr(c, &block_scope.base, lhs, .used);
3974 const addr_of = try Tag.address_of.create(c.arena, expr);3989 const addr_of = try Tag.address_of.create(c.arena, expr);
...@@ -4098,9 +4113,9 @@ fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang...@@ -4098,9 +4113,9 @@ fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang
4098 var block_scope = try Scope.Block.init(c, scope, true);4113 var block_scope = try Scope.Block.init(c, scope, true);
4099 defer block_scope.deinit();4114 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");
4102 const init_node = try transExpr(c, &block_scope.base, cond_expr, .used);4117 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 });
4104 try block_scope.statements.append(ref_decl);4119 try block_scope.statements.append(ref_decl);
41054120
4106 var cond_scope = Scope.Condition{4121 var cond_scope = Scope.Condition{
...@@ -4111,7 +4126,7 @@ fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang...@@ -4111,7 +4126,7 @@ fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang
4111 };4126 };
4112 defer cond_scope.deinit();4127 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);
4115 const ty = getExprQualType(c, cond_expr).getTypePtr();4130 const ty = getExprQualType(c, cond_expr).getTypePtr();
4116 const cond_node = try finishBoolExpr(c, &cond_scope.base, cond_expr.getBeginLoc(), ty, cond_ident, .used);4131 const cond_node = try finishBoolExpr(c, &cond_scope.base, cond_expr.getBeginLoc(), ty, cond_ident, .used);
4117 var then_body = cond_ident;4132 var then_body = cond_ident;
...@@ -4552,11 +4567,12 @@ fn transCreateNodeAssign(...@@ -4552,11 +4567,12 @@ fn transCreateNodeAssign(
4552 var block_scope = try Scope.Block.init(c, scope, true);4567 var block_scope = try Scope.Block.init(c, scope, true);
4553 defer block_scope.deinit();4568 defer block_scope.deinit();
45544569
4555 const tmp = try block_scope.makeMangledName(c, "tmp");4570 const tmp = try block_scope.reserveMangledName(c, "tmp");
4556 var rhs_node = try transExpr(c, &block_scope.base, rhs, .used);4571 var rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
4557 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {4572 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
4558 rhs_node = try Tag.bool_to_int.create(c.arena, rhs_node);4573 rhs_node = try Tag.bool_to_int.create(c.arena, rhs_node);
4559 }4574 }
4575
4560 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = rhs_node });4576 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = rhs_node });
4561 try block_scope.statements.append(tmp_decl);4577 try block_scope.statements.append(tmp_decl);
45624578
test/translate_c.zig+155
...@@ -3962,4 +3962,159 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3962,4 +3962,159 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3962 , &[_][]const u8{3962 , &[_][]const u8{
3963 \\pub const foo: [3:0]u8 = "bar";3963 \\pub const foo: [3:0]u8 = "bar";
3964 });3964 });
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 });
3965}4120}