Type inheritance graph built for one translation unit with
build_type_inheritance_graph() might be incomplete, in that vtable would
not be emitted for a class by frontend, if its key virtual method is just
a declaration. Therefore, given a virtual call, some of all its possible
target set might be missed, and this would break the assumption that
speculative devirt targets is subset of the former, that is, here
assertion targets.length () <= len may not be satisfied. For example:
class A {
public:
virtual ~A();
virtual int f() = 0;
};
class B : public A {
public:
virtual ~B();
virtual int f();
};
void foo(B *b)
{
A *a = b;
delete a;
}
The relation that "B" is derived class of "A" is not recorded by
build_type_inheritance_graph(). And the result of the first call to
possible_polymorphic_call_targets() would be empty, which is based
on odr type of "A". The other is for speculative devirt, which is
based on odr type of "B", the result target is destructor of "B".
So this patch would remove the assertion:
gcc_assert (symtab->state < IPA_SSA || targets.length () <= len);
Regards,
Feng
From 818c951742414bddf7c38a01d937ff12c5691a54 Mon Sep 17 00:00:00 2001
From: Feng Xue <f...@os.amperecomputing.com>
Date: Tue, 15 Jul 2025 14:26:08 +0800
Subject: [PATCH] ipa/107044 - Remove assertion in
dump_possible_polymorphic_call_targets
Type inheritance graph built for one translation unit with
build_type_inheritance_graph() might be incomplete, in that vtable would
not be emitted for a class by frontend, if its key virtual method is just
a declaration. Therefore, given a virtual call, some of all its possible
target set might be missed, and this would break the assumption that
speculative devirt targets is subset of the former, that is, here
assertion targets.length () <= len may not be satisfied.
2025-07-15 Feng Xue <f...@os.amperecomputing.com>
gcc/
PR tree-optimization/107044
* ipa-devirt.cc (dump_possible_polymorphic_call_targets): Remove
assertion.
gcc/testsuite/
PR tree-optimization/107044
* g++.dg/ipa/pr107044.C: New test.
---
gcc/ipa-devirt.cc | 41 ++++++++++++++++++++++++-----
gcc/testsuite/g++.dg/ipa/pr107044.C | 21 +++++++++++++++
2 files changed, 55 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/ipa/pr107044.C
diff --git a/gcc/ipa-devirt.cc b/gcc/ipa-devirt.cc
index 18cb5a82195..c0ccc87e34c 100644
--- a/gcc/ipa-devirt.cc
+++ b/gcc/ipa-devirt.cc
@@ -3460,13 +3460,40 @@ dump_possible_polymorphic_call_targets (FILE *f,
fprintf (f, " Speculative targets:");
dump_targets (f, targets, verbose);
}
- /* Ugly: during callgraph construction the target cache may get populated
- before all targets are found. While this is harmless (because all local
- types are discovered and only in those case we devirtualize fully and we
- don't do speculative devirtualization before IPA stage) it triggers
- assert here when dumping at that stage also populates the case with
- speculative targets. Quietly ignore this. */
- gcc_assert (symtab->state < IPA_SSA || targets.length () <= len);
+
+ /* Type inheritance graph built for one translation unit with
+ build_type_inheritance_graph() might be incomplete, in that vtable would
+ not be emitted for a class by frontend, if its key virtual method is just
+ a declaration. Therefore, given a virtual call, some of all its possible
+ target set might be missed, and this would break the assumption that
+ speculative devirt targets is subset of the former, that is, here
+ assertion targets.length () <= len may not be satisfied. For example:
+
+ class A {
+ public:
+ virtual ~A();
+ virtual int f() = 0;
+ };
+
+ class B : public A {
+ public:
+ virtual ~B();
+ virtual int f();
+ };
+
+ void foo(B *b)
+ {
+ A *a = b;
+
+ delete a;
+ }
+
+ The relation that "B" is derived class of "A" is not recorded by
+ build_type_inheritance_graph(). And the result of the first call to
+ possible_polymorphic_call_targets() would be empty, which is based
+ on odr type of "A". The other is for speculative devirt, which is
+ based on odr type of "B", the result target is destructor of "B". */
+
fprintf (f, "\n");
}
diff --git a/gcc/testsuite/g++.dg/ipa/pr107044.C b/gcc/testsuite/g++.dg/ipa/pr107044.C
new file mode 100644
index 00000000000..67a68626f49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/pr107044.C
@@ -0,0 +1,21 @@
+// { dg-do compile }
+// { dg-options "-O3 -fdump-tree-all" }
+
+class A {
+public:
+ virtual ~A();
+ virtual int f() = 0;
+};
+
+class B : public A {
+public:
+ virtual ~B();
+ virtual int f();
+};
+
+void foo(B *b)
+{
+ A *a = b;
+
+ delete a;
+}
--
2.17.1