| author | |
| committer | |
| log | f846dc420fff629572caa1175bfa64e5fcffaeb5 |
| tree | f2e882f35401602799e46b76990a9e9403e3c909 |
| parent | ee651c3cd358f40f60db0bbcd82ffde99aed9b88 |
| parent | 0274e2f1fd3b7a81344080d532cfd2d384427cd2 |
| signature |
translate-c: fix for #10461. Check child records for opaque types2 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 | 793 | var is_extern = storage_class == .Extern and !has_init; |
| 794 | 794 | var is_export = !is_extern and storage_class != .Static; |
| 795 | 795 | |
| 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 | 800 | const type_node = transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, var_decl_loc) catch |err| switch (err) { |
| 797 | 801 | error.UnsupportedTranslation, error.UnsupportedType => { |
| 798 | 802 | return failDecl(c, var_decl_loc, var_name, "unable to resolve variable type", .{}); |
| ... | ... | @@ -1839,6 +1843,7 @@ fn transDeclStmtOne( |
| 1839 | 1843 | .Var => { |
| 1840 | 1844 | const var_decl = @ptrCast(*const clang.VarDecl, decl); |
| 1841 | 1845 | const decl_init = var_decl.getInit(); |
| 1846 | const loc = decl.getLocation(); | |
| 1842 | 1847 | |
| 1843 | 1848 | const qual_type = var_decl.getTypeSourceInfo_getType(); |
| 1844 | 1849 | const name = try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin()); |
| ... | ... | @@ -1848,12 +1853,12 @@ fn transDeclStmtOne( |
| 1848 | 1853 | // This is actually a global variable, put it in the global scope and reference it. |
| 1849 | 1854 | // `_ = mangled_name;` |
| 1850 | 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 | } |
| 1852 | 1859 | |
| 1853 | 1860 | const is_static_local = var_decl.isStaticLocal(); |
| 1854 | 1861 | const is_const = qual_type.isConstQualified(); |
| 1855 | ||
| 1856 | const loc = decl.getLocation(); | |
| 1857 | 1862 | const type_node = try transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, loc); |
| 1858 | 1863 | |
| 1859 | 1864 | var init_node = if (decl_init) |expr| |
| ... | ... | @@ -4831,7 +4836,16 @@ fn qualTypeWasDemotedToOpaque(c: *Context, qt: clang.QualType) bool { |
| 4831 | 4836 | |
| 4832 | 4837 | const record_decl = record_ty.getDecl(); |
| 4833 | 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 | 4850 | .Enum => { |
| 4837 | 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 | pub fn addCases(cases: *tests.TranslateCContext) void { |
| 7 | 7 | const default_enum_type = if (builtin.abi == .msvc) "c_int" else "c_uint"; |
| 8 | 8 | |
| 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 | 23 | cases.add("field access is grouped if necessary", |
| 10 | 24 | \\unsigned long foo(unsigned long x) { |
| 11 | 25 | \\ return ((union{unsigned long _x}){x})._x; |
| ... | ... | @@ -3587,7 +3601,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3587 | 3601 | \\ struct my_struct S = {.a = 1, .b = 2}; |
| 3588 | 3602 | \\} |
| 3589 | 3603 | , &[_][]const u8{ |
| 3590 | \\warning: cannot initialize opaque type | |
| 3604 | \\warning: local variable has opaque type | |
| 3591 | 3605 | , |
| 3592 | 3606 | \\warning: unable to translate function, demoted to extern |
| 3593 | 3607 | \\pub extern fn initialize() void; |
| ... | ... | @@ -3607,6 +3621,30 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3607 | 3621 | \\pub extern fn deref(arg_s: ?*struct_my_struct) void; |
| 3608 | 3622 | }); |
| 3609 | 3623 | |
| 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 | 3648 | cases.add("Function prototype declared within function", |
| 3611 | 3649 | \\int foo(void) { |
| 3612 | 3650 | \\ extern int bar(int, int); |