-
Notifications
You must be signed in to change notification settings - Fork 14.6k
Reland: [clang] Track function template instantiation from definition #125266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
#include "TreeTransform.h" | ||
#include "clang/AST/ASTConsumer.h" | ||
#include "clang/AST/ASTContext.h" | ||
#include "clang/AST/ASTLambda.h" | ||
#include "clang/AST/ASTMutationListener.h" | ||
#include "clang/AST/DeclTemplate.h" | ||
#include "clang/AST/DependentDiagnostic.h" | ||
|
@@ -5276,9 +5277,31 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, | |
RebuildTypeSourceInfoForDefaultSpecialMembers(); | ||
SetDeclDefaulted(Function, PatternDecl->getLocation()); | ||
} else { | ||
NamedDecl *ND = Function; | ||
DeclContext *DC = ND->getLexicalDeclContext(); | ||
std::optional<ArrayRef<TemplateArgument>> Innermost; | ||
if (auto *Primary = Function->getPrimaryTemplate(); | ||
Primary && | ||
!isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) && | ||
Function->getTemplateSpecializationKind() != | ||
TSK_ExplicitSpecialization) { | ||
auto It = llvm::find_if(Primary->redecls(), | ||
[](const RedeclarableTemplateDecl *RTD) { | ||
return cast<FunctionTemplateDecl>(RTD) | ||
->isCompatibleWithDefinition(); | ||
}); | ||
assert(It != Primary->redecls().end() && | ||
"Should't get here without a definition"); | ||
if (FunctionDecl *Def = cast<FunctionTemplateDecl>(*It) | ||
->getTemplatedDecl() | ||
->getDefinition()) | ||
DC = Def->getLexicalDeclContext(); | ||
else | ||
DC = (*It)->getLexicalDeclContext(); | ||
Comment on lines
+5295
to
+5300
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we get into a situation like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need the lexical context because we are interested in the template context of the declaration, ie what set of parameters it sits under, which is a lexical thing. I don't follow what you mean this situation with friends, can you provide an example? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, nevermind. I understand what you are doing now. However, I'm wondering if we are not reinventing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, there is commonality in that both are using the same helpers, but |
||
Innermost.emplace(Function->getTemplateSpecializationArgs()->asArray()); | ||
} | ||
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs( | ||
Function, Function->getLexicalDeclContext(), /*Final=*/false, | ||
/*Innermost=*/std::nullopt, false, PatternDecl); | ||
Function, DC, /*Final=*/false, Innermost, false, PatternDecl); | ||
|
||
// Substitute into the qualifier; we can get a substitution failure here | ||
// through evil use of alias templates. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++26 %s | ||
|
||
namespace t1 { | ||
template<int N> struct A { | ||
template<class C> friend auto cica(const A<N-1>&, C) { | ||
return N; | ||
} | ||
}; | ||
|
||
template<> struct A<0> { | ||
template<class C> friend auto cica(const A<0>&, C); | ||
// expected-note@-1 {{declared here}} | ||
}; | ||
|
||
void test() { | ||
cica(A<0>{}, 0); | ||
// expected-error@-1 {{function 'cica<int>' with deduced return type cannot be used before it is defined}} | ||
|
||
(void)A<1>{}; | ||
cica(A<0>{}, 0); | ||
} | ||
} // namespace t1 | ||
namespace t2 { | ||
template<int N> struct A { | ||
template<class C> friend auto cica(const A<N-1>&, C) { | ||
return N; | ||
} | ||
}; | ||
|
||
template<> struct A<0> { | ||
template<class C> friend auto cica(const A<0>&, C); | ||
}; | ||
|
||
template <int N, class = decltype(cica(A<N>{}, nullptr))> | ||
void MakeCica(); | ||
// expected-note@-1 {{candidate function}} | ||
|
||
template <int N> void MakeCica(A<N+1> = {}); | ||
// expected-note@-1 {{candidate function}} | ||
|
||
void test() { | ||
MakeCica<0>(); | ||
|
||
MakeCica<0>(); | ||
// expected-error@-1 {{call to 'MakeCica' is ambiguous}} | ||
} | ||
} // namespace t2 | ||
namespace t3 { | ||
template<int N> struct A { | ||
template<class C> friend auto cica(const A<N-1>&, C) { | ||
return N-1; | ||
} | ||
}; | ||
|
||
template<> struct A<0> { | ||
template<class C> friend auto cica(const A<0>&, C); | ||
}; | ||
|
||
template <int N, class AT, class = decltype(cica(AT{}, nullptr))> | ||
static constexpr bool MakeCica(int); | ||
|
||
template <int N, class AT> | ||
static constexpr bool MakeCica(short, A<N+1> = {}); | ||
|
||
template <int N, class AT = A<N>, class Val = decltype(MakeCica<N, AT>(0))> | ||
static constexpr bool has_cica = Val{}; | ||
|
||
constexpr bool cica2 = has_cica<0> || has_cica<0>; | ||
} // namespace t3 | ||
namespace t4 { | ||
template<int N> struct A { | ||
template<class C> friend auto cica(const A<N-1>&, C); | ||
}; | ||
|
||
template<> struct A<0> { | ||
template<class C> friend auto cica(const A<0>&, C) { | ||
C a; | ||
} | ||
}; | ||
|
||
template struct A<1>; | ||
|
||
void test() { | ||
cica(A<0>{}, 0); | ||
} | ||
} // namespace t4 | ||
namespace regression1 { | ||
template <class> class A; | ||
|
||
template <class T> [[gnu::abi_tag("TAG")]] void foo(A<T>); | ||
|
||
template <class> struct A { | ||
friend void foo <>(A); | ||
}; | ||
|
||
template struct A<int>; | ||
|
||
template <class T> [[gnu::abi_tag("TAG")]] void foo(A<T>) {} | ||
|
||
template void foo<int>(A<int>); | ||
} // namespace regression1 | ||
namespace regression2 { | ||
template <class> struct A { | ||
template <class T> static void f() { | ||
A<int>::f<T>(); | ||
} | ||
}; | ||
template <> template <class T> void A<int>::f() { | ||
static_assert(__is_same(T, long)); | ||
} | ||
template void A<void>::f<long>(); | ||
} // namespace regression2 |
Uh oh!
There was an error while loading. Please reload this page.