On Thu, 2026-01-22 at 16:58:38 +0100, Jakub Jelinek wrote:
> 
> I must say I'm not sure if using TREE_ASM_WRITTEN for this is safe, it means
> what it is documented for:
> /* Nonzero in a VAR_DECL or STRING_CST means assembler code has been written.
>    Nonzero in a FUNCTION_DECL means that the function has been compiled.
>    This is interesting in an inline function, since it might not need
>    to be compiled separately.
> 
> E.g. I wonder if it won't change behavior for (questionable and perhaps
> invalid)
> extern int a;
> asm("" :: ":" (&a));
> int a = 42;
> because assemble_variable just punts on TREE_ASM_WRITTEN VAR_DECLs.
> 

I considered this incorrect, but it fails assert in varpool_node::assemble_decl,
so my assumption wasn't good in any case..

> Anyway, even if it is valid, comment like the above doesn't seem
> appropriate, because TREE_ASM_WRITTEN (decl) doesn't mean symbol defined in
> assembly.  It means in your patch that or cfgexpand has been done on
> a definition of the function already or (if it would also allow VAR_DECLs)
> that a var definition has been emitted into assembly or that a
> function/variable alias has been emitted etc.
> 
> If all you test is TREE_ASM_WRITTEN on are FUNCTION_DECLs, perhaps the
> flag should be set solely on ":" with FUNCTION_DECLs.
> 
>       Jakub
> 

Saving a bit this way was probably a bad idea, or at least with needless issues.
tree_decl_with_vis still has a lot of free bits, so in v3 I put the flag there.

Michal

---

Static symbols defined in assembly cause wrong "used but never defined"
warning.

static void asm_fn();
asm("%cc0:" :: ":"(&asm_fn));

This happens in C,C++ frontends before cgraph is created, so we need
to have a tree flag to mark a symbol as defined in assembly to disable
the warning.

I did not add LTO streaming/merging of the flag; the flag is not needed
that late.

Tested on x86_64-pc-linux-gnu.

        PR testsuite/123559

gcc/c/ChangeLog:

        * c-decl.cc (c_write_global_declarations_1): Check asm symbols.
        * c-typeck.cc (build_asm_expr): Mark asm symbols.

gcc/ChangeLog:

        * cgraphunit.cc (check_global_declaration): Check asm symbols.
        * tree-core.h (struct tree_decl_with_vis): Add defined_in_asm.
        * tree.h (DECL_DEFINED_IN_ASM): New.

gcc/cp/ChangeLog:

        * decl.cc (wrapup_namespace_globals): Check asm symbols.
        * semantics.cc (finish_asm_stmt): Mark asm symbols.

gcc/testsuite/ChangeLog:

        * c-c++-common/toplevel-extended-asm-1.c: New test.
---
 gcc/c/c-decl.cc                                      | 3 ++-
 gcc/c/c-typeck.cc                                    | 2 ++
 gcc/cgraphunit.cc                                    | 3 ++-
 gcc/cp/decl.cc                                       | 1 +
 gcc/cp/semantics.cc                                  | 2 ++
 gcc/testsuite/c-c++-common/toplevel-extended-asm-1.c | 5 +++++
 gcc/tree-core.h                                      | 4 +++-
 gcc/tree.h                                           | 5 +++++
 8 files changed, 22 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/toplevel-extended-asm-1.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 7e94430435c..b463d742074 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -13669,7 +13669,8 @@ c_write_global_declarations_1 (tree globals)
       if (TREE_CODE (decl) == FUNCTION_DECL
          && DECL_INITIAL (decl) == NULL_TREE
          && DECL_EXTERNAL (decl)
-         && !TREE_PUBLIC (decl))
+         && !TREE_PUBLIC (decl)
+         && !DECL_DEFINED_IN_ASM (decl))
        {
          if (C_DECL_USED (decl))
            {
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 098a4b55339..b1f16be1442 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -13170,6 +13170,8 @@ build_asm_expr (location_t loc, tree string, tree 
outputs, tree inputs,
                                 "of a function or non-automatic variable");
                  input = error_mark_node;
                }
+             else
+               DECL_DEFINED_IN_ASM (TREE_OPERAND (t, 0)) = 1;
            }
        }
       else
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index 88c1071c8de..d6dc2e2663a 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -1106,7 +1106,8 @@ check_global_declaration (symtab_node *snode)
       && DECL_INITIAL (decl) == 0
       && DECL_EXTERNAL (decl)
       && ! DECL_ARTIFICIAL (decl)
-      && ! TREE_PUBLIC (decl))
+      && ! TREE_PUBLIC (decl)
+      && ! DECL_DEFINED_IN_ASM (decl))
     {
       if (warning_suppressed_p (decl, OPT_Wunused))
        ;
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 270158510df..5c1df825f50 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1014,6 +1014,7 @@ wrapup_namespace_globals ()
              && DECL_EXTERNAL (decl)
              && !TREE_PUBLIC (decl)
              && !DECL_ARTIFICIAL (decl)
+             && !DECL_DEFINED_IN_ASM (decl)
              && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl)
              && !warning_suppressed_p (decl, OPT_Wunused_function))
            warning_at (DECL_SOURCE_LOCATION (decl),
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 35bc48e49dc..8b45af64f26 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2494,6 +2494,8 @@ finish_asm_stmt (location_t loc, int volatile_p, tree 
string,
                                "of a function or non-automatic variable");
                      operand = error_mark_node;
                    }
+                 else
+                   DECL_DEFINED_IN_ASM (TREE_OPERAND (t, 0)) = 1;
                }
            }
          else
diff --git a/gcc/testsuite/c-c++-common/toplevel-extended-asm-1.c 
b/gcc/testsuite/c-c++-common/toplevel-extended-asm-1.c
new file mode 100644
index 00000000000..531c9423165
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/toplevel-extended-asm-1.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+static void asm_fn(); /* { dg-bogus "but never defined" } */
+asm("%cc0:" :: ":"(&asm_fn));
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 07e9318f5e8..3bfc4565be5 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -2025,6 +2025,8 @@ struct GTY(()) tree_decl_with_vis {
  /* Used for FUNCTION_DECL, VAR_DECL and in C++ for TYPE_DECL.  */
  ENUM_BITFIELD(symbol_visibility) visibility : 2;
  unsigned visibility_specified : 1;
+ /* Used for FUNCTION_DECL and VAR_DECL.  */
+ unsigned defined_in_asm : 1;
 
  /* Belong to FUNCTION_DECL exclusively.  */
  unsigned init_priority_p : 1;
@@ -2038,7 +2040,7 @@ struct GTY(()) tree_decl_with_vis {
  unsigned final : 1;
  /* Belong to FUNCTION_DECL exclusively.  */
  unsigned regdecl_flag : 1;
- /* 14 unused bits. */
+ /* 13 unused bits. */
  /* 32 more unused on 64 bit HW. */
 };
 
diff --git a/gcc/tree.h b/gcc/tree.h
index dcd3ff85d04..b9898b49d61 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3381,6 +3381,11 @@ extern void decl_value_expr_insert (tree, tree);
 #define DECL_VISIBILITY_SPECIFIED(NODE) \
   (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.visibility_specified)
 
+/* Nonzero means that the symbol is defined in asm statement.
+   Note: this flag is currently not propagated through LTO.  */
+#define DECL_DEFINED_IN_ASM(NODE) \
+  (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.defined_in_asm)
+
 /* In a VAR_DECL, the model to use if the data should be allocated from
    thread-local storage.  */
 #define DECL_TLS_MODEL(NODE) decl_tls_model (NODE)
-- 
2.52.0

Reply via email to