llvm / llvm/llvm-project

[Clang] Variable-template specialization of a type trait caches a stable value when first instantiated during enclosing-class completion

Open
#204,665 2 comments 0 reactions 0 assignees View on GitHub
clang:frontend concepts
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Clang evaluates a variable-template specialization to `false` while the equivalent class-template and builtin spellings yield `true` for the same type. The wrong value comes from the variable template being first instantiated while the enclosing class is still incomplete; the poisoned cache value is then re-used at the point of use.

### Minimal reproeducer

https://godbolt.org/z/dfzEd6jMz

```cxx
template
constexpr bool is_constructible_v = __is_constructible(T, A...);

template
struct x {
constexpr x() requires is_constructible_v {}
};

struct wrapped {
struct inner { bool _{}; };
x _;
};

static_assert(__is_constructible(wrapped::inner)); // ok
static_assert(is_constructible_v); // error
```

`is_constructible_v` is defined as `__is_constructible(T)`, so the two `static_assert`s should both pass or fail -- yet only the variable-template form fails.

### Expected
Both assertions pass (`wrapped::inner` is trivially default-constructible).

### Actual
The second assertion fails. With ``, the divergence is visible across all three equivalent spellings:

```cxx
static_assert(__is_constructible(wrapped::inner)); // ok
static_assert(std::is_constructible::value); // ok
static_assert(std::is_constructible_v); // error
```

### Reduction
1. `inner` is **nested** inside `wrapped`
2. `inner` has a **initializer**
3. The member `x` evaluates a **`requires is_constructible_v`** constraint during `wrapped`'s completion

Contributor guide

Open the contributing guide

Research direction

Start by compiling the minimal reproducer linked in the issue and compare the builtin, class-template, and variable-template assertions. Trace when is_constructible_v is first instantiated during wrapped completion and verify that the final use no longer reuses the incomplete-state value; done means both assertions pass consistently.

Written by the indexing model from the issue text.

Assessment

Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.