Skip to content

Conversation

mizvekov
Copy link
Contributor

@mizvekov mizvekov commented Sep 3, 2025

This fixes a regression which was introduced in #147835.

Since this regression was never released, there are no release notes.

Fixes #156458

This fixes a regression which was introduced in #147835.

Since this regression was never released, there are no release notes.

Fixes #156458
@mizvekov mizvekov self-assigned this Sep 3, 2025
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Sep 3, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 3, 2025

@llvm/pr-subscribers-clang

Author: Matheus Izvekov (mizvekov)

Changes

This fixes a regression which was introduced in #147835.

Since this regression was never released, there are no release notes.

Fixes #156458


Full diff: https://github.com/llvm/llvm-project/pull/156772.diff

5 Files Affected:

  • (modified) clang/include/clang/Sema/Sema.h (+1-1)
  • (modified) clang/lib/Parse/ParseDeclCXX.cpp (+2-2)
  • (modified) clang/lib/Sema/SemaCXXScopeSpec.cpp (+60-48)
  • (modified) clang/lib/Sema/SemaDeclCXX.cpp (+5-4)
  • (added) clang/test/SemaCXX/GH156458.cpp (+12)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c3fb57774c8dc..f20c1e25a384d 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5363,7 +5363,7 @@ class Sema final : public SemaBase {
                                   SourceLocation UsingLoc,
                                   SourceLocation EnumLoc, SourceRange TyLoc,
                                   const IdentifierInfo &II, ParsedType Ty,
-                                  CXXScopeSpec *SS = nullptr);
+                                  const CXXScopeSpec &SS);
   Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS,
                               MultiTemplateParamsArg TemplateParams,
                               SourceLocation UsingLoc, UnqualifiedId &Name,
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 8135f4f603907..19f94122f151e 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -672,7 +672,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
           /*WantNontrivialTypeSourceInfo=*/true);
 
       UED = Actions.ActOnUsingEnumDeclaration(
-          getCurScope(), AS, UsingLoc, UELoc, IdentLoc, *IdentInfo, Type, &SS);
+          getCurScope(), AS, UsingLoc, UELoc, IdentLoc, *IdentInfo, Type, SS);
     } else if (Tok.is(tok::annot_template_id)) {
       TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
 
@@ -687,7 +687,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
 
         UED = Actions.ActOnUsingEnumDeclaration(getCurScope(), AS, UsingLoc,
                                                 UELoc, Loc, *TemplateId->Name,
-                                                Type.get(), &SS);
+                                                Type.get(), SS);
       } else {
         Diag(Tok.getLocation(), diag::err_using_enum_not_enum)
             << TemplateId->Name->getName()
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index ef14dde5203a6..437c69aa1587d 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -398,6 +398,54 @@ class NestedNameSpecifierValidatorCCC final
 
 }
 
+[[nodiscard]] static bool ExtendNestedNameSpecifier(Sema &S, CXXScopeSpec &SS,
+                                                    const NamedDecl *ND,
+                                                    SourceLocation NameLoc,
+                                                    SourceLocation CCLoc) {
+  TypeLocBuilder TLB;
+  QualType T;
+  if (const auto *USD = dyn_cast<UsingShadowDecl>(ND)) {
+    T = S.Context.getUsingType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
+                               USD);
+    TLB.push<UsingTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(),
+                                  SS.getWithLocInContext(S.Context), NameLoc);
+  } else if (const auto *TD = dyn_cast<TypeDecl>(ND)) {
+    T = S.Context.getTypeDeclType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
+                                  TD);
+    switch (T->getTypeClass()) {
+    case Type::Record:
+    case Type::InjectedClassName:
+    case Type::Enum: {
+      auto TTL = TLB.push<TagTypeLoc>(T);
+      TTL.setElaboratedKeywordLoc(SourceLocation());
+      TTL.setQualifierLoc(SS.getWithLocInContext(S.Context));
+      TTL.setNameLoc(NameLoc);
+      break;
+    }
+    case Type::Typedef:
+      TLB.push<TypedefTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(),
+                                      SS.getWithLocInContext(S.Context),
+                                      NameLoc);
+      break;
+    case Type::UnresolvedUsing:
+      TLB.push<UnresolvedUsingTypeLoc>(T).set(
+          /*ElaboratedKeywordLoc=*/SourceLocation(),
+          SS.getWithLocInContext(S.Context), NameLoc);
+      break;
+    default:
+      assert(SS.isEmpty());
+      T = S.Context.getTypeDeclType(TD);
+      TLB.pushTypeSpec(T).setNameLoc(NameLoc);
+      break;
+    }
+  } else {
+    return false;
+  }
+  SS.clear();
+  SS.Make(S.Context, TLB.getTypeLocInContext(S.Context, T), CCLoc);
+  return true;
+}
+
 bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
                                        bool EnteringContext, CXXScopeSpec &SS,
                                        NamedDecl *ScopeLookupResult,
