Skip to content

Commit 9929506

Browse files
sdkrystianlouistatta
authored andcommitted
Add Krystian's Q4 2024 Update
1 parent 4b0f629 commit 9929506

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed
+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
layout: post
3+
nav-class: dark
4+
categories: krystian
5+
title: Krystian's Q4 2024 Update
6+
author-id: krystian
7+
---
8+
9+
# Clang
10+
11+
This quarter, I continued working on the *fourth* iteration of my [refactoring of multi-level template argument list collection](https://github.com/llvm/llvm-project/pull/111852) ([#112381](https://github.com/llvm/llvm-project/pull/112381), [#114258](https://github.com/llvm/llvm-project/pull/114258) and [#114569](https://github.com/llvm/llvm-project/pull/114569) related), fixed support for the `@relates` command, made improvements to C++ conformance, amongst other things.
12+
13+
## Multi-level template argument list collection (again)
14+
15+
[My initial patch](https://github.com/llvm/llvm-project/pull/106585) that refactored multi-level template argument list collection proved to have some nasty bugs relating to instantiation order. The following is a reduction of a reported regression when compiling QT:
16+
17+
```cpp
18+
template<int N>
19+
struct A
20+
{
21+
template<typename T>
22+
static constexpr bool f();
23+
};
24+
25+
template<>
26+
template<typename T>
27+
constexpr bool A<0>::f()
28+
{
29+
return A<1>::f<T>(); // note: undefined function 'f<int>' cannot be used in a constant expression
30+
}
31+
32+
template<>
33+
template<typename T>
34+
constexpr bool A<1>::f()
35+
{
36+
return true;
37+
}
38+
39+
static_assert(A<0>::f<int>()); // error: static assertion expression is not an integral constant expression
40+
```
41+
42+
I initially thought Clang was correct to complain here, since the member specialization `A<1>::f` does not precede its first use (lexically), ergo IFNDR per [[temp.expl.spec] p7](http://eel.is/c++draft/temp.expl.spec#7):
43+
> 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.
44+
45+
However, the declaration of the member specialization is reachable from a point in the *instantiation context* of the definition of `A<0>::f<int>` (that being, immediately prior to the _static_assert-declaration_), so this example is indeed valid.
46+
47+
## Explicit specialization of members of partial specializations
48+
49+
On the C++ conformance side of things, I landed a [patch](https://github.com/llvm/llvm-project/pull/113464) implementing [[temp.spec.partial.member] p2](http://eel.is/c++draft/temp.spec.partial.member#2):
50+
> If the primary member template is explicitly specialized for a given (implicit) specialization of the enclosing class template, the partial specializations of the member template are ignored for this specialization of the enclosing class template.
51+
If a partial specialization of the member template is explicitly specialized for a given (implicit) specialization of the enclosing class template, the primary member template and its other partial specializations are still considered for this specialization of the enclosing class template.
52+
53+
Its meaning can be illustrated via the following:
54+
```cpp
55+
template<typename T>
56+
struct A
57+
{
58+
template<typename U>
59+
struct B
60+
{
61+
static constexpr int x = 0; // #1
62+
};
63+
64+
template<typename U>
65+
struct B<U*>
66+
{
67+
static constexpr int x = 1; // #2
68+
};
69+
};
70+
71+
template<>
72+
template<typename U>
73+
struct A<long>::B
74+
{
75+
static constexpr int x = 2; // #3
76+
};
77+
78+
static_assert(A<short>::B<int>::y == 0); // uses #1
79+
static_assert(A<short>::B<int*>::y == 1); // uses #2
80+
81+
static_assert(A<long>::B<int>::y == 2); // uses #3
82+
static_assert(A<long>::B<int*>::y == 2); // uses #3
83+
```
84+
85+
Since the primary member template `A<long>::B` is explicitly specialized for a given (implicit) specialization of its enclosing class template, the partial specialization `B<U*>` will be ignored when instantiating a specialization of `B`.

0 commit comments

Comments
 (0)