Skip to content

[clang] Missing optimization for typeid on a final class reference #196476

@Mryange

Description

@Mryange

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.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions