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