[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