@@ -653,40 +701,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
     if (isa<EnumDecl>(TD))
       Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec);
 
-    QualType T;
-    TypeLocBuilder TLB;
-    if (const auto *USD = dyn_cast<UsingShadowDecl>(SD)) {
-      T = Context.getUsingType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
-                               USD);
-      TLB.push<UsingTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(),
-                                    SS.getWithLocInContext(Context),
-                                    IdInfo.IdentifierLoc);
-    } else if (const auto *Tag = dyn_cast<TagDecl>(TD)) {
-      T = Context.getTagType(ElaboratedTypeKeyword::None, SS.getScopeRep(), Tag,
-                             /*OwnsTag=*/false);
-      auto TTL = TLB.push<TagTypeLoc>(T);
-      TTL.setElaboratedKeywordLoc(SourceLocation());
-      TTL.setQualifierLoc(SS.getWithLocInContext(SemaRef.Context));
-      TTL.setNameLoc(IdInfo.IdentifierLoc);
-    } else if (auto *TN = dyn_cast<TypedefNameDecl>(TD)) {
-      T = Context.getTypedefType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
-                                 TN);
-      TLB.push<TypedefTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(),
-                                      SS.getWithLocInContext(SemaRef.Context),
-                                      IdInfo.IdentifierLoc);
-    } else if (auto *UD = dyn_cast<UnresolvedUsingTypenameDecl>(TD)) {
-      T = Context.getUnresolvedUsingType(ElaboratedTypeKeyword::None,
-                                         SS.getScopeRep(), UD);
-      TLB.push<UnresolvedUsingTypeLoc>(T).set(
-          /*ElaboratedKeywordLoc=*/SourceLocation(),
-          SS.getWithLocInContext(SemaRef.Context), IdInfo.IdentifierLoc);
-    } else {
-      assert(SS.isEmpty());
-      T = Context.getTypeDeclType(TD);
-      TLB.pushTypeSpec(T).setNameLoc(IdInfo.IdentifierLoc);
-    }
-    SS.clear();
-    SS.Make(Context, TLB.getTypeLocInContext(Context, T), IdInfo.CCLoc);
+    [[maybe_unused]] bool IsType = ::ExtendNestedNameSpecifier(
+        *this, SS, SD, IdInfo.IdentifierLoc, IdInfo.CCLoc);
+    assert(IsType && "unhandled declaration kind");
     return false;
   }
 
