Skip to content

A parameter pack appears both empty and non-empty at the same time #137885

Open
@HolyBlackCat

Description

@HolyBlackCat

Found a really concerning bug:

template <typename ...P>
struct A {};

struct B
{
    consteval B() {} // Making this constexpr makes the assert below pass.

    template <typename ...P>
    consteval operator A<P...>() const
    {
        static_assert(sizeof...(P) > 0); // This fails on Clang.
        return {};
    }
};

template <typename T>
struct type_identity 
{
    using type = T;
};

template <typename ...P>
void foo(typename type_identity<A<P...>>::type a, P...) {}

int main()
{
    foo(B(), 1, 2);
}

The static_assert fires on Clang, meaning it calls operator A<> with no template arguments! But the corresponding function parameter is A<int, int>.

Apparently A<> gets reinterpreted (!!) into A<int, int> at compile-time. E.g. if you add a int x = sizeof...(P) data member to it, it'll be 0 despite the type actually being A<int, int>.

Here's an example of this being used to reinterpret_cast a float into an int: https://gcc.godbolt.org/z/Txbsj8ofM


Tested on Clang 20 and trunk. The only flag needed is -std=c++20 for consteval.

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:frontendLanguage frontend issues, e.g. anything involving "Sema"confirmedVerified by a second partyconstevalC++20 consteval

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions