]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c: Fix use of variably-modified structure/union types in nested context [PR124985]
authorMartin Uecker <uecker@tugraz.at>
Sat, 25 Apr 2026 18:14:13 +0000 (20:14 +0200)
committerMartin Uecker <uecker@gcc.gnu.org>
Wed, 6 May 2026 15:30:23 +0000 (17:30 +0200)
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.

gcc/c/c-decl.cc
gcc/c/c-typeck.cc
gcc/testsuite/gcc.dg/Wreturn-nested-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr124985.c [new file with mode: 0644]

index cc07e05e33634669a0842e33b927aef241d57006..683780ab65430bbb0166c9e70ee7f2d40144f0f8 100644 (file)
@@ -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));
index aa368a6e95ae288074a0681b3ba9e89f847ab5e9..6195d1795432947ac6ceb7f0765cb8d40ebf9cf5 100644 (file)
@@ -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 (file)
index 0000000..c31685f
--- /dev/null
@@ -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 (file)
index 0000000..8ccc282
--- /dev/null
@@ -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();
+}
+