[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
github-actions[bot] wrote: @firstmoonlight Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested by our [build bots](https://lab.llvm.org/buildbot/). If there is a problem with a build, you may receive a report in an email or a comment on this PR. Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues. How to do this, and the rest of the post-merge process, is covered in detail [here](https://llvm.org/docs/MyFirstTypoFix.html#myfirsttypofix-issues-after-landing-your-pr). If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of [LLVM development](https://llvm.org/docs/DeveloperPolicy.html#patch-reversion-policy). You can fix your changes and open a new PR to merge them again. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! https://github.com/llvm/llvm-project/pull/190597 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
https://github.com/AaronBallman closed https://github.com/llvm/llvm-project/pull/190597 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
https://github.com/AaronBallman auto_merge_enabled https://github.com/llvm/llvm-project/pull/190597 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
firstmoonlight wrote: > Do you need someone to land this? I will be traveling soon but hopefully > @AaronBallman can take care of it Thanks! Yes, please let @Aaron Ballman take care of landing it. I've been pretty busy with work lately and haven't been following this closely. Thanks for the reminder. https://github.com/llvm/llvm-project/pull/190597 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
https://github.com/firstmoonlight updated
https://github.com/llvm/llvm-project/pull/190597
>From e6b542ad65ca92878235cc8787c9f329f52c398d Mon Sep 17 00:00:00 2001
From: victorl
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}}
};
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
firstmoonlight wrote: > Does you PR also fix: #196001 Yes, I've verified that this PR also fixes #196001. The root cause is the same: the early return in type specifier checking prevents proper recovery. https://github.com/llvm/llvm-project/pull/190597 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
https://github.com/firstmoonlight updated
https://github.com/llvm/llvm-project/pull/190597
>From 6014a94423f619ea101608f48aa0d20f7e761ab5 Mon Sep 17 00:00:00 2001
From: victorl
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 cb19b80b7e994..09f7647969558 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -579,6 +579,7 @@ Bug Fixes to C++ Support
- Fixed a crash in Itanium C++ name mangling for a lambda in a local class
field initializer inside a constructor/destructor. (#GH176395)
- Fixed crashes in Itanium C++ name mangling for lambdas with trailing
requires-clauses involving requires-expressions. (#GH100774) (#GH123854)
- Fixed an invalid rejection and assertion failure while generating
``operator=`` for fields with the ``__restrict`` qualifier. (#GH37979)
+- 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 61706bc8f4229..be4a8bba6be83 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -888,6 +888,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
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
shafik wrote: Does you PR also fix: https://github.com/llvm/llvm-project/issues/196001 https://github.com/llvm/llvm-project/pull/190597 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
https://github.com/cor3ntin approved this pull request. Thanks https://github.com/llvm/llvm-project/pull/190597 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
https://github.com/firstmoonlight updated
https://github.com/llvm/llvm-project/pull/190597
>From a64173fcc8f4bd095bb14530cee6a9f6b9deea4c Mon Sep 17 00:00:00 2001
From: victorl
Date: Wed, 8 Apr 2026 21:41:05 +0800
Subject: [PATCH 1/4] [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()),
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
cor3ntin wrote: This change needs a release note. Please add an entry to `clang/docs/ReleaseNotes.rst` in the section the most adapted to the change, and referencing any Github issue this change fixes. Thanks! https://github.com/llvm/llvm-project/pull/190597 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Sema]fix crash of invalid friend declaration with storage-class specifier (PR #190597)
https://github.com/firstmoonlight edited https://github.com/llvm/llvm-project/pull/190597 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
