[clang] 921b45a - [Sema]Select correct lexical context during template instantiate

Congcong Cai via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 26 15:30:39 PDT 2023


Author: Congcong Cai
Date: 2023-04-27T00:29:13+02:00
New Revision: 921b45a855f09afe99ea9c0c173794ee4ccd5872

URL: https://github.com/llvm/llvm-project/commit/921b45a855f09afe99ea9c0c173794ee4ccd5872
DIFF: https://github.com/llvm/llvm-project/commit/921b45a855f09afe99ea9c0c173794ee4ccd5872.diff

LOG: [Sema]Select correct lexical context during template instantiate

This patch wants to fix inline friend decl like
```
template <class F1> int foo(F1 X);
template <int A1> struct A {
  template <class F1> friend int foo(F1 X) { return A1; }
};

template struct A<1>;
int a = foo(1.0);
```

Differential Revision: https://reviews.llvm.org/D149009

Added: 
    clang/test/SemaTemplate/template-friend-definition-in-template.cpp

Modified: 
    clang/lib/Sema/SemaTemplateDeduction.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 2f13505d8ed71..d60c75c319894 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3591,11 +3591,28 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
   DeclContext *Owner = FunctionTemplate->getDeclContext();
   if (FunctionTemplate->getFriendObjectKind())
     Owner = FunctionTemplate->getLexicalDeclContext();
+  FunctionDecl *FD = FunctionTemplate->getTemplatedDecl();
+  // additional check for inline friend, 
+  // ```
+  //   template <class F1> int foo(F1 X);
+  //   template <int A1> struct A {
+  //     template <class F1> friend int foo(F1 X) { return A1; }
+  //   };
+  //   template struct A<1>;
+  //   int a = foo(1.0);
+  // ```
+  const FunctionDecl *FDFriend;
+  if (FD->getFriendObjectKind() == Decl::FriendObjectKind::FOK_None &&
+      FD->isDefined(FDFriend, /*CheckForPendingFriendDefinition*/ true) &&
+      FDFriend->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None) {
+    FD = const_cast<FunctionDecl *>(FDFriend);
+    Owner = FD->getLexicalDeclContext();
+  }
   MultiLevelTemplateArgumentList SubstArgs(
       FunctionTemplate, CanonicalDeducedArgumentList->asArray(),
       /*Final=*/false);
   Specialization = cast_or_null<FunctionDecl>(
-      SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs));
+      SubstDecl(FD, Owner, SubstArgs));
   if (!Specialization || Specialization->isInvalidDecl())
     return TDK_SubstitutionFailure;
 

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e749c24e7f702..444162ef5df62 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4662,11 +4662,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
   ActiveInstType &ActiveInst = SemaRef.CodeSynthesisContexts.back();
   if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution ||
       ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) {
-    if (FunctionTemplateDecl *FunTmpl
-          = dyn_cast<FunctionTemplateDecl>(ActiveInst.Entity)) {
-      assert(FunTmpl->getTemplatedDecl() == Tmpl &&
-             "Deduction from the wrong function template?");
-      (void) FunTmpl;
+    if (isa<FunctionTemplateDecl>(ActiveInst.Entity)) {
       SemaRef.InstantiatingSpecializations.erase(
           {ActiveInst.Entity->getCanonicalDecl(), ActiveInst.Kind});
       atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst);

diff  --git a/clang/test/SemaTemplate/template-friend-definition-in-template.cpp b/clang/test/SemaTemplate/template-friend-definition-in-template.cpp
new file mode 100644
index 0000000000000..cfcf00b58b026
--- /dev/null
+++ b/clang/test/SemaTemplate/template-friend-definition-in-template.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+template <class F1> int foo1(F1 X1);
+
+template <int A1> struct A {
+  template <class F2> friend int foo1(F2 X2) {
+    return A1;
+  }
+};
+
+template struct A<1>;
+int main() { 
+  foo1(1.0);
+}
+
+template <class F1> int foo2(F1 X1);
+
+template <int A1> struct B {
+  template <class F2> friend int foo2(F2 X2) {
+    return A1;
+  }
+};
+
+template struct B<1>;
+template int foo2<float>(float X1);


        


More information about the cfe-commits mailing list