Skip to content

Commit

Permalink
[clang] Implement sugared substitution changes to infrastructure
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mizvekov committed Oct 26, 2022
1 parent 5312198 commit c4c2a3c
Show file tree
Hide file tree
Showing 22 changed files with 447 additions and 289 deletions.
5 changes: 3 additions & 2 deletions clang/include/clang/AST/ASTContext.h
Expand Up @@ -1621,7 +1621,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
Decl *AssociatedDecl, unsigned Index,
Optional<unsigned> PackIndex) const;
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
unsigned Index,
unsigned Index, bool Final,
const TemplateArgument &ArgPack);

QualType
Expand Down Expand Up @@ -2207,7 +2207,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
Optional<unsigned> PackIndex) const;
TemplateName getSubstTemplateTemplateParmPack(const TemplateArgument &ArgPack,
Decl *AssociatedDecl,
unsigned Index) const;
unsigned Index,
bool Final) const;

enum GetBuiltinTypeError {
/// No error
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/AST/PropertiesBase.td
Expand Up @@ -730,8 +730,11 @@ let Class = PropertyTypeCase<TemplateName, "SubstTemplateTemplateParmPack"> in {
def : Property<"index", UInt32> {
let Read = [{ parm->getIndex() }];
}
def : Property<"final", Bool> {
let Read = [{ parm->getFinal() }];
}
def : Creator<[{
return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index);
return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index, final);
}]>;
}

Expand Down
17 changes: 8 additions & 9 deletions clang/include/clang/AST/TemplateName.h
Expand Up @@ -139,25 +139,24 @@ class OverloadedTemplateStorage : public UncommonTemplateNameStorage {
class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage,
public llvm::FoldingSetNode {
const TemplateArgument *Arguments;
Decl *AssociatedDecl;
llvm::PointerIntPair<Decl *, 1, bool> AssociatedDeclAndFinal;

public:
SubstTemplateTemplateParmPackStorage(ArrayRef<TemplateArgument> ArgPack,
Decl *AssociatedDecl, unsigned Index)
: UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Index,
ArgPack.size()),
Arguments(ArgPack.data()), AssociatedDecl(AssociatedDecl) {
assert(AssociatedDecl != nullptr);
}
Decl *AssociatedDecl, unsigned Index,
bool Final);

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

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

// When true the substitution will be 'Final' (subst node won't be placed).
bool getFinal() const;

/// Retrieve the template template parameter pack being substituted.
TemplateTemplateParmDecl *getParameterPack() const;

Expand All @@ -169,7 +168,7 @@ class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage,

static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
const TemplateArgument &ArgPack, Decl *AssociatedDecl,
unsigned Index);
unsigned Index, bool Final);
};

/// Represents a C++ template name within the type system.
Expand Down
12 changes: 8 additions & 4 deletions clang/include/clang/AST/Type.h
Expand Up @@ -5158,10 +5158,10 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
/// parameter pack is instantiated with.
const TemplateArgument *Arguments;

Decl *AssociatedDecl;
llvm::PointerIntPair<Decl *, 1, bool> AssociatedDeclAndFinal;

SubstTemplateTypeParmPackType(QualType Canon, Decl *AssociatedDecl,
unsigned Index,
unsigned Index, bool Final,
const TemplateArgument &ArgPack);

public:
Expand All @@ -5170,7 +5170,7 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
/// A template-like entity which owns the whole pattern being substituted.
/// This will usually own a set of template parameters, or in some
/// cases might even be a template parameter itself.
Decl *getAssociatedDecl() const { return AssociatedDecl; }
Decl *getAssociatedDecl() const;

/// Gets the template parameter declaration that was substituted for.
const TemplateTypeParmDecl *getReplacedParameter() const;
Expand All @@ -5179,6 +5179,9 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
/// This should match the result of `getReplacedParameter()->getIndex()`.
unsigned getIndex() const { return SubstTemplateTypeParmPackTypeBits.Index; }

// When true the substitution will be 'Final' (subst node won't be placed).
bool getFinal() const;

unsigned getNumArgs() const {
return SubstTemplateTypeParmPackTypeBits.NumArgs;
}
Expand All @@ -5190,7 +5193,8 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {

void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl,
unsigned Index, const TemplateArgument &ArgPack);
unsigned Index, bool Final,
const TemplateArgument &ArgPack);

static bool classof(const Type *T) {
return T->getTypeClass() == SubstTemplateTypeParmPack;
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/AST/TypeProperties.td
Expand Up @@ -773,13 +773,16 @@ let Class = SubstTemplateTypeParmPackType in {
def : Property<"Index", UInt32> {
let Read = [{ node->getIndex() }];
}
def : Property<"Final", Bool> {
let Read = [{ node->getFinal() }];
}
def : Property<"replacementPack", TemplateArgument> {
let Read = [{ node->getArgumentPack() }];
}

def : Creator<[{
return ctx.getSubstTemplateTypeParmPackType(
associatedDecl, Index, replacementPack);
associatedDecl, Index, Final, replacementPack);
}]>;
}

Expand Down
26 changes: 12 additions & 14 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -9074,10 +9074,12 @@ class Sema final {
// C++ Template Instantiation
//

MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
const NamedDecl *D, const TemplateArgumentList *Innermost = nullptr,
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
bool ForConstraintInstantiation = false);
MultiLevelTemplateArgumentList
getTemplateInstantiationArgs(const NamedDecl *D, bool Final = false,
const TemplateArgumentList *Innermost = nullptr,
bool RelativeToPrimary = false,
const FunctionDecl *Pattern = nullptr,
bool ForConstraintInstantiation = false);

/// A context in which code is being synthesized (where a source location
/// alone is not sufficient to identify the context). This covers template
Expand Down Expand Up @@ -10171,16 +10173,12 @@ class Sema final {
bool FailOnError = false);

/// Build an Objective-C object pointer type.
QualType BuildObjCObjectType(QualType BaseType,
SourceLocation Loc,
SourceLocation TypeArgsLAngleLoc,
ArrayRef<TypeSourceInfo *> TypeArgs,
SourceLocation TypeArgsRAngleLoc,
SourceLocation ProtocolLAngleLoc,
ArrayRef<ObjCProtocolDecl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc,
bool FailOnError = false);
QualType BuildObjCObjectType(
QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc,
ArrayRef<TypeSourceInfo *> TypeArgs, SourceLocation TypeArgsRAngleLoc,
SourceLocation ProtocolLAngleLoc, ArrayRef<ObjCProtocolDecl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs, SourceLocation ProtocolRAngleLoc,
bool FailOnError, bool Rebuilding);

/// Ensure attributes are consistent with type.
/// \param [in, out] Attributes The attributes to check; they will
Expand Down
23 changes: 13 additions & 10 deletions clang/include/clang/Sema/Template.h
Expand Up @@ -77,7 +77,7 @@ enum class TemplateSubstitutionKind : char {

using ArgList = ArrayRef<TemplateArgument>;
struct ArgumentListLevel {
Decl *AssociatedDecl;
llvm::PointerIntPair<Decl *, 1, bool> AssociatedDeclAndFinal;
ArgList Args;
};
using ContainerType = SmallVector<ArgumentListLevel, 4>;
Expand All @@ -101,8 +101,8 @@ enum class TemplateSubstitutionKind : char {
MultiLevelTemplateArgumentList() = default;

/// Construct a single-level template argument list.
MultiLevelTemplateArgumentList(Decl *D, ArgList Args) {
addOuterTemplateArguments(D, Args);
MultiLevelTemplateArgumentList(Decl *D, ArgList Args, bool Final) {
addOuterTemplateArguments(D, Args, Final);
}

void setKind(TemplateSubstitutionKind K) { Kind = K; }
Expand Down Expand Up @@ -160,9 +160,11 @@ enum class TemplateSubstitutionKind : char {
/// A template-like entity which owns the whole pattern being substituted.
/// This will usually own a set of template parameters, or in some
/// cases might even be a template parameter itself.
Decl *getAssociatedDecl(unsigned Depth) const {
std::pair<Decl *, bool> getAssociatedDecl(unsigned Depth) const {
assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
return TemplateArgumentLists[getNumLevels() - Depth - 1].AssociatedDecl;
auto AD = TemplateArgumentLists[getNumLevels() - Depth - 1]
.AssociatedDeclAndFinal;
return {AD.getPointer(), AD.getInt()};
}

/// Determine whether there is a non-NULL template argument at the
Expand Down Expand Up @@ -202,21 +204,22 @@ enum class TemplateSubstitutionKind : char {

/// Add a new outmost level to the multi-level template argument
/// list.
void addOuterTemplateArguments(Decl *AssociatedDecl, ArgList Args) {
/// A 'Final' substitution means that Subst* nodes won't be built
/// for the replacements.
void addOuterTemplateArguments(Decl *AssociatedDecl, ArgList Args,
bool Final) {
assert(!NumRetainedOuterLevels &&
"substituted args outside retained args?");
assert(getKind() == TemplateSubstitutionKind::Specialization);
assert(AssociatedDecl != nullptr || Args.size() == 0);
TemplateArgumentLists.push_back(
{AssociatedDecl ? AssociatedDecl->getCanonicalDecl() : nullptr,
Args});
{{AssociatedDecl->getCanonicalDecl(), Final}, Args});
}

void addOuterTemplateArguments(ArgList Args) {
assert(!NumRetainedOuterLevels &&
"substituted args outside retained args?");
assert(getKind() == TemplateSubstitutionKind::Rewrite);
TemplateArgumentLists.push_back({nullptr, Args});
TemplateArgumentLists.push_back({{}, Args});
}

void addOuterTemplateArguments(llvm::NoneType) {
Expand Down

0 comments on commit c4c2a3c

Please sign in to comment.