Skip to content

Commit

Permalink
[clang] Track the templated entity in type substitution.
Browse files Browse the repository at this point in the history
This is a change to how we represent type subsitution in the AST.
Instead of only storing the replaced type, we track the templated
entity we are substituting, plus an index.
We modify MLTAL to track the templated entity at each level.

Otherwise, it's much more expensive to go from the template parameter back
to the templated entity, and not possible to do in some cases, as when
we instantiate outer templates, parameters might still reference the
original entity.

This also allows us to very cheaply lookup the templated entity we saw in
the naming context and find the corresponding argument it was replaced
from, such as for implementing template specialization resugaring.

Signed-off-by: Matheus Izvekov <mizvekov@gmail.com>

Differential Revision: https://reviews.llvm.org/D131858
  • Loading branch information
mizvekov committed Oct 15, 2022
1 parent 0784de2 commit bcd9ba2
Show file tree
Hide file tree
Showing 46 changed files with 981 additions and 641 deletions.
Expand Up @@ -52,7 +52,7 @@ void ExceptionBaseclassCheck::check(const MatchFinder::MatchResult &Result) {
diag(BadThrow->getSubExpr()->getBeginLoc(),
"type %0 is a template instantiation of %1", DiagnosticIDs::Note)
<< BadThrow->getSubExpr()->getType()
<< Template->getReplacedParameter()->getDecl();
<< Template->getReplacedParameter();

if (const auto *TypeDecl = Result.Nodes.getNodeAs<NamedDecl>("decl"))
diag(TypeDecl->getBeginLoc(), "type defined here", DiagnosticIDs::Note);
Expand Down
Expand Up @@ -191,12 +191,12 @@ bool differentReplacedTemplateParams(const QualType &VarType,
getSubstitutedType(VarType, Context)) {
if (const SubstTemplateTypeParmType *InitializerTmplType =
getSubstitutedType(InitializerType, Context)) {
return VarTmplType->getReplacedParameter()
->desugar()
.getCanonicalType() !=
InitializerTmplType->getReplacedParameter()
->desugar()
.getCanonicalType();
const TemplateTypeParmDecl *VarTTP = VarTmplType->getReplacedParameter();
const TemplateTypeParmDecl *InitTTP =
InitializerTmplType->getReplacedParameter();
return (VarTTP->getDepth() != InitTTP->getDepth() ||
VarTTP->getIndex() != InitTTP->getIndex() ||
VarTTP->isParameterPack() != InitTTP->isParameterPack());
}
}
return false;
Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/clangd/AST.cpp
Expand Up @@ -730,8 +730,8 @@ const TemplateTypeParmType *getUnderylingPackType(const ParmVarDecl *Param) {
if (const auto *SubstType = dyn_cast<SubstTemplateTypeParmType>(PlainType)) {
const auto *ReplacedParameter = SubstType->getReplacedParameter();
if (ReplacedParameter->isParameterPack()) {
return dyn_cast<TemplateTypeParmType>(
ReplacedParameter->getCanonicalTypeUnqualified()->getTypePtr());
return ReplacedParameter->getTypeForDecl()
->castAs<TemplateTypeParmType>();
}
}
return nullptr;
Expand Down
21 changes: 12 additions & 9 deletions clang/include/clang/AST/ASTContext.h
Expand Up @@ -1617,12 +1617,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
QualType Wrapped);

QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced,
QualType Replacement,
QualType getSubstTemplateTypeParmType(QualType Replacement,
Decl *AssociatedDecl, unsigned Index,
Optional<unsigned> PackIndex) const;
QualType
getSubstTemplateTypeParmPackType(const TemplateTypeParmType *Replaced,
const TemplateArgument &ArgPack);
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
unsigned Index,
const TemplateArgument &ArgPack);

QualType
getTemplateTypeParmType(unsigned Depth, unsigned Index,
Expand Down Expand Up @@ -2202,10 +2202,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
const IdentifierInfo *Name) const;
TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
OverloadedOperatorKind Operator) const;
TemplateName getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param,
TemplateName replacement) const;
TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
const TemplateArgument &ArgPack) const;
TemplateName getSubstTemplateTemplateParm(TemplateName replacement,
Decl *AssociatedDecl,
unsigned Index,
Optional<unsigned> PackIndex) const;
TemplateName getSubstTemplateTemplateParmPack(const TemplateArgument &ArgPack,
Decl *AssociatedDecl,
unsigned Index) const;

enum GetBuiltinTypeError {
/// No error
Expand Down
5 changes: 1 addition & 4 deletions clang/include/clang/AST/ASTNodeTraverser.h
Expand Up @@ -389,12 +389,9 @@ class ASTNodeTraverser
void VisitBTFTagAttributedType(const BTFTagAttributedType *T) {
Visit(T->getWrappedType());
}
void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
Visit(T->getReplacedParameter());
}
void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *) {}
void
VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
Visit(T->getReplacedParameter());
Visit(T->getArgumentPack());
}
void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
Expand Down
19 changes: 11 additions & 8 deletions clang/include/clang/AST/DeclTemplate.h
Expand Up @@ -459,18 +459,17 @@ class TemplateDecl : public NamedDecl {
NamedDecl *TemplatedDecl;
TemplateParameterList *TemplateParams;

public:
void setTemplateParameters(TemplateParameterList *TParams) {
TemplateParams = TParams;
}

public:
/// Initialize the underlying templated declaration and
/// template parameters.
void init(NamedDecl *templatedDecl, TemplateParameterList* templateParams) {
assert(!TemplatedDecl && "TemplatedDecl already set!");
assert(!TemplateParams && "TemplateParams already set!");
TemplatedDecl = templatedDecl;
TemplateParams = templateParams;
/// Initialize the underlying templated declaration.
void init(NamedDecl *NewTemplatedDecl) {
if (TemplatedDecl)
assert(TemplatedDecl == NewTemplatedDecl && "Inconsistent TemplatedDecl");
else
TemplatedDecl = NewTemplatedDecl;
}
};

Expand Down Expand Up @@ -3425,6 +3424,10 @@ inline Optional<unsigned> getExpandedPackSize(const NamedDecl *Param) {
return None;
}

/// Internal helper used by Subst* nodes to retrieve the parameter list
/// for their AssociatedDecl.
TemplateParameterList *getReplacedTemplateParameterList(Decl *D);

} // namespace clang

#endif // LLVM_CLANG_AST_DECLTEMPLATE_H
2 changes: 1 addition & 1 deletion clang/include/clang/AST/DeclarationName.h
Expand Up @@ -941,7 +941,7 @@ class AssumedTemplateStorage : public UncommonTemplateNameStorage {
friend class ASTContext;

AssumedTemplateStorage(DeclarationName Name)
: UncommonTemplateNameStorage(Assumed, 0), Name(Name) {}
: UncommonTemplateNameStorage(Assumed, 0, 0), Name(Name) {}
DeclarationName Name;

public:
Expand Down
63 changes: 45 additions & 18 deletions clang/include/clang/AST/ExprCXX.h
Expand Up @@ -4270,24 +4270,30 @@ class SubstNonTypeTemplateParmExpr : public Expr {
friend class ASTReader;
friend class ASTStmtReader;

/// The replaced parameter and a flag indicating if it was a reference
/// The replacement expression.
Stmt *Replacement;

/// The associated declaration and a flag indicating if it was a reference
/// parameter. For class NTTPs, we can't determine that based on the value
/// category alone.
llvm::PointerIntPair<NonTypeTemplateParmDecl*, 1, bool> ParamAndRef;
llvm::PointerIntPair<Decl *, 1, bool> AssociatedDeclAndRef;

/// The replacement expression.
Stmt *Replacement;
unsigned Index : 15;
unsigned PackIndex : 16;

explicit SubstNonTypeTemplateParmExpr(EmptyShell Empty)
: Expr(SubstNonTypeTemplateParmExprClass, Empty) {}

public:
SubstNonTypeTemplateParmExpr(QualType Ty, ExprValueKind ValueKind,
SourceLocation Loc,
NonTypeTemplateParmDecl *Param, bool RefParam,
Expr *Replacement)
SourceLocation Loc, Expr *Replacement,
Decl *AssociatedDecl, unsigned Index,
Optional<unsigned> PackIndex, bool RefParam)
: Expr(SubstNonTypeTemplateParmExprClass, Ty, ValueKind, OK_Ordinary),
ParamAndRef(Param, RefParam), Replacement(Replacement) {
Replacement(Replacement),
AssociatedDeclAndRef(AssociatedDecl, RefParam), Index(Index),
PackIndex(PackIndex ? *PackIndex + 1 : 0) {
assert(AssociatedDecl != nullptr);
SubstNonTypeTemplateParmExprBits.NameLoc = Loc;
setDependence(computeDependence(this));
}
Expand All @@ -4300,11 +4306,23 @@ class SubstNonTypeTemplateParmExpr : public Expr {

Expr *getReplacement() const { return cast<Expr>(Replacement); }

NonTypeTemplateParmDecl *getParameter() const {
return ParamAndRef.getPointer();
/// A template-like entity which owns the whole pattern being substituted.
/// This will own a set of template parameters.
Decl *getAssociatedDecl() const { return AssociatedDeclAndRef.getPointer(); }

/// Returns the index of the replaced parameter in the associated declaration.
/// This should match the result of `getParameter()->getIndex()`.
unsigned getIndex() const { return Index; }

Optional<unsigned> getPackIndex() const {
if (PackIndex == 0)
return None;
return PackIndex - 1;
}

bool isReferenceParameter() const { return ParamAndRef.getInt(); }
NonTypeTemplateParmDecl *getParameter() const;

bool isReferenceParameter() const { return AssociatedDeclAndRef.getInt(); }

/// Determine the substituted type of the template parameter.
QualType getParameterType(const ASTContext &Ctx) const;
Expand Down Expand Up @@ -4338,14 +4356,16 @@ class SubstNonTypeTemplateParmPackExpr : public Expr {
friend class ASTStmtReader;

/// The non-type template parameter pack itself.
NonTypeTemplateParmDecl *Param;
Decl *AssociatedDecl;

/// A pointer to the set of template arguments that this
/// parameter pack is instantiated with.
const TemplateArgument *Arguments;

/// The number of template arguments in \c Arguments.
unsigned NumArguments;
unsigned NumArguments : 16;

unsigned Index : 16;

/// The location of the non-type template parameter pack reference.
SourceLocation NameLoc;
Expand All @@ -4354,14 +4374,21 @@ class SubstNonTypeTemplateParmPackExpr : public Expr {
: Expr(SubstNonTypeTemplateParmPackExprClass, Empty) {}

public:
SubstNonTypeTemplateParmPackExpr(QualType T,
ExprValueKind ValueKind,
NonTypeTemplateParmDecl *Param,
SubstNonTypeTemplateParmPackExpr(QualType T, ExprValueKind ValueKind,
SourceLocation NameLoc,
const TemplateArgument &ArgPack);
const TemplateArgument &ArgPack,
Decl *AssociatedDecl, unsigned Index);

/// A template-like entity which owns the whole pattern being substituted.
/// This will own a set of template parameters.
Decl *getAssociatedDecl() const { return AssociatedDecl; }

/// Returns the index of the replaced parameter in the associated declaration.
/// This should match the result of `getParameterPack()->getIndex()`.
unsigned getIndex() const { return Index; }

/// Retrieve the non-type template parameter pack being substituted.
NonTypeTemplateParmDecl *getParameterPack() const { return Param; }
NonTypeTemplateParmDecl *getParameterPack() const;

/// Retrieve the location of the parameter pack name.
SourceLocation getParameterPackLocation() const { return NameLoc; }
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/JSONNodeDumper.h
Expand Up @@ -222,6 +222,8 @@ class JSONNodeDumper
void VisitTagType(const TagType *TT);
void VisitTemplateTypeParmType(const TemplateTypeParmType *TTPT);
void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *STTPT);
void
VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T);
void VisitAutoType(const AutoType *AT);
void VisitTemplateSpecializationType(const TemplateSpecializationType *TST);
void VisitInjectedClassNameType(const InjectedClassNameType *ICNT);
Expand Down
25 changes: 17 additions & 8 deletions clang/include/clang/AST/PropertiesBase.td
Expand Up @@ -701,28 +701,37 @@ let Class = PropertyTypeCase<TemplateName, "SubstTemplateTemplateParm"> in {
def : ReadHelper<[{
auto parm = node.getAsSubstTemplateTemplateParm();
}]>;
def : Property<"parameter", TemplateTemplateParmDeclRef> {
let Read = [{ parm->getParameter() }];
}
def : Property<"replacement", TemplateName> {
let Read = [{ parm->getReplacement() }];
}
def : Property<"associatedDecl", DeclRef> {
let Read = [{ parm->getAssociatedDecl() }];
}
def : Property<"index", UInt32> {
let Read = [{ parm->getIndex() }];
}
def : Property<"packIndex", Optional<UInt32>> {
let Read = [{ parm->getPackIndex() }];
}
def : Creator<[{
return ctx.getSubstTemplateTemplateParm(parameter, replacement);
return ctx.getSubstTemplateTemplateParm(replacement, associatedDecl, index, packIndex);
}]>;
}
let Class = PropertyTypeCase<TemplateName, "SubstTemplateTemplateParmPack"> in {
def : ReadHelper<[{
auto parm = node.getAsSubstTemplateTemplateParmPack();
}]>;
def : Property<"parameterPack", TemplateTemplateParmDeclRef> {
let Read = [{ parm->getParameterPack() }];
}
def : Property<"argumentPack", TemplateArgument> {
let Read = [{ parm->getArgumentPack() }];
}
def : Property<"associatedDecl", DeclRef> {
let Read = [{ parm->getAssociatedDecl() }];
}
def : Property<"index", UInt32> {
let Read = [{ parm->getIndex() }];
}
def : Creator<[{
return ctx.getSubstTemplateTemplateParmPack(parameterPack, argumentPack);
return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index);
}]>;
}

Expand Down

0 comments on commit bcd9ba2

Please sign in to comment.