Consider this:
#include <typeinfo>
struct Base {
virtual int foo() { return 42; }
};
struct Derived final : Base {
int foo() override { return 84; }
};
int f(Derived &d) {
if (typeid(d) == typeid(Derived))
return d.foo();
return 0;
}
Godbolt:
https://godbolt.org/z/K1T9vve86
x86-64 clang (trunk), -std=c++20 -O3
f(Derived&):
mov rax, qword ptr [rdi]
mov rax, qword ptr [rax - 8]
mov rdi, qword ptr [rax + 8]
lea rax, [rip + typeinfo name for Derived]
cmp rdi, rax
je .LBB0_3
xor eax, eax
cmp byte ptr [rdi], 42
je .LBB0_4
push rax
lea rsi, [rip + typeinfo name for Derived]
call strcmp@PLT
mov ecx, eax
xor eax, eax
test ecx, ecx
lea rsp, [rsp + 8]
je .LBB0_3
.LBB0_4:
ret
.LBB0_3:
mov eax, 84
ret
typeinfo name for Derived:
.asciz "7Derived"
x86-64 gcc 16.1, -std=c++20 -O3
"f(Derived&)":
mov eax, 84
ret
On Godbolt, Clang trunk still emits RTTI lookup from the vtable and compares the type names, while GCC 16.1 folds the function to a constant return.
Since Derived is final, a Derived& cannot refer to a more-derived dynamic type, so typeid(d) == typeid(Derived) should be known to be true and the function should fold to return 84;.
This looks very similar in spirit to #10013, but for typeid instead of dynamic_cast.
Tested on Godbolt with x86-64 clang (trunk) and x86-64 gcc 16.1.
Consider this:
Godbolt:
https://godbolt.org/z/K1T9vve86
x86-64 clang (trunk),
-std=c++20 -O3x86-64 gcc 16.1,
-std=c++20 -O3On Godbolt, Clang trunk still emits RTTI lookup from the vtable and compares the type names, while GCC 16.1 folds the function to a constant return.
Since
Derivedisfinal, aDerived&cannot refer to a more-derived dynamic type, sotypeid(d) == typeid(Derived)should be known to be true and the function should fold toreturn 84;.This looks very similar in spirit to #10013, but for
typeidinstead ofdynamic_cast.Tested on Godbolt with x86-64 clang (trunk) and x86-64 gcc 16.1.