authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-05-30 16:01:05+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-30 16:01:05+03:00
logf846dc420fff629572caa1175bfa64e5fcffaeb5
treef2e882f35401602799e46b76990a9e9403e3c909
parentee651c3cd358f40f60db0bbcd82ffde99aed9b88
parent0274e2f1fd3b7a81344080d532cfd2d384427cd2
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10474 from TwoClocks/master

translate-c: fix for #10461. Check child records for opaque types

2 files changed, 56 insertions(+), 4 deletions(-)

src/translate_c.zig+17-3
...@@ -793,6 +793,10 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co...@@ -793,6 +793,10 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
793 var is_extern = storage_class == .Extern and !has_init;793 var is_extern = storage_class == .Extern and !has_init;
794 var is_export = !is_extern and storage_class != .Static;794 var is_export = !is_extern and storage_class != .Static;
795795
796 if (!is_extern and qualTypeWasDemotedToOpaque(c, qual_type)) {
797 return failDecl(c, var_decl_loc, var_name, "non-extern variable has opaque type", .{});
798 }
799
796 const type_node = transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {800 const type_node = transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {
797 error.UnsupportedTranslation, error.UnsupportedType => {801 error.UnsupportedTranslation, error.UnsupportedType => {
798 return failDecl(c, var_decl_loc, var_name, "unable to resolve variable type", .{});802 return failDecl(c, var_decl_loc, var_name, "unable to resolve variable type", .{});
...@@ -1839,6 +1843,7 @@ fn transDeclStmtOne(...@@ -1839,6 +1843,7 @@ fn transDeclStmtOne(
1839 .Var => {1843 .Var => {
1840 const var_decl = @ptrCast(*const clang.VarDecl, decl);1844 const var_decl = @ptrCast(*const clang.VarDecl, decl);
1841 const decl_init = var_decl.getInit();1845 const decl_init = var_decl.getInit();
1846 const loc = decl.getLocation();
18421847
1843 const qual_type = var_decl.getTypeSourceInfo_getType();1848 const qual_type = var_decl.getTypeSourceInfo_getType();
1844 const name = try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin());1849 const name = try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin());
...@@ -1848,12 +1853,12 @@ fn transDeclStmtOne(...@@ -1848,12 +1853,12 @@ fn transDeclStmtOne(
1848 // This is actually a global variable, put it in the global scope and reference it.1853 // This is actually a global variable, put it in the global scope and reference it.
1849 // `_ = mangled_name;`1854 // `_ = mangled_name;`
1850 return visitVarDecl(c, var_decl, mangled_name);1855 return visitVarDecl(c, var_decl, mangled_name);
1856 } else if (qualTypeWasDemotedToOpaque(c, qual_type)) {
1857 return fail(c, error.UnsupportedTranslation, loc, "local variable has opaque type", .{});
1851 }1858 }
18521859
1853 const is_static_local = var_decl.isStaticLocal();1860 const is_static_local = var_decl.isStaticLocal();
1854 const is_const = qual_type.isConstQualified();1861 const is_const = qual_type.isConstQualified();
1855
1856 const loc = decl.getLocation();
1857 const type_node = try transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, loc);1862 const type_node = try transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, loc);
18581863
1859 var init_node = if (decl_init) |expr|1864 var init_node = if (decl_init) |expr|
...@@ -4831,7 +4836,16 @@ fn qualTypeWasDemotedToOpaque(c: *Context, qt: clang.QualType) bool {...@@ -4831,7 +4836,16 @@ fn qualTypeWasDemotedToOpaque(c: *Context, qt: clang.QualType) bool {
48314836
4832 const record_decl = record_ty.getDecl();4837 const record_decl = record_ty.getDecl();
4833 const canonical = @ptrToInt(record_decl.getCanonicalDecl());4838 const canonical = @ptrToInt(record_decl.getCanonicalDecl());
4834 return c.opaque_demotes.contains(canonical);4839 if (c.opaque_demotes.contains(canonical)) return true;
4840
4841 // check all childern for opaque types.
4842 var it = record_decl.field_begin();
4843 const end_it = record_decl.field_end();
4844 while (it.neq(end_it)) : (it = it.next()) {
4845 const field_decl = it.deref();
4846 if (qualTypeWasDemotedToOpaque(c, field_decl.getType())) return true;
4847 }
4848 return false;
4835 },4849 },
4836 .Enum => {4850 .Enum => {
4837 const enum_ty = @ptrCast(*const clang.EnumType, ty);4851 const enum_ty = @ptrCast(*const clang.EnumType, ty);
test/translate_c.zig+39-1
...@@ -6,6 +6,20 @@ const CrossTarget = std.zig.CrossTarget;...@@ -6,6 +6,20 @@ const CrossTarget = std.zig.CrossTarget;
6pub fn addCases(cases: *tests.TranslateCContext) void {6pub fn addCases(cases: *tests.TranslateCContext) void {
7 const default_enum_type = if (builtin.abi == .msvc) "c_int" else "c_uint";7 const default_enum_type = if (builtin.abi == .msvc) "c_int" else "c_uint";
88
9 cases.add("variables check for opaque demotion",
10 \\struct A {
11 \\ _Atomic int a;
12 \\} a;
13 \\int main(void) {
14 \\ struct A a;
15 \\}
16 , &[_][]const u8{
17 \\pub const struct_A = opaque {};
18 \\pub const a = @compileError("non-extern variable has opaque type");
19 ,
20 \\pub extern fn main() c_int;
21 });
22
9 cases.add("field access is grouped if necessary",23 cases.add("field access is grouped if necessary",
10 \\unsigned long foo(unsigned long x) {24 \\unsigned long foo(unsigned long x) {
11 \\ return ((union{unsigned long _x}){x})._x;25 \\ return ((union{unsigned long _x}){x})._x;
...@@ -3587,7 +3601,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3587,7 +3601,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3587 \\ struct my_struct S = {.a = 1, .b = 2};3601 \\ struct my_struct S = {.a = 1, .b = 2};
3588 \\}3602 \\}
3589 , &[_][]const u8{3603 , &[_][]const u8{
3590 \\warning: cannot initialize opaque type3604 \\warning: local variable has opaque type
3591 ,3605 ,
3592 \\warning: unable to translate function, demoted to extern3606 \\warning: unable to translate function, demoted to extern
3593 \\pub extern fn initialize() void;3607 \\pub extern fn initialize() void;
...@@ -3607,6 +3621,30 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3607,6 +3621,30 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3607 \\pub extern fn deref(arg_s: ?*struct_my_struct) void;3621 \\pub extern fn deref(arg_s: ?*struct_my_struct) void;
3608 });3622 });
36093623
3624 cases.add("Demote function that dereference types that contain opaque type",
3625 \\struct inner {
3626 \\ _Atomic int a;
3627 \\};
3628 \\struct outer {
3629 \\ int thing;
3630 \\ struct inner sub_struct;
3631 \\};
3632 \\void deref(struct outer *s) {
3633 \\ *s;
3634 \\}
3635 , &[_][]const u8{
3636 \\pub const struct_inner = opaque {};
3637 ,
3638 \\pub const struct_outer = extern struct {
3639 \\ thing: c_int,
3640 \\ sub_struct: struct_inner,
3641 \\};
3642 ,
3643 \\warning: unable to translate function, demoted to extern
3644 ,
3645 \\pub extern fn deref(arg_s: ?*struct_outer) void;
3646 });
3647
3610 cases.add("Function prototype declared within function",3648 cases.add("Function prototype declared within function",
3611 \\int foo(void) {3649 \\int foo(void) {
3612 \\ extern int bar(int, int);3650 \\ extern int bar(int, int);