Bug 99093 - [missed optimization] Missed devirtualization involving internal-linkage class type (but only sometimes)
Summary: [missed optimization] Missed devirtualization involving internal-linkage clas...
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 11.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Keywords: missed-optimization
Depends on:
Reported: 2021-02-14 01:08 UTC by Arthur O'Dwyer
Modified: 2021-02-15 08:32 UTC (History)
2 users (show)

See Also:
Known to work:
Known to fail: 11.0
Last reconfirmed:


Note You need to log in before you can comment on or make changes to this bug.
Description Arthur O'Dwyer 2021-02-14 01:08:17 UTC
// https://godbolt.org/z/hx7h7v
struct Base {
    virtual int f() { return 1; }

namespace {
    struct Derived1 : public Base {
        int f() override { return 2; }
    struct Derived2 : public Base {};

int leaf_class1(Base *p) { return ((Derived1*)p)->f(); }
    // devirtualized by GCC, because PrivateDerived is provably a leaf

int leaf_class2(Base *p) { return ((Derived2*)p)->f(); }
    // not devirtualized by GCC -- this smells like a missed-optimization bug


GCC 4.9 started to be able to devirtualize things in the compiler, based on translation-unit-wide (but still compiler-time) information. GCC 4.9.0 is able to devirtualize the call in `leaf_class1`. This is awesome!

However, both GCC 4.9 and GCC trunk fail to apply the exact same optimization to `leaf_class2`. The only difference between `Derived1` and `Derived2` is that `Derived1::f` is declared directly in `Derived1` whereas `Derived2::f` is technically a member of `Base`. That shouldn't matter at all to the devirtualization logic. But apparently it does.


Barely possibly related missed-devirtualization bugs: #47316, #60674, #89924, #94243.