[clang] [Clang] Fix crash when type-name is combined with class specifier in template argument (PR #191689)

Oliver Hunt via cfe-commits cfe-commits at lists.llvm.org
Sun Apr 19 17:04:47 PDT 2026


================
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s
+
+class A {
+public:
+    class B {};
+};
+
+using X = A::B;
+
+class C {
+    template <typename T = X class A::B> void f();
+    // expected-error at -1 {{cannot combine with previous 'type-name' declaration specifier}}
+};
----------------
ojhunt wrote:

We should reduce this test a lot. Fuzzer generated test cases are often much more complex than necessary, as they trip the error with whatever random code they happen to have at that point, whether or not all of the test is needed.

This fault is related to multiple qualifiers/specifiers, so I worked to remove things that did not seem related to what was failing. So, first I just made `C` use `X class A::B field` as that's clearly the problematic decl, and then removed different parts.

Then I moved it out of a class, and tried simplifying each part of the `X class A::B` - e.g. `X int` `int class A::B`, and both were required, so I then tried replacing X with `A::B class A::B` which didn't work. I then changed X to `using X=int`, and this asserted.

After consideration I realized `A::B class A::B` would syntactically force a different path, and replaced that with a single token type name, giving this reduced test case:

```cpp
struct A {
  struct B{};
};

A struct A::B i;
```

Removing templates, alias definitions, etc (struct instead of class just to remove "public:", it's a no op semantically).

With that in place we know the issue is specifically the scoped name going wrong, which means we can think about other scoping, and yes

```cpp
namespace NS{ struct S{}; };
A struct NS::S i;
```

trips it, at which point I realized that the _absolute_ minimal test case to reproduce this is:

```cpp
struct S{};
S struct ::S test;
```

Here's the test case I'd make:

```cpp
struct A {
  struct B{};
};

A struct A::B i;

struct S{};
S struct A::B i;

using T = int;
T struct A::B i;

// Any
namespace NS {
  struct Scoped{};
};

S struct NS::Scoped i;

S struct ::S i;
```

Which covers the varying different scoping paths.

This makes me think the current fix _might_ not be correct.

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


More information about the cfe-commits mailing list