https://gcc.gnu.org/g:67bc28c6c0c68a22280fd0942df598f20e339431
commit r17-366-g67bc28c6c0c68a22280fd0942df598f20e339431 Author: Martin Uecker <[email protected]> Date: Sat Apr 25 20:14:13 2026 +0200 c: Fix use of variably-modified structure/union types in nested context [PR124985] If a nested function uses a variably-modified structure or union type that depends on the enclosing context, it needs the static chain. My recent change missed this, because in this case no decl was used. To address this, we now call mark_decl_used also on TYPE_STUB_DECLs. PR c/124985 gcc/c/ChangeLog: * c-decl.cc (pushtag): Update comment. (declspecs_add_type): Mark TYPE_STUB_DECL as used. * c-typeck.cc (function_to_pointer_conversion): Fix grammar in comment. gcc/testsuite/ChangeLog: * gcc.dg/Wreturn-nested-3.c: New test. * gcc.dg/pr124985.c: New test. Diff: --- gcc/c/c-decl.cc | 8 ++++++- gcc/c/c-typeck.cc | 2 +- gcc/testsuite/gcc.dg/Wreturn-nested-3.c | 42 +++++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/pr124985.c | 13 ++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index cc07e05e3363..683780ab6543 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -1709,7 +1709,8 @@ pushtag (location_t loc, tree name, tree type) NULL-named TYPE_DECL node helps dwarfout.c to know when it needs to output a representation of a tagged type, and it also gives us a convenient place to record the "scope start" address for the - tagged type. */ + tagged type, and it is used to track whether the type is used + in a non-local context via mark_decl_used. */ TYPE_STUB_DECL (type) = pushdecl (build_decl (loc, TYPE_DECL, NULL_TREE, type)); @@ -13134,6 +13135,11 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, specs->typedef_p = true; specs->locations[cdw_typedef] = loc; } + + if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + mark_decl_used (TYPE_STUB_DECL (type), false); + if (spec.expr) { tree expr = save_expr (fold_convert (void_type_node, spec.expr)); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index aa368a6e95ae..6195d1795432 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -2373,7 +2373,7 @@ function_to_pointer_conversion (location_t loc, tree exp) tree exp2 = build_unary_op (loc, ADDR_EXPR, exp, false); - /* If the function is defined and known to not to require a non-local + /* If the function is defined and known to not require a non-local context, make sure no trampoline is generated. */ if (TREE_CODE (exp) == FUNCTION_DECL && DECL_INITIAL (exp) && !C_FUNC_NONLOCAL_CONTEXT (exp)) diff --git a/gcc/testsuite/gcc.dg/Wreturn-nested-3.c b/gcc/testsuite/gcc.dg/Wreturn-nested-3.c new file mode 100644 index 000000000000..c31685f28f37 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wreturn-nested-3.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target trampolines } */ +/* { dg-options "" } */ + + +void *a0() { + int b = 1; + struct bar { char c[b]; }; + struct bar e() { struct bar f; return f; } + return &e; /* { dg-warning "referencing local context" } */ +} + +void *a1() { + int b = 1; + struct bar { char c[b]; }; + struct bar e() { } + return &e; +} + +void *a2() { + int b = 1; + struct bar { char c[b]; }; + struct bar e() { typeof(struct bar) f; return f; } + return &e; /* { dg-warning "referencing local context" } */ +} + +void *a3() { + int b = 1; + struct bar { char c[b]; }; + struct bar (*d)(); + struct bar e() { typeof((*d)()) f; return f; } + return &e; /* { dg-warning "referencing local context" } */ +} + +void *a4() { + int b = 1; + struct bar { char c[b]; }; + struct bar e() { struct bar f; return f; } + return &e; /* { dg-warning "referencing local context" } */ +} + + diff --git a/gcc/testsuite/gcc.dg/pr124985.c b/gcc/testsuite/gcc.dg/pr124985.c new file mode 100644 index 000000000000..8ccc282586fe --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr124985.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target trampolines } */ +/* { dg-options "-O1 -fno-tree-dse" } */ + +void a() { + int b = 0; + struct bar { char c[b]; }; + struct bar (*d)(); + struct bar e() { struct bar f; return f; } + d = e; + d(); +} +
