[clang] [Clang][Sema] Refactor collection of multi-level template argument lists (PR #106585)

Krystian Stasiowski via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 24 08:41:52 PDT 2024


sdkrystian wrote:

Another example using class templates:
```cpp
template<int N>
struct A
{
    template<typename T>
    struct B;
};

template<>
template<typename T>
struct A<0>::B : A<1>::B<T> { };

template<>
template<typename T>
struct A<1>::B
{
    static constexpr bool x = true;
};

static_assert(A<0>::B<int>::x); // error: implicit instantiation of undefined template 'A<1>::B<int>'
```
This currently results in a crash on trunk. With this patch applied, we instantiate the undefined class template declared in the definition of `A` and complain.

These differences in behavior arise from the fact that we bind names to the most recent redeclaration of an entity when creating `Expr` nodes that refer to that entity. In the above example, the explicit specialization of `A<1>::B` is declared after it is referenced in the explicit specialization of `A<0>::B`, resulting in the initial declaration being used to instantiate `B<int>`.

IMO this behavior is correct per [[temp.expl.spec] p7](http://eel.is/c++draft/temp.expl.spec#7):
> If a template, a member template or a member of a class template is explicitly specialized, a declaration of that specialization shall be reachable from every use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.

However, I would like to know what @erichkeane, @mizvekov, and @zygoloid think.

In any case, the QT example can be fixed by reordering the explicit specialization such that each specialization is declared before being referenced.

https://github.com/llvm/llvm-project/pull/106585


More information about the cfe-commits mailing list