Skip to content

Commit

Permalink
[NFC] Start saving InstantiatedFromDecl in non-template functions
Browse files Browse the repository at this point in the history
In cases where a non-template function is defined inside a function
template, we don't have information about the original uninstantiated
version.  In the case of concepts instantiation, we will need the
ability to get back to the original template.  This patch splits a piece
of the deferred concepts instantaition patch off to accomplish the
storage of this, with minor runtime overhead, and zero additional
storage.
  • Loading branch information
Erich Keane committed Jul 22, 2022
1 parent 7068aa9 commit 3ff86f9
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 11 deletions.
27 changes: 19 additions & 8 deletions clang/include/clang/AST/Decl.h
Expand Up @@ -1890,7 +1890,10 @@ class FunctionDecl : public DeclaratorDecl,
TK_FunctionTemplateSpecialization,
// A function template specialization that hasn't yet been resolved to a
// particular specialized function template.
TK_DependentFunctionTemplateSpecialization
TK_DependentFunctionTemplateSpecialization,
// A non-template function which is in a dependent scope.
TK_DependentNonTemplate

};

/// Stashed information about a defaulted function definition whose body has
Expand Down Expand Up @@ -1939,20 +1942,21 @@ class FunctionDecl : public DeclaratorDecl,
/// The template or declaration that this declaration
/// describes or was instantiated from, respectively.
///
/// For non-templates, this value will be NULL. For function
/// declarations that describe a function template, this will be a
/// pointer to a FunctionTemplateDecl. For member functions
/// of class template specializations, this will be a MemberSpecializationInfo
/// For non-templates this value will be NULL, unless this declaration was
/// declared directly inside of a function template, in which case it will
/// have a pointer to a FunctionDecl, stored in the NamedDecl. For function
/// declarations that describe a function template, this will be a pointer to
/// a FunctionTemplateDecl, stored in the NamedDecl. For member functions of
/// class template specializations, this will be a MemberSpecializationInfo
/// pointer containing information about the specialization.
/// For function template specializations, this will be a
/// FunctionTemplateSpecializationInfo, which contains information about
/// the template being specialized and the template arguments involved in
/// that specialization.
llvm::PointerUnion<FunctionTemplateDecl *,
MemberSpecializationInfo *,
llvm::PointerUnion<NamedDecl *, MemberSpecializationInfo *,
FunctionTemplateSpecializationInfo *,
DependentFunctionTemplateSpecializationInfo *>
TemplateOrSpecialization;
TemplateOrSpecialization;

/// Provides source/type location info for the declaration name embedded in
/// the DeclaratorDecl base class.
Expand Down Expand Up @@ -2695,6 +2699,13 @@ class FunctionDecl : public DeclaratorDecl,
setInstantiationOfMemberFunction(getASTContext(), FD, TSK);
}

/// Specify that this function declaration was instantiated from a
/// FunctionDecl FD. This is only used if this is a function declaration
/// declared locally inside of a function template.
void setInstantiatedFromDecl(FunctionDecl *FD);

FunctionDecl *getInstantiatedFromDecl() const;

/// Retrieves the function template that is described by this
/// function declaration.
///
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/ASTImporter.cpp
Expand Up @@ -3109,6 +3109,11 @@ Error ASTNodeImporter::ImportTemplateInformation(
case FunctionDecl::TK_FunctionTemplate:
return Error::success();

case FunctionDecl::TK_DependentNonTemplate:
if (Expected<FunctionDecl *> InstFDOrErr =
import(FromFD->getInstantiatedFromDecl()))
ToFD->setInstantiatedFromDecl(*InstFDOrErr);
return Error::success();
case FunctionDecl::TK_MemberSpecialization: {
TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind();

Expand Down
24 changes: 21 additions & 3 deletions clang/lib/AST/Decl.cpp
Expand Up @@ -3732,8 +3732,13 @@ const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const {
FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const {
if (TemplateOrSpecialization.isNull())
return TK_NonTemplate;
if (TemplateOrSpecialization.is<FunctionTemplateDecl *>())
if (const auto *ND = TemplateOrSpecialization.dyn_cast<NamedDecl *>()) {
if (isa<FunctionDecl>(ND))
return TK_DependentNonTemplate;
assert(isa<FunctionTemplateDecl>(ND) &&
"No other valid types in NamedDecl");
return TK_FunctionTemplate;
}
if (TemplateOrSpecialization.is<MemberSpecializationInfo *>())
return TK_MemberSpecialization;
if (TemplateOrSpecialization.is<FunctionTemplateSpecializationInfo *>())
Expand Down Expand Up @@ -3774,15 +3779,28 @@ FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C,
}

FunctionTemplateDecl *FunctionDecl::getDescribedFunctionTemplate() const {
return TemplateOrSpecialization.dyn_cast<FunctionTemplateDecl *>();
return dyn_cast_or_null<FunctionTemplateDecl>(
TemplateOrSpecialization.dyn_cast<NamedDecl *>());
}

void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
void FunctionDecl::setDescribedFunctionTemplate(
FunctionTemplateDecl *Template) {
assert(TemplateOrSpecialization.isNull() &&
"Member function is already a specialization");
TemplateOrSpecialization = Template;
}

void FunctionDecl::setInstantiatedFromDecl(FunctionDecl *FD) {
assert(TemplateOrSpecialization.isNull() &&
"Function is already a specialization");
TemplateOrSpecialization = FD;
}

FunctionDecl *FunctionDecl::getInstantiatedFromDecl() const {
return dyn_cast_or_null<FunctionDecl>(
TemplateOrSpecialization.dyn_cast<NamedDecl *>());
}

bool FunctionDecl::isImplicitlyInstantiable() const {
// If the function is invalid, it can't be implicitly instantiated.
if (isInvalidDecl())
Expand Down
1 change: 1 addition & 0 deletions clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
Expand Up @@ -303,6 +303,7 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
// Skip templated functions.
switch (Decl->getTemplatedKind()) {
case FunctionDecl::TK_NonTemplate:
case FunctionDecl::TK_DependentNonTemplate:
break;
case FunctionDecl::TK_MemberSpecialization:
case FunctionDecl::TK_FunctionTemplateSpecialization:
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Expand Up @@ -2182,6 +2182,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
// definition. We don't want non-template functions to be marked as being
// template instantiations.
Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
} else if (!isFriend) {
// If this is not a function template, and this is not a friend (that is,
// this is a locally declared function), save the instantiation relationship
// for the purposes of constraint instantiation.
Function->setInstantiatedFromDecl(D);
}

if (isFriend) {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Expand Up @@ -953,6 +953,10 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
case FunctionDecl::TK_NonTemplate:
mergeRedeclarable(FD, Redecl);
break;
case FunctionDecl::TK_DependentNonTemplate:
mergeRedeclarable(FD, Redecl);
FD->setInstantiatedFromDecl(readDeclAs<FunctionDecl>());
break;
case FunctionDecl::TK_FunctionTemplate:
// Merged when we merge the template.
FD->setDescribedFunctionTemplate(readDeclAs<FunctionTemplateDecl>());
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Expand Up @@ -585,6 +585,9 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
switch (D->getTemplatedKind()) {
case FunctionDecl::TK_NonTemplate:
break;
case FunctionDecl::TK_DependentNonTemplate:
Record.AddDeclRef(D->getInstantiatedFromDecl());
break;
case FunctionDecl::TK_FunctionTemplate:
Record.AddDeclRef(D->getDescribedFunctionTemplate());
break;
Expand Down

0 comments on commit 3ff86f9

Please sign in to comment.