[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
This commit is contained in:
Congcong Cai 2023-04-25 00:30:58 +02:00
parent b6da4bf1f8
commit 921b45a855
3 changed files with 45 additions and 6 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);