Skip to content

Commit 55611de

Browse files
firstmoonlightvictorl
andauthored
[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: #186569 Co-authored-by: victorl <liuvicsen@gmail.com>
1 parent c65e6da commit 55611de

4 files changed

Lines changed: 23 additions & 8 deletions

File tree

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,7 @@ Bug Fixes to C++ Support
733733
- Fixed a use-after-free bug when parsing default arguments containing lambdas in declarations with template-id declarators. (#GH196725)
734734
- Fixed a crash in constant evaluation using placement new on an array which was later initialized. (#GH196450)
735735
- Fixed an issue where Clang incorrectly accepted invalid unqualified uses of local nested class names outside their declaring scope. (#GH184622)
736+
- Fixed a crash when parsing invalid friend declaration with storage-class specifier. (#GH186569)
736737

737738
Bug Fixes to AST Handling
738739
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Sema/DeclSpec.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,10 @@ class DeclSpec {
889889
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
890890
void Finish(Sema &S, const PrintingPolicy &Policy);
891891

892+
void CheckTypeSpec(Sema &S, const PrintingPolicy &Policy);
893+
894+
void CheckFriendSpec(Sema &S, const PrintingPolicy &Policy);
895+
892896
const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const {
893897
return writtenBS;
894898
}

clang/lib/Sema/DeclSpec.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,20 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
11621162

11631163
// Check the type specifier components first. No checking for an invalid
11641164
// type.
1165+
CheckTypeSpec(S, Policy);
1166+
1167+
CheckFriendSpec(S, Policy);
1168+
1169+
assert(!TypeSpecOwned || isDeclRep((TST)TypeSpecType));
1170+
1171+
// Okay, now we can infer the real type.
1172+
1173+
// TODO: return "auto function" and other bad things based on the real type.
1174+
1175+
// 'data definition has no type or storage class'?
1176+
}
1177+
1178+
void DeclSpec::CheckTypeSpec(Sema &S, const PrintingPolicy &Policy) {
11651179
if (TypeSpecType == TST_error)
11661180
return;
11671181

@@ -1441,6 +1455,9 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
14411455
S.Diag(ConstexprLoc, diag::warn_cxx20_compat_consteval);
14421456
else if (getConstexprSpecifier() == ConstexprSpecKind::Constinit)
14431457
S.Diag(ConstexprLoc, diag::warn_cxx20_compat_constinit);
1458+
}
1459+
1460+
void DeclSpec::CheckFriendSpec(Sema &S, const PrintingPolicy &Policy) {
14441461
// C++ [class.friend]p6:
14451462
// No storage-class-specifier shall appear in the decl-specifier-seq
14461463
// of a friend declaration.
@@ -1498,14 +1515,6 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
14981515
FS_explicit_specifier = ExplicitSpecifier();
14991516
FS_virtualLoc = FS_explicitLoc = SourceLocation();
15001517
}
1501-
1502-
assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType));
1503-
1504-
// Okay, now we can infer the real type.
1505-
1506-
// TODO: return "auto function" and other bad things based on the real type.
1507-
1508-
// 'data definition has no type or storage class'?
15091518
}
15101519

15111520
bool DeclSpec::isMissingDeclaratorOk() {

clang/test/CXX/class/class.friend/p6.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ class A {
1919
#else
2020
friend thread_local class G; // expected-error {{'thread_local' is invalid in friend declarations}}
2121
#endif
22+
friend register enum; // expected-error {{expected identifier or '{'}} expected-error {{'register' is invalid in friend declarations}}
2223
};

0 commit comments

Comments
 (0)