On Thu, 2026-01-22 at 13:13:36 +0100, Jakub Jelinek wrote:
> > + walk_tree (&t, walk_through_asm_defined_symbol, NULL, NULL);
>
> Why?
> Immediately above this there is
> if (TREE_CODE (t) != ADDR_EXPR
> || !(TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL
> || (VAR_P (TREE_OPERAND (t, 0))
> && is_global_var (TREE_OPERAND (t, 0)))))
> error
> So, why not simply add
> else
> TREE_ASM_WRITTEN (TREE_OPERAND (t, 0)) = 1;
> with a comment?
I wrongly assumed these are represented differently:
asm("%cc0:" :: ":"(asm_fn));
asm("%cc0:" :: ":"(&asm_fn));
> And do it for C as well and add a testcase for it into c-c++-common
> with dg-bogus?
>
> Jakub
>
Thanks, following v2 is now for both C and C++.
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.
TREE_ASM_WRITTEN seems to be usable for this purpose; written symbols
are always defined, and the symbol will be written separately by
toplevel assembly.
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.
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 | 4 +++-
gcc/c/c-typeck.cc | 3 +++
gcc/cgraphunit.cc | 4 +++-
gcc/cp/decl.cc | 2 ++
gcc/cp/semantics.cc | 3 +++
gcc/testsuite/c-c++-common/toplevel-extended-asm-1.c | 5 +++++
6 files changed, 19 insertions(+), 2 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..b2d7eeb888f 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -13669,7 +13669,9 @@ 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)
+ /* Symbols defined in assembly. */
+ && !TREE_ASM_WRITTEN (decl))
{
if (C_DECL_USED (decl))
{
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 04b33111f62..a4ad8cbd34e 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -13169,6 +13169,9 @@ build_asm_expr (location_t loc, tree string, tree
outputs, tree inputs,
"of a function or non-automatic variable");
input = error_mark_node;
}
+ else
+ /* Mark symbol defined in asm. */
+ TREE_ASM_WRITTEN (TREE_OPERAND (t, 0)) = 1;
}
}
else
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index 88c1071c8de..401e016b8ca 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -1106,7 +1106,9 @@ check_global_declaration (symtab_node *snode)
&& DECL_INITIAL (decl) == 0
&& DECL_EXTERNAL (decl)
&& ! DECL_ARTIFICIAL (decl)
- && ! TREE_PUBLIC (decl))
+ && ! TREE_PUBLIC (decl)
+ /* Symbols defined in assembly. */
+ && ! TREE_ASM_WRITTEN (decl))
{
if (warning_suppressed_p (decl, OPT_Wunused))
;
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 46a17a596ed..27244293e8d 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1013,6 +1013,8 @@ wrapup_namespace_globals ()
&& DECL_EXTERNAL (decl)
&& !TREE_PUBLIC (decl)
&& !DECL_ARTIFICIAL (decl)
+ /* Symbols defined in assembly. */
+ && !TREE_ASM_WRITTEN (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 78d717cade3..4e3810e19e9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2492,6 +2492,9 @@ finish_asm_stmt (location_t loc, int volatile_p, tree
string,
"of a function or non-automatic variable");
operand = error_mark_node;
}
+ else
+ /* Mark symbol defined in asm. */
+ TREE_ASM_WRITTEN (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));
--
2.52.0