llvm / llvm/llvm-project

[clang] P3310 reverses partial ordering when template-template and template-id packs are empty

Open
#216,092 3 comments 0 reactions 0 assignees View on GitHub
clang:frontend
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Reproducer

```cpp
template
struct select;

template class C, class A, class... Rest>
struct select> { // candidate 1
static const int value = 1;
};

template class C, class A>
struct select> { // candidate 2
static const int value = 2;
};

template
struct unary;

static_assert(select>::value == 2, "");
```

```console
$ clang++ -std=c++11 -pedantic-errors -fsyntax-only repro.cpp
repro.cpp:18:15: error: static assertion failed due to requirement
'select>::value == 2'
repro.cpp:18:41: note: expression evaluates to '1 == 2'
```

## Expected result

Clang should select candidate 2. Its template-template parameter has the same
one-parameter template head as `unary`. Candidate 1 matches by leaving both
trailing packs empty.

Clang 19, Apple Clang 17, and GCC 15 select candidate 2. Clang 20 through
current trunk select candidate 1. Clang 20 selects candidate 2 with
`-fno-relaxed-template-template-args`.

## Regression

#124137 introduced the change while implementing P3310 and CWG2398. P3310's
invented default arguments take part in candidate-to-candidate partial ordering,
where Clang no longer has the actual `unary` template head. The variadic
candidate then wins.

A fix must preserve the `type_pack3` case in
`clang/test/SemaTemplate/cwg2398.cpp`. That case passes a template with a
defaulted second parameter and should select the variadic partial.

CWG1432 remains open, and Clang labels its implementation as provisional.
Please confirm whether the fixed partial should win when its template-template
parameter matches the actual template head and each competing mismatch comes
from a trailing template-template parameter pack.

## Related work

- #124137 implemented the P3310 and CWG2398 changes.
- #129436 fixed a code-completion crash in the CWG1432 tie-breaker.
- #177233 covers a separate function-template ordering case.
- [P3310R6](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3310r6.html)
- [CWG1432](https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1432)

Contributor guide

Open the contributing guide

Research direction

Start by running the provided C++11 reproducer and reading clang/test/SemaTemplate/cwg2398.cpp, especially the type_pack3 case. Trace the P3310 and CWG2398 partial-ordering behavior introduced by #124137, then verify that the reproducer selects candidate 2 while type_pack3 still selects the variadic partial.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.