https://github.com/firstmoonlight updated 
https://github.com/llvm/llvm-project/pull/190597

>From a64173fcc8f4bd095bb14530cee6a9f6b9deea4c Mon Sep 17 00:00:00 2001
From: victorl <[email protected]>
Date: Wed, 8 Apr 2026 21:41:05 +0800
Subject: [PATCH] [clang][Sema]fix crash of invalid friend declaration with
 storage-class specifier

---
 clang/include/clang/Sema/DeclSpec.h      |   2 +
 clang/lib/Sema/DeclSpec.cpp              | 157 ++++++++++++-----------
 clang/test/CXX/class/class.friend/p6.cpp |   1 +
 3 files changed, 83 insertions(+), 77 deletions(-)

diff --git a/clang/include/clang/Sema/DeclSpec.h 
b/clang/include/clang/Sema/DeclSpec.h
index 6e5421c7072c7..d9e41679ba6ea 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -887,6 +887,8 @@ class DeclSpec {
   /// DeclSpec is guaranteed self-consistent, even if an error occurred.
   void Finish(Sema &S, const PrintingPolicy &Policy);
 
+  void CheckTypeSpec(Sema &S, const PrintingPolicy &Policy);
+
   const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const {
     return writtenBS;
   }
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 479a959e0aadc..68197dd872c21 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -1162,6 +1162,76 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy 
&Policy) {
 
   // Check the type specifier components first. No checking for an invalid
   // type.
+  CheckTypeSpec(S, Policy);
+
+  // C++ [class.friend]p6:
+  //   No storage-class-specifier shall appear in the decl-specifier-seq
+  //   of a friend declaration.
+  if (isFriendSpecified() &&
+      (getStorageClassSpec() || getThreadStorageClassSpec())) {
+    SmallString<32> SpecName;
+    SourceLocation SCLoc;
+    FixItHint StorageHint, ThreadHint;
+
+    if (DeclSpec::SCS SC = getStorageClassSpec()) {
+      SpecName = getSpecifierName(SC);
+      SCLoc = getStorageClassSpecLoc();
+      StorageHint = FixItHint::CreateRemoval(SCLoc);
+    }
+
+    if (DeclSpec::TSCS TSC = getThreadStorageClassSpec()) {
+      if (!SpecName.empty())
+        SpecName += " ";
+      SpecName += getSpecifierName(TSC);
+      SCLoc = getThreadStorageClassSpecLoc();
+      ThreadHint = FixItHint::CreateRemoval(SCLoc);
+    }
+
+    S.Diag(SCLoc, diag::err_friend_decl_spec)
+        << SpecName << StorageHint << ThreadHint;
+
+    ClearStorageClassSpecs();
+  }
+
+  // C++11 [dcl.fct.spec]p5:
+  //   The virtual specifier shall be used only in the initial
+  //   declaration of a non-static class member function;
+  // C++11 [dcl.fct.spec]p6:
+  //   The explicit specifier shall be used only in the declaration of
+  //   a constructor or conversion function within its class
+  //   definition;
+  if (isFriendSpecified() && (isVirtualSpecified() || hasExplicitSpecifier())) 
{
+    StringRef Keyword;
+    FixItHint Hint;
+    SourceLocation SCLoc;
+
+    if (isVirtualSpecified()) {
+      Keyword = "virtual";
+      SCLoc = getVirtualSpecLoc();
+      Hint = FixItHint::CreateRemoval(SCLoc);
+    } else {
+      Keyword = "explicit";
+      SCLoc = getExplicitSpecLoc();
+      Hint = FixItHint::CreateRemoval(getExplicitSpecRange());
+    }
+
+    S.Diag(SCLoc, diag::err_friend_decl_spec) << Keyword << Hint;
+
+    FS_virtual_specified = false;
+    FS_explicit_specifier = ExplicitSpecifier();
+    FS_virtualLoc = FS_explicitLoc = SourceLocation();
+  }
+
+  assert(!TypeSpecOwned || isDeclRep((TST)TypeSpecType));
+
+  // Okay, now we can infer the real type.
+
+  // TODO: return "auto function" and other bad things based on the real type.
+
+  // 'data definition has no type or storage class'?
+}
+
+void DeclSpec::CheckTypeSpec(Sema &S, const PrintingPolicy &Policy) {
   if (TypeSpecType == TST_error)
     return;
 
@@ -1228,8 +1298,8 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy 
&Policy) {
            (TypeSpecType != TST_int) && (TypeSpecType != TST_int128)) ||
           TypeAltiVecPixel) {
         S.Diag(TSTLoc, diag::err_invalid_vector_bool_decl_spec)
-          << (TypeAltiVecPixel ? "__pixel" :
-                                 getSpecifierName((TST)TypeSpecType, Policy));
+            << (TypeAltiVecPixel ? "__pixel"
+                                 : getSpecifierName((TST)TypeSpecType, 
Policy));
       }
       // vector bool __int128 requires Power10 (or ZVector).
       if ((TypeSpecType == TST_int128) &&
@@ -1345,10 +1415,8 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy 
&Policy) {
   // use. Need information about the backend.
   if (TypeSpecComplex != TSC_unspecified) {
     if (TypeSpecType == TST_unspecified) {
-      S.Diag(TSCLoc, diag::ext_plain_complex)
-        << FixItHint::CreateInsertion(
-                              S.getLocForEndOfToken(getTypeSpecComplexLoc()),
-                                                 " double");
+      S.Diag(TSCLoc, diag::ext_plain_complex) << FixItHint::CreateInsertion(
+          S.getLocForEndOfToken(getTypeSpecComplexLoc()), " double");
       TypeSpecType = TST_double;   // _Complex -> _Complex double.
     } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
       // Note that this intentionally doesn't include _Complex _Bool.
@@ -1378,14 +1446,14 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy 
&Policy) {
       if (S.getSourceManager().isBeforeInTranslationUnit(
             getThreadStorageClassSpecLoc(), getStorageClassSpecLoc()))
         S.Diag(getStorageClassSpecLoc(),
-             diag::err_invalid_decl_spec_combination)
-          << DeclSpec::getSpecifierName(getThreadStorageClassSpec())
-          << SourceRange(getThreadStorageClassSpecLoc());
+               diag::err_invalid_decl_spec_combination)
+            << DeclSpec::getSpecifierName(getThreadStorageClassSpec())
+            << SourceRange(getThreadStorageClassSpecLoc());
       else
         S.Diag(getThreadStorageClassSpecLoc(),
-             diag::err_invalid_decl_spec_combination)
-          << DeclSpec::getSpecifierName(getStorageClassSpec())
-          << SourceRange(getStorageClassSpecLoc());
+               diag::err_invalid_decl_spec_combination)
+            << DeclSpec::getSpecifierName(getStorageClassSpec())
+            << SourceRange(getStorageClassSpecLoc());
       // Discard the thread storage class specifier to recover.
       ThreadStorageClassSpec = TSCS_unspecified;
       ThreadStorageClassSpecLoc = SourceLocation();
