https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89989

            Bug ID: 89989
           Summary: missed devirtualization opportunity on final function
           Product: gcc
           Version: 9.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Example:

struct Base {
    virtual int foo() { return 0; }
    int bar() { return foo(); }
};

struct Derived : Base {
    int foo() override final { return 1; }
};

int call_foo(Derived& d) { return d.foo(); }
int call_bar(Derived& d) { return d.bar(); }

For call_foo, the devirtualization happens:

call_foo(Derived&):
        mov     eax, 1
        ret

For call_bar, gcc emits a branch to check whether 'd' is in fact a Derived:

call_bar(Derived&):
        mov     rax, QWORD PTR [rdi]
        mov     rax, QWORD PTR [rax]
        cmp     rax, OFFSET FLAT:Derived::foo()
        jne     .L6
        mov     eax, 1
        ret
.L6:
        jmp     rax

But Derived::foo() is final, so there can't be any other valid behavior besides
simply returning 1. 

Notably, if you add "int bar() { return foo(); }" to Derived as well, then
call_bar also just emits "mov eax, 1".

Reply via email to