On 1/10/2025 15:40, Richard Biener wrote:
On Thu, Jul 31, 2025 at 5:47 PM Yangyu Chen <[email protected]> wrote:

When building with LTO, DECL_VINDEX is not always set for virtual
functions, which allows virtual functions to be incorrectly treated as
non-virtual and then being multi-versioned, and causes errors sometimes.

This patch addresses the issue by ensuring that we also check
DECL_VIRTUAL_P in addition to DECL_VINDEX when handling virtual
functions during multiversioning.

I think checking DECL_VINDEX is flawed - it's only relevant for creating
OBJ_TYPE_REFs IIRC.  That is, it's irrelevant to GIMPLE and thus freed
in free-lang-data (which we unfortunately run only with -flto).

So, can you test removing the DECL_VINDEX check and only rely on
DECL_VIRTUAL_P?


It can be hard to check since most real-world source code with optimizations may not use it.

I think we should keep checking these two since DECL_VIRTUAL_P will only be set by the frontend. For some future passes that may clone a member function and insert VINDEX, this behavior can be found during compilation time instead of a runtime crash.

Thanks,
Yangyu Chen

Thanks,
Richard.

gcc/ChangeLog:

         * config/aarch64/aarch64.cc 
(aarch64_generate_version_dispatcher_body): Check DECL_VIRTUAL_P for virtual 
functions for LTO handling.
         * config/i386/i386-features.cc 
(ix86_generate_version_dispatcher_body): Ditto.
         * config/riscv/riscv.cc (riscv_generate_version_dispatcher_body): 
Ditto.
         * config/rs6000/rs6000.cc (rs6000_generate_version_dispatcher_body): 
Ditto.

Signed-off-by: Yangyu Chen <[email protected]>
---
This should also be backported to GCC stable branches.
---
  gcc/config/aarch64/aarch64.cc    | 2 +-
  gcc/config/i386/i386-features.cc | 2 +-
  gcc/config/riscv/riscv.cc        | 2 +-
  gcc/config/rs6000/rs6000.cc      | 2 +-
  4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index fff8d9da49d..fd77e24ce12 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -20763,7 +20763,7 @@ aarch64_generate_version_dispatcher_body (void *node_p)
          not.  This happens for methods in derived classes that override
          virtual methods in base classes but are not explicitly marked as
          virtual.  */
-      if (DECL_VINDEX (versn->decl))
+      if (DECL_VIRTUAL_P (versn->decl) || DECL_VINDEX (versn->decl))
         sorry ("virtual function multiversioning not supported");

        fn_ver_vec.safe_push (versn->decl);
diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index 31f3ee2ef17..043e86ece8e 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -4421,7 +4421,7 @@ ix86_generate_version_dispatcher_body (void *node_p)
          not.  This happens for methods in derived classes that override
          virtual methods in base classes but are not explicitly marked as
          virtual.  */
-      if (DECL_VINDEX (versn->decl))
+      if (DECL_VIRTUAL_P (versn->decl) || DECL_VINDEX (versn->decl))
         sorry ("virtual function multiversioning not supported");

        fn_ver_vec.safe_push (versn->decl);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index a0657323f65..90f2cbce68e 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -13747,7 +13747,7 @@ riscv_generate_version_dispatcher_body (void *node_p)
          not.  This happens for methods in derived classes that override
          virtual methods in base classes but are not explicitly marked as
          virtual.  */
-      if (DECL_VINDEX (versn->decl))
+      if (DECL_VIRTUAL_P (versn->decl) || DECL_VINDEX (versn->decl))
         sorry ("virtual function multiversioning not supported");

        fn_ver_vec.safe_push (versn->decl);
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 12dbde2bc63..0c13d524124 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -25656,7 +25656,7 @@ rs6000_generate_version_dispatcher_body (void *node_p)
          not.  This happens for methods in derived classes that override
          virtual methods in base classes but are not explicitly marked as
          virtual.  */
-      if (DECL_VINDEX (version->decl))
+      if (DECL_VIRTUAL_P (version->decl) || DECL_VINDEX (version->decl))
         sorry ("Virtual function multiversioning not supported");

        fn_ver_vec.safe_push (version->decl);
--
2.49.0


Reply via email to