Author: firstmoonlight
Date: 2026-06-08T13:21:47Z
New Revision: 55611deca57a0843cbfceca50ccbdfa9e1a3bf84

URL: 
https://github.com/llvm/llvm-project/commit/55611deca57a0843cbfceca50ccbdfa9e1a3bf84
DIFF: 
https://github.com/llvm/llvm-project/commit/55611deca57a0843cbfceca50ccbdfa9e1a3bf84.diff

LOG: [clang][Sema]fix crash of invalid friend declaration with storage-class 
specifier (#190597)

Fix an assertion failure in Sema::ActOnFriendTypeDecl when parsing an
invalid friend type declaration that incorrectly includes a
storage-class specifier (e.g., 'static', 'extern', 'register').

Root cause:
If the type specifier is marked as invalid, DeclSpec::Finish returns
early. However, even when the type specifier is invalid, some other
checks can still be performed instead of skipping everything.

This change allows necessary checks to proceed, preventing the
assertion in ActOnFriendTypeDecl and enabling proper error diagnostics.

Fixes: https://github.com/llvm/llvm-project/issues/186569

Co-authored-by: victorl <[email protected]>

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Sema/DeclSpec.h
    clang/lib/Sema/DeclSpec.cpp
    clang/test/CXX/class/class.friend/p6.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f97e90634396a..f8bb0b48e2512 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -733,6 +733,7 @@ Bug Fixes to C++ Support
 - Fixed a use-after-free bug when parsing default arguments containing lambdas 
in declarations with template-id declarators. (#GH196725)
 - Fixed a crash in constant evaluation using placement new on an array which 
was later initialized. (#GH196450)
 - Fixed an issue where Clang incorrectly accepted invalid unqualified uses of 
local nested class names outside their declaring scope. (#GH184622)
+- Fixed a crash when parsing invalid friend declaration with storage-class 
specifier. (#GH186569)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/Sema/DeclSpec.h 
b/clang/include/clang/Sema/DeclSpec.h
index b3c459821c79c..6e7f9cd6e3d38 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -889,6 +889,10 @@ 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);
+
+  void CheckFriendSpec(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 660b1805c450e..2add7c6aa3080 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -1162,6 +1162,20 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy 
&Policy) {
 
   // Check the type specifier components first. No checking for an invalid
   // type.
+  CheckTypeSpec(S, Policy);
+
+  CheckFriendSpec(S, Policy);
+
+  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;
 
@@ -1441,6 +1455,9 @@ 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);
+}
+
+void DeclSpec::CheckFriendSpec(Sema &S, const PrintingPolicy &Policy) {
   // C++ [class.friend]p6:
   //   No storage-class-specifier shall appear in the decl-specifier-seq
   //   of a friend declaration.
@@ -1498,14 +1515,6 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy 
&Policy) {
     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