Implements the changes required to perform substitution with non-canonical template arguments, and to 'finalize' them by not placing 'Subst' nodes. A finalized substitution means we won't resugar them later, because these templates themselves were eagerly substituted with the intended arguments at the point of use. We may still resugar other templates used within those, though. This patch does not actually implement any uses of this functionality, those will be added in subsequent patches, so expect no changes to existing tests. Signed-off-by: Matheus Izvekov <mizvekov@gmail.com> Differential Revision: https://reviews.llvm.org/D134604
373 lines
13 KiB
C++
373 lines
13 KiB
C++
//===- 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/Casting.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <cassert>
|
|
#include <string>
|
|
|
|
using namespace clang;
|
|
|
|
TemplateArgument
|
|
SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
|
|
return TemplateArgument(llvm::makeArrayRef(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());
|
|
}
|
|
|
|
void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID,
|
|
TemplateName Replacement,
|
|
Decl *AssociatedDecl,
|
|
unsigned Index,
|
|
Optional<unsigned> PackIndex) {
|
|
Replacement.Profile(ID);
|
|
ID.AddPointer(AssociatedDecl);
|
|
ID.AddInteger(Index);
|
|
ID.AddInteger(PackIndex ? *PackIndex + 1 : 0);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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) {}
|
|
|
|
bool TemplateName::isNull() const { return Storage.isNull(); }
|
|
|
|
TemplateName::NameKind TemplateName::getKind() const {
|
|
if (auto *ND = Storage.dyn_cast<Decl *>()) {
|
|
if (isa<UsingShadowDecl>(ND))
|
|
return UsingTemplate;
|
|
assert(isa<TemplateDecl>(ND));
|
|
return Template;
|
|
}
|
|
|
|
if (Storage.is<DependentTemplateName *>())
|
|
return DependentTemplate;
|
|
if (Storage.is<QualifiedTemplateName *>())
|
|
return QualifiedTemplate;
|
|
|
|
UncommonTemplateNameStorage *uncommon
|
|
= Storage.get<UncommonTemplateNameStorage*>();
|
|
if (uncommon->getAsOverloadedStorage())
|
|
return OverloadedTemplate;
|
|
if (uncommon->getAsAssumedTemplateName())
|
|
return AssumedTemplate;
|
|
if (uncommon->getAsSubstTemplateTemplateParm())
|
|
return SubstTemplateTemplateParm;
|
|
return SubstTemplateTemplateParmPack;
|
|
}
|
|
|
|
TemplateDecl *TemplateName::getAsTemplateDecl() const {
|
|
if (Decl *TemplateOrUsing = Storage.dyn_cast<Decl *>()) {
|
|
if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(TemplateOrUsing))
|
|
return cast<TemplateDecl>(USD->getTargetDecl());
|
|
|
|
assert(isa<TemplateDecl>(TemplateOrUsing));
|
|
return cast<TemplateDecl>(TemplateOrUsing);
|
|
}
|
|
|
|
if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
|
|
return QTN->getUnderlyingTemplate().getAsTemplateDecl();
|
|
|
|
if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm())
|
|
return sub->getReplacement().getAsTemplateDecl();
|
|
|
|
if (UsingShadowDecl *USD = getAsUsingShadowDecl())
|
|
return cast<TemplateDecl>(USD->getTargetDecl());
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
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 =
|
|
Storage.dyn_cast<UncommonTemplateNameStorage *>())
|
|
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 Storage.dyn_cast<QualifiedTemplateName *>();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
TemplateName TemplateName::getNameToSubstitute() const {
|
|
TemplateDecl *Decl = getAsTemplateDecl();
|
|
|
|
// Substituting a dependent template name: preserve it as written.
|
|
if (!Decl)
|
|
return *this;
|
|
|
|
// If we have a template declaration, use the most recent non-friend
|
|
// declaration of that template.
|
|
Decl = cast<TemplateDecl>(Decl->getMostRecentDecl());
|
|
while (Decl->getFriendObjectKind()) {
|
|
Decl = cast<TemplateDecl>(Decl->getPreviousDecl());
|
|
assert(Decl && "all declarations of template are friends");
|
|
}
|
|
return TemplateName(Decl);
|
|
}
|
|
|
|
TemplateNameDependence TemplateName::getDependence() const {
|
|
auto D = TemplateNameDependence::None;
|
|
switch (getKind()) {
|
|
case TemplateName::NameKind::QualifiedTemplate:
|
|
D |= toTemplateNameDependence(
|
|
getAsQualifiedTemplateName()->getQualifier()->getDependence());
|
|
break;
|
|
case TemplateName::NameKind::DependentTemplate:
|
|
D |= toTemplateNameDependence(
|
|
getAsDependentTemplateName()->getQualifier()->getDependence());
|
|
break;
|
|
case TemplateName::NameKind::SubstTemplateTemplateParmPack:
|
|
D |= TemplateNameDependence::UnexpandedPack;
|
|
break;
|
|
case TemplateName::NameKind::OverloadedTemplate:
|
|
llvm_unreachable("overloaded templates shouldn't survive to here.");
|
|
default:
|
|
break;
|
|
}
|
|
if (TemplateDecl *Template = getAsTemplateDecl()) {
|
|
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;
|
|
} else {
|
|
D |= TemplateNameDependence::DependentInstantiation;
|
|
}
|
|
return D;
|
|
}
|
|
|
|
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 Kind = getKind();
|
|
TemplateDecl *Template = nullptr;
|
|
if (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.
|
|
Template = getAsTemplateDecl();
|
|
}
|
|
|
|
if (Template)
|
|
if (Policy.CleanUglifiedParameters &&
|
|
isa<TemplateTemplateParmDecl>(Template) && Template->getIdentifier())
|
|
OS << Template->getIdentifier()->deuglifiedName();
|
|
else if (Qual == Qualified::Fully &&
|
|
getDependence() !=
|
|
TemplateNameDependenceScope::DependentInstantiation)
|
|
Template->printQualifiedName(OS, Policy);
|
|
else
|
|
OS << *Template;
|
|
else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
|
|
if (Qual == Qualified::Fully &&
|
|
getDependence() !=
|
|
TemplateNameDependenceScope::DependentInstantiation) {
|
|
QTN->getUnderlyingTemplate().getAsTemplateDecl()->printQualifiedName(
|
|
OS, Policy);
|
|
return;
|
|
}
|
|
if (Qual == Qualified::AsWritten)
|
|
QTN->getQualifier()->print(OS, Policy);
|
|
if (QTN->hasTemplateKeyword())
|
|
OS << "template ";
|
|
OS << *QTN->getUnderlyingTemplate().getAsTemplateDecl();
|
|
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
|
|
if (Qual == Qualified::AsWritten && DTN->getQualifier())
|
|
DTN->getQualifier()->print(OS, Policy);
|
|
OS << "template ";
|
|
|
|
if (DTN->isIdentifier())
|
|
OS << DTN->getIdentifier()->getName();
|
|
else
|
|
OS << "operator " << getOperatorSpelling(DTN->getOperator());
|
|
} 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 {
|
|
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 << '\'';
|
|
OS.flush();
|
|
return DB << NameStr;
|
|
}
|
|
|
|
void TemplateName::dump(raw_ostream &OS) const {
|
|
LangOptions LO; // FIXME!
|
|
LO.CPlusPlus = true;
|
|
LO.Bool = true;
|
|
print(OS, PrintingPolicy(LO));
|
|
}
|
|
|
|
LLVM_DUMP_METHOD void TemplateName::dump() const {
|
|
dump(llvm::errs());
|
|
}
|