Skip to content

Commit 616613c

Browse files
authored
[Clang] [Sema] Fix a crash when a friend function is redefined as deleted (#135679)
NB: This only fixes the crash introduced in Clang 19; we still accept this code even though we shouldn’t: ```c++ struct S { friend int f() { return 3; } friend int f() = delete; }; ``` I tried figuring out a way to diagnose this redeclaration, but it seems tricky because I kept running into issues around defaulted comparison operators. From my testing, however, this fix here would still be required even once we do start diagnosing this. Fixes #135506.
1 parent 27c1aa9 commit 616613c

File tree

3 files changed

+37
-10
lines changed

3 files changed

+37
-10
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ Bug Fixes in This Version
425425
- Fixed a clang 20 regression where diagnostics attached to some calls to member functions
426426
using C++23 "deducing this" did not have a diagnostic location (#GH135522)
427427

428+
- Fixed a crash when a ``friend`` function is redefined as deleted. (#GH135506)
429+
428430
Bug Fixes to Compiler Builtins
429431
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
430432

clang/lib/Sema/SemaDecl.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16199,16 +16199,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
1619916199
// This is meant to pop the context added in ActOnStartOfFunctionDef().
1620016200
ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD));
1620116201
if (FD) {
16202-
// If this is called by Parser::ParseFunctionDefinition() after marking
16203-
// the declaration as deleted, and if the deleted-function-body contains
16204-
// a message (C++26), then a DefaultedOrDeletedInfo will have already been
16205-
// added to store that message; do not overwrite it in that case.
16206-
//
16207-
// Since this would always set the body to 'nullptr' in that case anyway,
16208-
// which is already done when the function decl is initially created,
16209-
// always skipping this irrespective of whether there is a delete message
16210-
// should not be a problem.
16211-
if (!FD->isDeletedAsWritten())
16202+
// The function body and the DefaultedOrDeletedInfo, if present, use
16203+
// the same storage; don't overwrite the latter if the former is null
16204+
// (the body is initialised to null anyway, so even if the latter isn't
16205+
// present, this would still be a no-op).
16206+
if (Body)
1621216207
FD->setBody(Body);
1621316208
FD->setWillHaveBody(false);
1621416209

clang/test/SemaCXX/cxx2c-delete-with-message.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,33 @@ void operators() {
271271
if (to_int_int) {} // expected-error {{attempt to use a deleted function: deleted (TO<int, int>, operator bool)}}
272272
static_cast<bool>(to_int_int); // expected-error {{static_cast from 'TO<int, int>' to 'bool' uses deleted function: deleted (TO<int, int>, operator bool)}}
273273
};
274+
275+
namespace gh135506 {
276+
struct a {
277+
// FIXME: We currently don't diagnose these invalid redeclarations if the
278+
// second declaration is defaulted or deleted. This probably needs to be
279+
// handled in ParseCXXInlineMethodDef() after parsing the defaulted/deleted
280+
// body.
281+
friend consteval int f() { return 3; }
282+
friend consteval int f() = delete("foo");
283+
284+
friend consteval int g() { return 3; }
285+
friend consteval int g() = delete;
286+
287+
friend int h() { return 3; }
288+
friend int h() = delete;
289+
290+
friend consteval int i() = delete; // expected-note {{previous definition is here}}
291+
friend consteval int i() { return 3; } // expected-error {{redefinition of 'i'}}
292+
};
293+
294+
struct b {
295+
friend consteval bool operator==(b, b) { return true; } // expected-note {{previous declaration is here}}
296+
friend consteval bool operator==(b, b) = default; // expected-error {{defaulting this equality comparison operator is not allowed because it was already declared outside the class}}
297+
};
298+
299+
struct c {
300+
friend consteval bool operator==(c, c) = default; // expected-note {{previous definition is here}}
301+
friend consteval bool operator==(c, c) { return true; } // expected-error {{redefinition of 'operator=='}}
302+
};
303+
}

0 commit comments

Comments
 (0)