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
793793 var is_extern = storage_class == .Extern and !has_init;
794794 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
796800 const type_node = transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {
797801 error.UnsupportedTranslation, error.UnsupportedType => {
798802 return failDecl(c, var_decl_loc, var_name, "unable to resolve variable type", .{});
......@@ -1839,6 +1843,7 @@ fn transDeclStmtOne(
18391843 .Var => {
18401844 const var_decl = @ptrCast(*const clang.VarDecl, decl);
18411845 const decl_init = var_decl.getInit();
1846 const loc = decl.getLocation();
18421847
18431848 const qual_type = var_decl.getTypeSourceInfo_getType();
18441849 const name = try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin());
......@@ -1848,12 +1853,12 @@ fn transDeclStmtOne(
18481853 // This is actually a global variable, put it in the global scope and reference it.
18491854 // `_ = mangled_name;`
18501855 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", .{});
18511858 }
18521859
18531860 const is_static_local = var_decl.isStaticLocal();
18541861 const is_const = qual_type.isConstQualified();
1855
1856 const loc = decl.getLocation();
18571862 const type_node = try transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, loc);
18581863
18591864 var init_node = if (decl_init) |expr|
......@@ -4831,7 +4836,16 @@ fn qualTypeWasDemotedToOpaque(c: *Context, qt: clang.QualType) bool {
48314836
48324837 const record_decl = record_ty.getDecl();
48334838 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;
48354849 },
48364850 .Enum => {
48374851 const enum_ty = @ptrCast(*const clang.EnumType, ty);
test/translate_c.zig+39-1
......@@ -6,6 +6,20 @@ const CrossTarget = std.zig.CrossTarget;
66pub fn addCases(cases: *tests.TranslateCContext) void {
77 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
923 cases.add("field access is grouped if necessary",
1024 \\unsigned long foo(unsigned long x) {
1125 \\ return ((union{unsigned long _x}){x})._x;
......@@ -3587,7 +3601,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
35873601 \\ struct my_struct S = {.a = 1, .b = 2};
35883602 \\}
35893603 , &[_][]const u8{
3590 \\warning: cannot initialize opaque type
3604 \\warning: local variable has opaque type
35913605 ,
35923606 \\warning: unable to translate function, demoted to extern
35933607 \\pub extern fn initialize() void;
......@@ -3607,6 +3621,30 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
36073621 \\pub extern fn deref(arg_s: ?*struct_my_struct) void;
36083622 });
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
36103648 cases.add("Function prototype declared within function",
36113649 \\int foo(void) {
36123650 \\ extern int bar(int, int);