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".