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
