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

Reply via email to