https://github.com/Sirraide created 
https://github.com/llvm/llvm-project/pull/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.

>From daa795d3807ecdceedb764582a01396c3b7f2e2f Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalm...@gmail.com>
Date: Mon, 14 Apr 2025 22:54:11 +0200
Subject: [PATCH] [Clang] [Sema] Fix a crash when a `friend` function is
 redefined as deleted

---
 clang/docs/ReleaseNotes.rst                   |  2 +-
 clang/lib/Sema/SemaDecl.cpp                   | 15 ++++------
 .../SemaCXX/cxx2c-delete-with-message.cpp     | 30 +++++++++++++++++++
 3 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 11f62bc881b03..037f9f6fe79e0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -389,7 +389,7 @@ Bug Fixes in This Version
 
     #if 1 ? 1 : 999999999999999999999
     #endif
-
+- Fixed a crash when a ``friend`` function is redefined as deleted. (#GH135506)
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e9805c345b6af..8fd857d347895 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16178,16 +16178,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt 
*Body,
     // This is meant to pop the context added in ActOnStartOfFunctionDef().
     ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD));
     if (FD) {
-      // If this is called by Parser::ParseFunctionDefinition() after marking
-      // the declaration as deleted, and if the deleted-function-body contains
-      // a message (C++26), then a DefaultedOrDeletedInfo will have already 
been
-      // added to store that message; do not overwrite it in that case.
-      //
-      // Since this would always set the body to 'nullptr' in that case anyway,
-      // which is already done when the function decl is initially created,
-      // always skipping this irrespective of whether there is a delete message
-      // should not be a problem.
-      if (!FD->isDeletedAsWritten())
+      // The function body and the DefaultedOrDeletedInfo, if present, use
+      // the same storage; don't overwrite the latter if the former is null
+      // (the body is initialised to null anyway, so even if the latter isn't
+      // present, this would still be a no-op).
+      if (Body)
         FD->setBody(Body);
       FD->setWillHaveBody(false);
 
diff --git a/clang/test/SemaCXX/cxx2c-delete-with-message.cpp 
b/clang/test/SemaCXX/cxx2c-delete-with-message.cpp
index 22e65d902ecd4..5609da18c05aa 100644
--- a/clang/test/SemaCXX/cxx2c-delete-with-message.cpp
+++ b/clang/test/SemaCXX/cxx2c-delete-with-message.cpp
@@ -271,3 +271,33 @@ void operators() {
   if (to_int_int) {} // expected-error {{attempt to use a deleted function: 
deleted (TO<int, int>, operator bool)}}
   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)}}
 };
+
+namespace gh135506 {
+struct a {
+  // FIXME: We currently don't diagnose these invalid redeclarations if the
+  // second declaration is defaulted or deleted. This probably needs to be
+  // handled in ParseCXXInlineMethodDef() after parsing the defaulted/deleted
+  // body.
+  friend consteval int f() { return 3; }
+  friend consteval int f() = delete("foo");
+
+  friend consteval int g() { return 3; }
+  friend consteval int g() = delete;
+
+  friend int h() { return 3; }
+  friend int h() = delete;
+
+  friend consteval int i() = delete; // expected-note {{previous definition is 
here}}
+  friend consteval int i() { return 3; } // expected-error {{redefinition of 
'i'}}
+};
+
+struct b {
+  friend consteval bool operator==(b, b) { return true; } // expected-note 
{{previous declaration is here}}
+  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}}
+};
+
+struct c {
+  friend consteval bool operator==(c, c) = default; // expected-note 
{{previous definition is here}}
+  friend consteval bool operator==(c, c) { return true; } // expected-error 
{{redefinition of 'operator=='}}
+};
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to