https://github.com/Serosh-commits updated 
https://github.com/llvm/llvm-project/pull/186398

>From b88d19cdd09a75427d6599415860f0778d0972ef Mon Sep 17 00:00:00 2001
From: Serosh-commits <[email protected]>
Date: Fri, 13 Mar 2026 19:21:29 +0530
Subject: [PATCH 1/5] [Clang] Fix crash in friend definition

Fix assertion failure in instantiation.
---
 clang/docs/ReleaseNotes.rst                    |  1 +
 clang/lib/Sema/SemaDeclCXX.cpp                 |  3 +++
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp |  5 ++++-
 clang/test/SemaCXX/gh185341.cpp                | 17 +++++++++++++++++
 4 files changed, 25 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/SemaCXX/gh185341.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 613d87668be18..330c46b2eaaf3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -243,6 +243,7 @@ Bug Fixes to Attribute Support
 
 Bug Fixes to C++ Support
 ^^^^^^^^^^^^^^^^^^^^^^^^
+- Fixed a crash when a function template is defined as a non-template friend 
with a global scope qualifier. (#GH185341)
 - Fixed a crash when instantiating ``requires`` expressions involving 
substitution failures in C++ concepts. (#GH176402)
 - Fixed a crash when a default argument is passed to an explicit object 
parameter. (#GH176639)
 - Fixed a crash when diagnosing an invalid static member function with an 
explicit object parameter (#GH177741)
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 5837ecd6b9163..d966a3c1a25fd 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18452,10 +18452,12 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, 
Declarator &D,
         DB << SS.getScopeRep();
         if (DC->isFileContext())
           DB << FixItHint::CreateRemoval(SS.getRange());
+        ND->setInvalidDecl();
 
         // Friend function defined in a local class.
       } else if (FunctionContainingLocalClass) {
         Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
+        ND->setInvalidDecl();
 
         // Per [basic.pre]p4, a template-id is not a name. Therefore, if we 
have
         // a template-id, the function name is not unqualified because these is
@@ -18465,6 +18467,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, 
Declarator &D,
         // and diagnose them as such.
       } else if (isTemplateId) {
         Diag(NameInfo.getBeginLoc(), diag::err_friend_specialization_def);
+        ND->setInvalidDecl();
       }
     }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e74c41517ecbf..9e1416bac212c 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5563,6 +5563,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation 
PointOfInstantiation,
     // corresponding declaration of the function.
     assert(ExistingDefn->isThisDeclarationInstantiatedFromAFriendDefinition());
     Function = const_cast<FunctionDecl*>(ExistingDefn);
+    if (Function->isInvalidDecl())
+      return;
   }
 
 #ifndef NDEBUG
@@ -5888,7 +5890,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation 
PointOfInstantiation,
         Primary &&
         !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) &&
         Function->getTemplateSpecializationKind() !=
-            TSK_ExplicitSpecialization) {
+            TSK_ExplicitSpecialization &&
+        !Function->isThisDeclarationInstantiatedFromAFriendDefinition()) {
       auto It = llvm::find_if(Primary->redecls(),
                               [](const RedeclarableTemplateDecl *RTD) {
                                 return cast<FunctionTemplateDecl>(RTD)
diff --git a/clang/test/SemaCXX/gh185341.cpp b/clang/test/SemaCXX/gh185341.cpp
new file mode 100644
index 0000000000000..fb3ae259ccd6e
--- /dev/null
+++ b/clang/test/SemaCXX/gh185341.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
+
+
+template<class>
+struct D;
+
+template<class T>
+void foo(D<T>);
+
+template<class T>
+struct D {
+  friend void ::foo(D) {} // expected-error {{friend function definition 
cannot be qualified with '::'}}
+};
+
+int main() {
+  foo(D<int>{});
+}
\ No newline at end of file

>From 7da88732745d507b874cbd53916b4ebf2119398a Mon Sep 17 00:00:00 2001
From: Serosh-commits <[email protected]>
Date: Sat, 14 Mar 2026 00:16:57 +0530
Subject: [PATCH 2/5] [Clang] Fix crash in friend definition with recovery

This fix addresses GH185341 by correctly handling qualified friend function 
definitions through stripping the qualifier for error recovery and ensuring 
template instantiation logic correctly identifies functions instantiated from 
friends.
---
 clang/lib/Sema/SemaDeclCXX.cpp | 22 +++++++---------------
 1 file changed, 7 insertions(+), 15 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index d966a3c1a25fd..78f804f229e25 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18247,6 +18247,12 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, 
Declarator &D,
 
   bool isTemplateId = D.getName().getKind() == 
UnqualifiedIdKind::IK_TemplateId;
 
+  if (D.isFunctionDefinition() && SS.isNotEmpty()) {
+    Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def)
+        << SS.getScopeRep() << FixItHint::CreateRemoval(SS.getRange());
+    SS.clear();
+  }
+
   // There are five cases here.
   //   - There's no scope specifier and we're in a local class. Only look
   //     for functions declared in the immediately-enclosing block scope.
@@ -18441,21 +18447,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, 
Declarator &D,
     //   only if the class is a non-local class, and the function name is
     //   unqualified.
     if (D.isFunctionDefinition()) {
-      // Qualified friend function definition.
-      if (SS.isNotEmpty()) {
-        // FIXME: We should only do this if the scope specifier names the
-        // innermost enclosing namespace; otherwise the fixit changes the
-        // meaning of the code.
-        SemaDiagnosticBuilder DB =
-            Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def);
-
-        DB << SS.getScopeRep();
-        if (DC->isFileContext())
-          DB << FixItHint::CreateRemoval(SS.getRange());
-        ND->setInvalidDecl();
-
-        // Friend function defined in a local class.
-      } else if (FunctionContainingLocalClass) {
+      if (FunctionContainingLocalClass) {
         Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
         ND->setInvalidDecl();
 

>From 239d334655af53a78b14bcf4e6012e6845e77ba3 Mon Sep 17 00:00:00 2001
From: Serosh-commits <[email protected]>
Date: Sat, 14 Mar 2026 18:20:18 +0530
Subject: [PATCH 3/5] address feedback

---
 clang/lib/Sema/SemaDeclCXX.cpp                 | 11 ++++++++---
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp |  3 +--
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 78f804f229e25..f679f390cc752 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18245,14 +18245,16 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, 
Declarator &D,
   LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
                         RedeclarationKind::ForExternalRedeclaration);
 
-  bool isTemplateId = D.getName().getKind() == 
UnqualifiedIdKind::IK_TemplateId;
-
-  if (D.isFunctionDefinition() && SS.isNotEmpty()) {
+  bool WasQualifiedFriendDef = D.isFunctionDefinition() && SS.isNotEmpty();
+  if (WasQualifiedFriendDef) {
     Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def)
         << SS.getScopeRep() << FixItHint::CreateRemoval(SS.getRange());
     SS.clear();
+    Previous.clear();
   }
 
+  bool isTemplateId = D.getName().getKind() == 
UnqualifiedIdKind::IK_TemplateId;
+
   // There are five cases here.
   //   - There's no scope specifier and we're in a local class. Only look
   //     for functions declared in the immediately-enclosing block scope.
@@ -18406,6 +18408,9 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, 
Declarator &D,
                                           TemplateParams, AddToScope);
   if (!ND) return nullptr;
 
+  if (WasQualifiedFriendDef)
+    ND->setInvalidDecl();
+
   assert(ND->getLexicalDeclContext() == CurContext);
 
   // If we performed typo correction, we might have added a scope specifier
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 9e1416bac212c..cc37a98cd27ff 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5890,8 +5890,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation 
PointOfInstantiation,
         Primary &&
         !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) &&
         Function->getTemplateSpecializationKind() !=
-            TSK_ExplicitSpecialization &&
-        !Function->isThisDeclarationInstantiatedFromAFriendDefinition()) {
+            TSK_ExplicitSpecialization) {
       auto It = llvm::find_if(Primary->redecls(),
                               [](const RedeclarableTemplateDecl *RTD) {
                                 return cast<FunctionTemplateDecl>(RTD)

>From 6d325c1ad99177f8b05dfe4f6d9a945fec2c332b Mon Sep 17 00:00:00 2001
From: Serosh-commits <[email protected]>
Date: Sat, 14 Mar 2026 19:08:35 +0530
Subject: [PATCH 4/5] address feedback

---
 clang/lib/Sema/SemaDeclCXX.cpp                 | 2 --
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 --
 2 files changed, 4 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index f679f390cc752..6e462f272863c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18454,7 +18454,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, 
Declarator &D,
     if (D.isFunctionDefinition()) {
       if (FunctionContainingLocalClass) {
         Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
-        ND->setInvalidDecl();
 
         // Per [basic.pre]p4, a template-id is not a name. Therefore, if we 
have
         // a template-id, the function name is not unqualified because these is
@@ -18464,7 +18463,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, 
Declarator &D,
         // and diagnose them as such.
       } else if (isTemplateId) {
         Diag(NameInfo.getBeginLoc(), diag::err_friend_specialization_def);
-        ND->setInvalidDecl();
       }
     }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index cc37a98cd27ff..e74c41517ecbf 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5563,8 +5563,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation 
PointOfInstantiation,
     // corresponding declaration of the function.
     assert(ExistingDefn->isThisDeclarationInstantiatedFromAFriendDefinition());
     Function = const_cast<FunctionDecl*>(ExistingDefn);
-    if (Function->isInvalidDecl())
-      return;
   }
 
 #ifndef NDEBUG

>From 37edd087fe61b044231d47af5fd7d9bd09a9eab6 Mon Sep 17 00:00:00 2001
From: Serosh-commits <[email protected]>
Date: Mon, 16 Mar 2026 02:09:44 +0530
Subject: [PATCH 5/5] nit

---
 clang/lib/Sema/SemaDeclCXX.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 6e462f272863c..693898ca4c31f 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18408,9 +18408,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, 
Declarator &D,
                                           TemplateParams, AddToScope);
   if (!ND) return nullptr;
 
-  if (WasQualifiedFriendDef)
-    ND->setInvalidDecl();
-
   assert(ND->getLexicalDeclContext() == CurContext);
 
   // If we performed typo correction, we might have added a scope specifier

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to