[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 8 03:07:22 PDT 2026
https://github.com/firstmoonlight updated https://github.com/llvm/llvm-project/pull/190597
>From e6b542ad65ca92878235cc8787c9f329f52c398d Mon Sep 17 00:00:00 2001
From: victorl <liuvicsen at gmail.com>
Date: Wed, 8 Apr 2026 21:41:05 +0800
Subject: [PATCH] [clang][Sema]fix crash of invalid friend declaration with
storage-class specifier
Fix an assertion in ActOnFriendTypeDecl triggered by friend declarations
with storage-class specifiers.
The fix factors out type specifier validation into CheckTypeSpec and
moves the early return logic there. This allows the caller to proceed
with remaining checks even if a type specifier is invalid, preventing
the downstream assertion.
---
clang/docs/ReleaseNotes.rst | 1 +
clang/include/clang/Sema/DeclSpec.h | 4 ++++
clang/lib/Sema/DeclSpec.cpp | 25 ++++++++++++++++--------
clang/test/CXX/class/class.friend/p6.cpp | 1 +
4 files changed, 23 insertions(+), 8 deletions(-)
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}}
};
More information about the cfe-commits
mailing list