@@ -762,21 +779,16 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
   }
 
   if (!Found.empty()) {
-    if (TypeDecl *TD = Found.getAsSingle<TypeDecl>()) {
-      QualType T;
-      if (auto *TN = dyn_cast<TypedefNameDecl>(TD)) {
-        T = Context.getTypedefType(ElaboratedTypeKeyword::None,
-                                   SS.getScopeRep(), TN);
-      } else {
-        // FIXME: Enumerate the possibilities here.
-        assert(!isa<TagDecl>(TD));
-        assert(SS.isEmpty());
-        T = Context.getTypeDeclType(TD);
-      }
-
+    const auto *ND = Found.getAsSingle<NamedDecl>();
+    if (::ExtendNestedNameSpecifier(*this, SS, ND, IdInfo.IdentifierLoc,
+                                    IdInfo.CCLoc)) {
+      const Type *T = SS.getScopeRep().getAsType();
       Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace)
-          << T << getLangOpts().CPlusPlus;
-    } else if (Found.getAsSingle<TemplateDecl>()) {
+          << QualType(T, 0) << getLangOpts().CPlusPlus;
+      // Recover with this type if it would be a valid nested name specifier.
+      return !T->getAsCanonical<TagType>();
+    }
+    if (isa<TemplateDecl>(ND)) {
       ParsedType SuggestedType;
       DiagnoseUnknownTypeName(IdInfo.Identifier, IdInfo.IdentifierLoc, S, &SS,
                               SuggestedType);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 4b0dead182543..63ce87b9b0607 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -12628,16 +12628,17 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
                                       SourceLocation UsingLoc,
                                       SourceLocation EnumLoc, SourceRange TyLoc,
                                       const IdentifierInfo &II, ParsedType Ty,
-                                      CXXScopeSpec *SS) {
-  assert(SS && !SS->isInvalid() && "ScopeSpec is invalid");
+                                      const CXXScopeSpec &SS) {
   TypeSourceInfo *TSI = nullptr;
   SourceLocation IdentLoc = TyLoc.getBegin();
   QualType EnumTy = GetTypeFromParser(Ty, &TSI);
   if (EnumTy.isNull()) {
-    Diag(IdentLoc, isDependentScopeSpecifier(*SS)
+    Diag(IdentLoc, isDependentScopeSpecifier(SS)
                        ? diag::err_using_enum_is_dependent
                        : diag::err_unknown_typename)
-        << II.getName() << SourceRange(SS->getBeginLoc(), TyLoc.getEnd());
+        << II.getName()
+        << SourceRange(SS.isValid() ? SS.getBeginLoc() : IdentLoc,
+                       TyLoc.getEnd());
     return nullptr;
   }
 
diff --git a/clang/test/SemaCXX/GH156458.cpp b/clang/test/SemaCXX/GH156458.cpp
new file mode 100644
index 0000000000000..1e054a0958a83
--- /dev/null
+++ b/clang/test/SemaCXX/GH156458.cpp
@@ -0,0 +1,12 @@
+//RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+// Force a fatal error
+#include <unknownheader> // expected-error {{file not found}}
+
+namespace N {}
+
+enum class E {};
+using enum N::E::V;
+
+using T = int;
+using enum N::T::v;

@mizvekov mizvekov merged commit f3dcec0 into main Sep 4, 2025
12 checks passed
@mizvekov mizvekov deleted the users/mizvekov/GH156458 branch September 4, 2025 00:27
ckoparkar added a commit to ckoparkar/llvm-project that referenced this pull request Sep 4, 2025
* main: (1483 commits)
  [clang] fix error recovery for invalid nested name specifiers (llvm#156772)
  Revert "[lldb] Add count for errors of DWO files in statistics and combine DWO file count functions" (llvm#156777)
  AMDGPU: Add agpr variants of multi-data DS instructions (llvm#156420)
  [libc][NFC] disable localtime on aarch64/baremetal (llvm#156776)
  [win/asan] Improve SharedReAlloc with HEAP_REALLOC_IN_PLACE_ONLY. (llvm#132558)
  [LLDB] Make internal shell the default for running LLDB lit tests. (llvm#156729)
  [lldb][debugserver] Max response size for qSpeedTest (llvm#156099)
  [AMDGPU] Define 1024 VGPRs on gfx1250 (llvm#156765)
  [flang] Check for BIND(C) name conflicts with alternate entries (llvm#156563)
  [RISCV] Add exhausted_gprs_fprs test to calling-conv-half.ll. NFC (llvm#156586)
  [NFC] Remove trailing whitespaces from `clang/include/clang/Basic/AttrDocs.td`
  [lldb] Mark scripted frames as synthetic instead of artificial (llvm#153117)
  [docs] Refine some of the wording in the quality developer policy (llvm#156555)
  [MLIR] Apply clang-tidy fixes for readability-identifier-naming in TransformOps.cpp (NFC)
  [MLIR] Add LDBG() tracing to VectorTransferOpTransforms.cpp (NFC)
  [NFC] Apply clang-format to PPCInstrFutureMMA.td (llvm#156749)
  [libc] implement template functions for localtime (llvm#110363)
  [llvm-objcopy][COFF] Update .symidx values after stripping (llvm#153322)
  Add documentation on debugging LLVM.
  [lldb] Add count for errors of DWO files in statistics and combine DWO file count functions (llvm#155023)
  ...
@zwuis zwuis added the skip-precommit-approval PR for CI feedback, not intended for review label Sep 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category skip-precommit-approval PR for CI feedback, not intended for review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[clang] Assertion failure with unknown header
3 participants