llvm-project/clang/lib/AST/TemplateName.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

501 lines
18 KiB
C++
Raw Normal View History

//===- TemplateName.cpp - C++ Template Name Representation ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the TemplateName interface and subclasses.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/TemplateName.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DependenceFlags.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TemplateBase.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <optional>
#include <string>
using namespace clang;
DeducedTemplateStorage::DeducedTemplateStorage(TemplateName Underlying,
const DefaultArguments &DefArgs)
: UncommonTemplateNameStorage(Deduced, /*Index=*/DefArgs.StartPos,
DefArgs.Args.size()),
Underlying(Underlying) {
llvm::copy(DefArgs.Args, reinterpret_cast<TemplateArgument *>(this + 1));
}
void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context) const {
Profile(ID, Context, Underlying, getDefaultArguments());
}
void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context,
TemplateName Underlying,
const DefaultArguments &DefArgs) {
Underlying.Profile(ID);
ID.AddInteger(DefArgs.StartPos);
ID.AddInteger(DefArgs.Args.size());
for (const TemplateArgument &Arg : DefArgs.Args)
Arg.Profile(ID, Context);
}
TemplateArgument
SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
return TemplateArgument(llvm::ArrayRef(Arguments, Bits.Data));
}
TemplateTemplateParmDecl *
SubstTemplateTemplateParmPackStorage::getParameterPack() const {
return cast<TemplateTemplateParmDecl>(
getReplacedTemplateParameterList(getAssociatedDecl())
->asArray()[Bits.Index]);
}
TemplateTemplateParmDecl *
SubstTemplateTemplateParmStorage::getParameter() const {
return cast<TemplateTemplateParmDecl>(
getReplacedTemplateParameterList(getAssociatedDecl())
->asArray()[Bits.Index]);
}
void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, Replacement, getAssociatedDecl(), getIndex(), getPackIndex(),
getFinal());
}
void SubstTemplateTemplateParmStorage::Profile(
llvm::FoldingSetNodeID &ID, TemplateName Replacement, Decl *AssociatedDecl,
unsigned Index, UnsignedOrNone PackIndex, bool Final) {
Replacement.Profile(ID);
ID.AddPointer(AssociatedDecl);
ID.AddInteger(Index);
ID.AddInteger(PackIndex.toInternalRepresentation());
ID.AddBoolean(Final);
}
SubstTemplateTemplateParmPackStorage::SubstTemplateTemplateParmPackStorage(
ArrayRef<TemplateArgument> ArgPack, Decl *AssociatedDecl, unsigned Index,
bool Final)
: UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Index,
ArgPack.size()),
Arguments(ArgPack.data()), AssociatedDeclAndFinal(AssociatedDecl, Final) {
assert(AssociatedDecl != nullptr);
}
void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
ASTContext &Context) {
Profile(ID, Context, getArgumentPack(), getAssociatedDecl(), getIndex(),
getFinal());
}
Decl *SubstTemplateTemplateParmPackStorage::getAssociatedDecl() const {
return AssociatedDeclAndFinal.getPointer();
}
bool SubstTemplateTemplateParmPackStorage::getFinal() const {
return AssociatedDeclAndFinal.getInt();
}
void SubstTemplateTemplateParmPackStorage::Profile(
llvm::FoldingSetNodeID &ID, ASTContext &Context,
const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index,
bool Final) {
ArgPack.Profile(ID, Context);
ID.AddPointer(AssociatedDecl);
ID.AddInteger(Index);
ID.AddBoolean(Final);
}
IdentifierOrOverloadedOperator::IdentifierOrOverloadedOperator(
const IdentifierInfo *II)
: PtrOrOp(reinterpret_cast<uintptr_t>(II)) {
static_assert(NUM_OVERLOADED_OPERATORS <= 4096,
"NUM_OVERLOADED_OPERATORS is too large");
assert(II);
assert(getIdentifier() == II);
}
IdentifierOrOverloadedOperator::IdentifierOrOverloadedOperator(
OverloadedOperatorKind OOK)
: PtrOrOp(-uintptr_t(OOK)) {
assert(OOK != OO_None);
assert(getOperator() == OOK);
}
void IdentifierOrOverloadedOperator::Profile(llvm::FoldingSetNodeID &ID) const {
if (auto *Identifier = getIdentifier()) {
ID.AddBoolean(false);
ID.AddPointer(Identifier);
} else {
ID.AddBoolean(true);
ID.AddInteger(getOperator());
}
}
TemplateName::TemplateName(void *Ptr) {
Storage = StorageType::getFromOpaqueValue(Ptr);
}
TemplateName::TemplateName(TemplateDecl *Template) : Storage(Template) {}
TemplateName::TemplateName(OverloadedTemplateStorage *Storage)
: Storage(Storage) {}
TemplateName::TemplateName(AssumedTemplateStorage *Storage)
: Storage(Storage) {}
TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage)
: Storage(Storage) {}
TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
: Storage(Storage) {}
TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {}
TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {}
TemplateName::TemplateName(UsingShadowDecl *Using) : Storage(Using) {}
TemplateName::TemplateName(DeducedTemplateStorage *Deduced)
: Storage(Deduced) {}
bool TemplateName::isNull() const { return Storage.isNull(); }
TemplateName::NameKind TemplateName::getKind() const {
if (auto *ND = dyn_cast<Decl *>(Storage)) {
if (isa<UsingShadowDecl>(ND))
return UsingTemplate;
assert(isa<TemplateDecl>(ND));
return Template;
}
if (isa<DependentTemplateName *>(Storage))
return DependentTemplate;
if (isa<QualifiedTemplateName *>(Storage))
return QualifiedTemplate;
UncommonTemplateNameStorage *uncommon =
cast<UncommonTemplateNameStorage *>(Storage);
if (uncommon->getAsOverloadedStorage())
return OverloadedTemplate;
if (uncommon->getAsAssumedTemplateName())
return AssumedTemplate;
if (uncommon->getAsSubstTemplateTemplateParm())
return SubstTemplateTemplateParm;
if (uncommon->getAsDeducedTemplateName())
return DeducedTemplate;
assert(uncommon->getAsSubstTemplateTemplateParmPack() != nullptr);
return SubstTemplateTemplateParmPack;
}
TemplateDecl *TemplateName::getAsTemplateDecl(bool IgnoreDeduced) const {
TemplateName Name = *this;
while (std::optional<TemplateName> UnderlyingOrNone =
Name.desugar(IgnoreDeduced))
Name = *UnderlyingOrNone;
if (!IgnoreDeduced)
assert(Name.getAsDeducedTemplateName() == nullptr &&
"Unexpected canonical DeducedTemplateName; Did you mean to use "
"getTemplateDeclAndDefaultArgs instead?");
return cast_if_present<TemplateDecl>(
dyn_cast_if_present<Decl *>(Name.Storage));
}
std::pair<TemplateDecl *, DefaultArguments>
TemplateName::getTemplateDeclAndDefaultArgs() const {
for (TemplateName Name = *this; /**/; /**/) {
if (Name.getKind() == TemplateName::DeducedTemplate) {
DeducedTemplateStorage *DTS = Name.getAsDeducedTemplateName();
TemplateDecl *TD =
DTS->getUnderlying().getAsTemplateDecl(/*IgnoreDeduced=*/true);
DefaultArguments DefArgs = DTS->getDefaultArguments();
if (TD && DefArgs)
assert(DefArgs.StartPos + DefArgs.Args.size() <=
TD->getTemplateParameters()->size());
return {TD, DTS->getDefaultArguments()};
}
if (std::optional<TemplateName> UnderlyingOrNone =
Name.desugar(/*IgnoreDeduced=*/false)) {
Name = *UnderlyingOrNone;
continue;
}
return {cast_if_present<TemplateDecl>(Name.Storage.dyn_cast<Decl *>()), {}};
}
}
std::optional<TemplateName> TemplateName::desugar(bool IgnoreDeduced) const {
if (Decl *D = dyn_cast_if_present<Decl *>(Storage)) {
if (auto *USD = dyn_cast<UsingShadowDecl>(D))
return TemplateName(USD->getTargetDecl());
return std::nullopt;
}
if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
return QTN->getUnderlyingTemplate();
if (SubstTemplateTemplateParmStorage *S = getAsSubstTemplateTemplateParm())
return S->getReplacement();
if (IgnoreDeduced)
if (DeducedTemplateStorage *S = getAsDeducedTemplateName())
return S->getUnderlying();
return std::nullopt;
}
OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const {
if (UncommonTemplateNameStorage *Uncommon =
Storage.dyn_cast<UncommonTemplateNameStorage *>())
return Uncommon->getAsOverloadedStorage();
return nullptr;
}
AssumedTemplateStorage *TemplateName::getAsAssumedTemplateName() const {
if (UncommonTemplateNameStorage *Uncommon =
Storage.dyn_cast<UncommonTemplateNameStorage *>())
return Uncommon->getAsAssumedTemplateName();
return nullptr;
}
SubstTemplateTemplateParmStorage *
TemplateName::getAsSubstTemplateTemplateParm() const {
if (UncommonTemplateNameStorage *uncommon =
dyn_cast_if_present<UncommonTemplateNameStorage *>(Storage))
return uncommon->getAsSubstTemplateTemplateParm();
return nullptr;
}
SubstTemplateTemplateParmPackStorage *
TemplateName::getAsSubstTemplateTemplateParmPack() const {
if (UncommonTemplateNameStorage *Uncommon =
Storage.dyn_cast<UncommonTemplateNameStorage *>())
return Uncommon->getAsSubstTemplateTemplateParmPack();
return nullptr;
}
QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const {
return dyn_cast_if_present<QualifiedTemplateName *>(Storage);
}
DependentTemplateName *TemplateName::getAsDependentTemplateName() const {
return Storage.dyn_cast<DependentTemplateName *>();
}
UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const {
if (Decl *D = Storage.dyn_cast<Decl *>())
if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D))
return USD;
if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
return QTN->getUnderlyingTemplate().getAsUsingShadowDecl();
return nullptr;
}
DependentTemplateStorage::DependentTemplateStorage(
NestedNameSpecifier *Qualifier, IdentifierOrOverloadedOperator Name,
bool HasTemplateKeyword)
: Qualifier(Qualifier, HasTemplateKeyword), Name(Name) {
assert((!Qualifier || Qualifier->isDependent()) &&
"Qualifier must be dependent");
}
TemplateNameDependence DependentTemplateStorage::getDependence() const {
auto D = TemplateNameDependence::DependentInstantiation;
if (NestedNameSpecifier *Qualifier = getQualifier())
D |= toTemplateNameDependence(Qualifier->getDependence());
return D;
}
void DependentTemplateStorage::print(raw_ostream &OS,
const PrintingPolicy &Policy) const {
if (NestedNameSpecifier *NNS = getQualifier())
NNS->print(OS, Policy);
if (hasTemplateKeyword())
OS << "template ";
IdentifierOrOverloadedOperator Name = getName();
if (const IdentifierInfo *II = Name.getIdentifier())
OS << II->getName();
else
OS << "operator " << getOperatorSpelling(Name.getOperator());
}
DeducedTemplateStorage *TemplateName::getAsDeducedTemplateName() const {
if (UncommonTemplateNameStorage *Uncommon =
dyn_cast_if_present<UncommonTemplateNameStorage *>(Storage))
return Uncommon->getAsDeducedTemplateName();
return nullptr;
}
TemplateNameDependence TemplateName::getDependence() const {
switch (getKind()) {
case NameKind::Template:
case NameKind::UsingTemplate: {
TemplateDecl *Template = getAsTemplateDecl();
auto D = TemplateNameDependence::None;
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) {
D |= TemplateNameDependence::DependentInstantiation;
if (TTP->isParameterPack())
D |= TemplateNameDependence::UnexpandedPack;
}
// FIXME: Hack, getDeclContext() can be null if Template is still
// initializing due to PCH reading, so we check it before using it.
// Should probably modify TemplateSpecializationType to allow constructing
// it without the isDependent() checking.
if (Template->getDeclContext() &&
Template->getDeclContext()->isDependentContext())
D |= TemplateNameDependence::DependentInstantiation;
return D;
}
case NameKind::QualifiedTemplate: {
QualifiedTemplateName *S = getAsQualifiedTemplateName();
TemplateNameDependence D = S->getUnderlyingTemplate().getDependence();
if (NestedNameSpecifier *NNS = S->getQualifier())
D |= toTemplateNameDependence(NNS->getDependence());
return D;
}
case NameKind::DependentTemplate: {
DependentTemplateName *S = getAsDependentTemplateName();
auto D = TemplateNameDependence::DependentInstantiation;
if (NestedNameSpecifier *Qualifier = S->getQualifier())
D |= toTemplateNameDependence(Qualifier->getDependence());
return D;
}
case NameKind::SubstTemplateTemplateParm: {
auto *S = getAsSubstTemplateTemplateParm();
return S->getReplacement().getDependence();
}
case NameKind::SubstTemplateTemplateParmPack:
return TemplateNameDependence::UnexpandedPack |
TemplateNameDependence::DependentInstantiation;
case NameKind::DeducedTemplate: {
DeducedTemplateStorage *DTS = getAsDeducedTemplateName();
TemplateNameDependence D = DTS->getUnderlying().getDependence();
for (const TemplateArgument &Arg : DTS->getDefaultArguments().Args)
D |= toTemplateNameDependence(Arg.getDependence());
return D;
}
case NameKind::AssumedTemplate:
return TemplateNameDependence::DependentInstantiation;
case NameKind::OverloadedTemplate:
llvm_unreachable("overloaded templates shouldn't survive to here.");
}
llvm_unreachable("Unknown TemplateName kind");
}
bool TemplateName::isDependent() const {
return getDependence() & TemplateNameDependence::Dependent;
}
bool TemplateName::isInstantiationDependent() const {
return getDependence() & TemplateNameDependence::Instantiation;
}
bool TemplateName::containsUnexpandedParameterPack() const {
return getDependence() & TemplateNameDependence::UnexpandedPack;
}
void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
Qualified Qual) const {
auto handleAnonymousTTP = [&](TemplateDecl *TD, raw_ostream &OS) {
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(TD);
TTP && (Policy.PrintAsCanonical || TTP->getIdentifier() == nullptr)) {
OS << "template-parameter-" << TTP->getDepth() << "-" << TTP->getIndex();
return true;
}
return false;
};
if (NameKind Kind = getKind();
Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) {
// After `namespace ns { using std::vector }`, what is the fully-qualified
// name of the UsingTemplateName `vector` within ns?
//
// - ns::vector (the qualified name of the using-shadow decl)
// - std::vector (the qualified name of the underlying template decl)
//
// Similar to the UsingType behavior, using declarations are used to import
// names more often than to export them, thus using the original name is
// most useful in this case.
TemplateDecl *Template = getAsTemplateDecl();
if (Policy.PrintAsCanonical)
Template = cast<TemplateDecl>(Template->getCanonicalDecl());
if (handleAnonymousTTP(Template, OS))
return;
if (Qual == Qualified::None)
OS << *Template;
else
Template->printQualifiedName(OS, Policy);
} else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
if (Policy.PrintAsCanonical) {
QTN->getUnderlyingTemplate().print(OS, Policy, Qual);
return;
}
if (NestedNameSpecifier *NNS = QTN->getQualifier();
Qual != Qualified::None && NNS)
NNS->print(OS, Policy);
if (QTN->hasTemplateKeyword())
OS << "template ";
TemplateName Underlying = QTN->getUnderlyingTemplate();
assert(Underlying.getKind() == TemplateName::Template ||
Underlying.getKind() == TemplateName::UsingTemplate);
TemplateDecl *UTD = Underlying.getAsTemplateDecl();
if (handleAnonymousTTP(UTD, OS))
return;
if (IdentifierInfo *II = UTD->getIdentifier();
Policy.CleanUglifiedParameters && II &&
isa<TemplateTemplateParmDecl>(UTD))
OS << II->deuglifiedName();
else
OS << *UTD;
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
DTN->print(OS, Policy);
} else if (SubstTemplateTemplateParmStorage *subst =
getAsSubstTemplateTemplateParm()) {
subst->getReplacement().print(OS, Policy, Qual);
} else if (SubstTemplateTemplateParmPackStorage *SubstPack =
getAsSubstTemplateTemplateParmPack())
OS << *SubstPack->getParameterPack();
else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
Assumed->getDeclName().print(OS, Policy);
} else if (DeducedTemplateStorage *Deduced = getAsDeducedTemplateName()) {
Deduced->getUnderlying().print(OS, Policy);
DefaultArguments DefArgs = Deduced->getDefaultArguments();
OS << ":" << DefArgs.StartPos;
printTemplateArgumentList(OS, DefArgs.Args, Policy);
} else {
assert(getKind() == TemplateName::OverloadedTemplate);
OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
(*OTS->begin())->printName(OS, Policy);
}
}
const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
TemplateName N) {
std::string NameStr;
llvm::raw_string_ostream OS(NameStr);
LangOptions LO;
LO.CPlusPlus = true;
LO.Bool = true;
OS << '\'';
N.print(OS, PrintingPolicy(LO));
OS << '\'';
return DB << NameStr;
}