Skip to content

Commit f846dc4

Browse files
authored
Merge pull request #10474 from TwoClocks/master
translate-c: fix for #10461. Check child records for opaque types
2 parents ee651c3 + 0274e2f commit f846dc4

File tree

2 files changed

+56
-4
lines changed

2 files changed

+56
-4
lines changed

src/translate_c.zig

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@ const CrossTarget = std.zig.CrossTarget;
66
pub 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);

0 commit comments

Comments
 (0)