@@ -1442,71 +1510,6 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy 
&Policy) {
     S.Diag(ConstexprLoc, diag::warn_cxx20_compat_consteval);
   else if (getConstexprSpecifier() == ConstexprSpecKind::Constinit)
     S.Diag(ConstexprLoc, diag::warn_cxx20_compat_constinit);
-  // C++ [class.friend]p6:
-  //   No storage-class-specifier shall appear in the decl-specifier-seq
-  //   of a friend declaration.
-  if (isFriendSpecified() &&
-      (getStorageClassSpec() || getThreadStorageClassSpec())) {
-    SmallString<32> SpecName;
-    SourceLocation SCLoc;
-    FixItHint StorageHint, ThreadHint;
-
-    if (DeclSpec::SCS SC = getStorageClassSpec()) {
-      SpecName = getSpecifierName(SC);
-      SCLoc = getStorageClassSpecLoc();
-      StorageHint = FixItHint::CreateRemoval(SCLoc);
-    }
-
-    if (DeclSpec::TSCS TSC = getThreadStorageClassSpec()) {
-      if (!SpecName.empty()) SpecName += " ";
-      SpecName += getSpecifierName(TSC);
-      SCLoc = getThreadStorageClassSpecLoc();
-      ThreadHint = FixItHint::CreateRemoval(SCLoc);
-    }
-
-    S.Diag(SCLoc, diag::err_friend_decl_spec)
-      << SpecName << StorageHint << ThreadHint;
-
-    ClearStorageClassSpecs();
-  }
-
-  // C++11 [dcl.fct.spec]p5:
-  //   The virtual specifier shall be used only in the initial
-  //   declaration of a non-static class member function;
-  // C++11 [dcl.fct.spec]p6:
-  //   The explicit specifier shall be used only in the declaration of
-  //   a constructor or conversion function within its class
-  //   definition;
-  if (isFriendSpecified() && (isVirtualSpecified() || hasExplicitSpecifier())) 
{
-    StringRef Keyword;
-    FixItHint Hint;
-    SourceLocation SCLoc;
-
-    if (isVirtualSpecified()) {
-      Keyword = "virtual";
-      SCLoc = getVirtualSpecLoc();
-      Hint = FixItHint::CreateRemoval(SCLoc);
-    } else {
-      Keyword = "explicit";
-      SCLoc = getExplicitSpecLoc();
-      Hint = FixItHint::CreateRemoval(getExplicitSpecRange());
-    }
-
-    S.Diag(SCLoc, diag::err_friend_decl_spec)
-      << Keyword << Hint;
-
-    FS_virtual_specified = false;
-    FS_explicit_specifier = ExplicitSpecifier();
-    FS_virtualLoc = FS_explicitLoc = SourceLocation();
-  }
-
-  assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType));
-
-  // Okay, now we can infer the real type.
-
-  // TODO: return "auto function" and other bad things based on the real type.
-
-  // 'data definition has no type or storage class'?
 }
 
 bool DeclSpec::isMissingDeclaratorOk() {
diff --git a/clang/test/CXX/class/class.friend/p6.cpp 
b/clang/test/CXX/class/class.friend/p6.cpp
index e4c59f781e3de..a96dd8a3d4e4a 100644
--- a/clang/test/CXX/class/class.friend/p6.cpp
+++ b/clang/test/CXX/class/class.friend/p6.cpp
@@ -19,4 +19,5 @@ class A {
 #else
   friend thread_local class G; // expected-error {{'thread_local' is invalid 
in friend declarations}}
 #endif
+  friend register enum; // expected-error {{expected identifier or '{'}} 
expected-error {{'register' is invalid in friend declarations}}
 };

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to