https://github.com/matthiasgoergens created
https://github.com/llvm/llvm-project/pull/214520
Fixes llvm/llvm-project#212988.
## Cause
`ParseOptionalCXXScopeSpecifier` first accepts a leading global `::`, then
recognises `__super::` as though the scope specifier were still empty.
`NestedNameSpecifierLocBuilder::MakeMicrosoftSuper` replaces the semantic
representation but appends its locations to the existing global-qualifier
buffer. The representation and source locations therefore disagree, tripping
the range invariant in an assertions build (`DeclSpec.cpp:93`: `Range ==
Builder.getSourceRange() && "NestedNameSpecifierLoc range computation
incorrect"`); a release build silently discards the global qualifier.
## Fix
The parser now recognises a complete `__super::` scope only when no qualifier
has already been accumulated. Ordinary qualified-id parsing then rejects
`::__super::` with one `expected unqualified-id` diagnostic. The predicate
continues to enter the existing recovery path for malformed `::__super` without
a trailing `::`, preserving its more specific diagnostic.
## Trigger (reproduction on current main)
The exact issue reproducer — a globally qualified `::__super::T` under
`-fms-compatibility` — aborts at `DeclSpec.cpp:93` on an unmodified assertions
build of main.
## Verification
- The exact issue reproducer aborts at `DeclSpec.cpp:93` on unmodified main and
produces one ordinary diagnostic with the fix.
- The regression test uses the actual issue reproducer, `::__super::XXX x; //
expected-error {{expected unqualified-id}}`, and discriminates in both build
modes: an unpatched release build silently accepts it (lit FAIL) while an
unpatched assertions build aborts at `DeclSpec.cpp:93` (lit FAIL, SIGABRT);
patched builds pass in both modes. (A bare `::__super::;` was rejected even by
an unpatched release build, so it pinned the bug only via the assert abort.)
- A six-case matrix covers valid type and expression uses plus global, named,
repeated, and expression-form invalid qualifiers. Valid cases compile; every
invalid case produces one diagnostic without a crash or cascade.
- `clang/test/SemaCXX/MicrosoftSuper.cpp` contains the exact regression.
- All 1,436 SemaCXX tests pass: 1,424 passed, 11 unsupported, 1 expected
failure.
- All 418 Parser tests pass: 416 passed, 1 unsupported, 1 expected failure.
This suite exposed and prevented a first-draft diagnostic regression in the
pre-existing `::__super` recovery case.
- An independent call-path audit found no other source-parser route that can
pass a non-empty scope to `ActOnSuperScopeSpecifier`.
- `git diff --check` passes.
Upstream state as of 2026-08-06: issue open and unassigned, no competing PR
found, fix rebases cleanly onto current main.
From 02485465bd5dddfffed530d60f69764ded47155a Mon Sep 17 00:00:00 2001
From: Matthias Goergens <[email protected]>
Date: Sun, 2 Aug 2026 23:49:14 +0800
Subject: [PATCH 1/2] [clang][Parser] Reject qualified __super specifiers
---
clang/lib/Parse/ParseExprCXX.cpp | 3 ++-
clang/test/SemaCXX/MicrosoftSuper.cpp | 4 ++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 06ff45da413ca..97a9e49308258 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -153,7 +153,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
}
}
- if (Tok.is(tok::kw___super)) {
+ if (Tok.is(tok::kw___super) &&
+ (!HasScopeSpecifier || NextToken().isNot(tok::coloncolon))) {
SourceLocation SuperLoc = ConsumeToken();
if (!Tok.is(tok::coloncolon)) {
Diag(Tok.getLocation(), diag::err_expected_coloncolon_after_super);
diff --git a/clang/test/SemaCXX/MicrosoftSuper.cpp
b/clang/test/SemaCXX/MicrosoftSuper.cpp
index d117b93523363..89445b512b409 100644
--- a/clang/test/SemaCXX/MicrosoftSuper.cpp
+++ b/clang/test/SemaCXX/MicrosoftSuper.cpp
@@ -156,3 +156,7 @@ struct A : B {
void f() { int a = this->__super::a; }
};
}
+
+struct InvalidGlobalQualifier : Base1 {
+ ::__super::; // expected-error {{expected unqualified-id}}
+};
From 6941237585c93ae901c98dd30d0b7684ccf17072 Mon Sep 17 00:00:00 2001
From: Matthias Goergens <[email protected]>
Date: Thu, 6 Aug 2026 22:26:16 +0800
Subject: [PATCH 2/2] [clang][Parser] Strengthen qualified __super regression
test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
A bare '::__super::;' already yields 'expected unqualified-id' on an
unpatched release build, so the previous test only pinned the bug via
the assertion abort in asserts builds. Use '::__super::XXX x;' — the
original issue reproducer — which an unpatched release build silently
accepts, so the test now discriminates in both release and asserts
builds.
---
clang/test/SemaCXX/MicrosoftSuper.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang/test/SemaCXX/MicrosoftSuper.cpp
b/clang/test/SemaCXX/MicrosoftSuper.cpp
index 89445b512b409..31cc6b1130b73 100644
--- a/clang/test/SemaCXX/MicrosoftSuper.cpp
+++ b/clang/test/SemaCXX/MicrosoftSuper.cpp
@@ -158,5 +158,7 @@ struct A : B {
}
struct InvalidGlobalQualifier : Base1 {
- ::__super::; // expected-error {{expected unqualified-id}}
+ // In a release build without assertions the global qualifier is silently
+ // discarded, so this must be a use that would compile without the fix.
+ ::__super::XXX x; // expected-error {{expected unqualified-id}}
};
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits