[clang] [clang] fix crash in friend definition (PR #186398)

via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 13 06:56:02 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Serosh (Serosh-commits)

<details>
<summary>Changes</summary>

Mark invalid friend definitions with `setInvalidDecl()` and skip the redecl chain search in `InstantiateFunctionDefinition` for friend-instantiated functions, which don't follow standard template redecl rules
fixes #<!-- -->185341

---
Full diff: https://github.com/llvm/llvm-project/pull/186398.diff


4 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+1) 
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+3) 
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+4-1) 
- (added) clang/test/SemaCXX/gh185341.cpp (+17) 


``````````diff
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

``````````

</details>


https://github.com/llvm/llvm-project/pull/186398


More information about the cfe-commits mailing list