Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clang-tools-extra/clangd/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,8 @@ QualType declaredType(const TypeDecl *D) {
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
if (const auto *Args = CTSD->getTemplateArgsAsWritten())
return Context.getTemplateSpecializationType(
TemplateName(CTSD->getSpecializedTemplate()), Args->arguments());
TemplateName(CTSD->getSpecializedTemplate()), Args->arguments(),
/*CanonicalArgs=*/std::nullopt);
return Context.getTypeDeclType(D);
}

Expand Down
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ Improvements to Clang's diagnostics
- Clang now better preserves the sugared types of pointers to member.
- Clang now better preserves the presence of the template keyword with dependent
prefixes.
- Clang now in more cases avoids printing 'type-parameter-X-X' instead of the name of
the template parameter.
- Clang now respects the current language mode when printing expressions in
diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also
a bunch of HLSL types being printed as their C++ equivalents.
Expand Down
46 changes: 31 additions & 15 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
const ASTContext&>
CanonTemplateTemplateParms;

TemplateTemplateParmDecl *
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;

/// The typedef for the __int128_t type.
mutable TypedefDecl *Int128Decl = nullptr;

Expand Down Expand Up @@ -1808,22 +1805,26 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool ParameterPack,
TemplateTypeParmDecl *ParmDecl = nullptr) const;

QualType getTemplateSpecializationType(TemplateName T,
ArrayRef<TemplateArgument> Args,
QualType Canon = QualType()) const;
QualType getCanonicalTemplateSpecializationType(
TemplateName T, ArrayRef<TemplateArgument> CanonicalArgs) const;

QualType
getCanonicalTemplateSpecializationType(TemplateName T,
ArrayRef<TemplateArgument> Args) const;
getTemplateSpecializationType(TemplateName T,
ArrayRef<TemplateArgument> SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs,
QualType Underlying = QualType()) const;

QualType getTemplateSpecializationType(TemplateName T,
ArrayRef<TemplateArgumentLoc> Args,
QualType Canon = QualType()) const;
QualType
getTemplateSpecializationType(TemplateName T,
ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs,
QualType Canon = QualType()) const;

TypeSourceInfo *
getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc,
const TemplateArgumentListInfo &Args,
QualType Canon = QualType()) const;
TypeSourceInfo *getTemplateSpecializationTypeInfo(
TemplateName T, SourceLocation TLoc,
const TemplateArgumentListInfo &SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs,
QualType Canon = QualType()) const;

QualType getParenType(QualType NamedType) const;

Expand Down Expand Up @@ -2939,6 +2940,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg)
const;

/// Canonicalize the given template argument list.
///
/// Returns true if any arguments were non-canonical, false otherwise.
bool
canonicalizeTemplateArguments(MutableArrayRef<TemplateArgument> Args) const;

/// Canonicalize the given TemplateTemplateParmDecl.
TemplateTemplateParmDecl *
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;

TemplateTemplateParmDecl *findCanonicalTemplateTemplateParmDeclInternal(
TemplateTemplateParmDecl *TTP) const;
TemplateTemplateParmDecl *insertCanonicalTemplateTemplateParmDeclInternal(
TemplateTemplateParmDecl *CanonTTP) const;

/// Type Query functions. If the type is an instance of the specified class,
/// return the Type pointer for the underlying maximally pretty type. This
/// is a member of ASTContext because this may need to do some amount of
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -877,11 +877,14 @@ let Class = PropertyTypeCase<TemplateArgument, "Expression"> in {
def : Property<"expression", ExprRef> {
let Read = [{ node.getAsExpr() }];
}
def : Property<"IsCanonical", Bool> {
let Read = [{ node.isCanonicalExpr() }];
}
def : Property<"isDefaulted", Bool> {
let Read = [{ node.getIsDefaulted() }];
}
def : Creator<[{
return TemplateArgument(expression, isDefaulted);
return TemplateArgument(expression, IsCanonical, isDefaulted);
}]>;
}
let Class = PropertyTypeCase<TemplateArgument, "Pack"> in {
Expand Down
13 changes: 11 additions & 2 deletions clang/include/clang/AST/TemplateBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ class TemplateArgument {
unsigned Kind : 31;
LLVM_PREFERRED_TYPE(bool)
unsigned IsDefaulted : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsCanonicalExpr : 1;
uintptr_t V;
};
union {
Expand All @@ -187,7 +189,8 @@ class TemplateArgument {

public:
/// Construct an empty, invalid template argument.
constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {}
constexpr TemplateArgument()
: TypeOrValue{Null, /*IsDefaulted=*/0, /*IsCanonicalExpr=*/0, /*V=*/0} {}

/// Construct a template type argument.
TemplateArgument(QualType T, bool isNullPtr = false,
Expand Down Expand Up @@ -262,9 +265,10 @@ class TemplateArgument {
/// This form of template argument only occurs in template argument
/// lists used for dependent types and for expression; it will not
/// occur in a non-dependent, canonical template argument list.
explicit TemplateArgument(Expr *E, bool IsDefaulted = false) {
TemplateArgument(Expr *E, bool IsCanonical, bool IsDefaulted = false) {
TypeOrValue.Kind = Expression;
TypeOrValue.IsDefaulted = IsDefaulted;
TypeOrValue.IsCanonicalExpr = IsCanonical;
TypeOrValue.V = reinterpret_cast<uintptr_t>(E);
}

Expand Down Expand Up @@ -407,6 +411,11 @@ class TemplateArgument {
return reinterpret_cast<Expr *>(TypeOrValue.V);
}

bool isCanonicalExpr() const {
assert(getKind() == Expression && "Unexpected kind");
return TypeOrValue.IsCanonicalExpr;
}

/// Iterator that traverses the elements of a template argument pack.
using pack_iterator = const TemplateArgument *;

Expand Down
7 changes: 3 additions & 4 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -6676,10 +6676,9 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
/// replacement must, recursively, be one of these).
TemplateName Template;

TemplateSpecializationType(TemplateName T,
TemplateSpecializationType(TemplateName T, bool IsAlias,
ArrayRef<TemplateArgument> Args,
QualType Canon,
QualType Aliased);
QualType Underlying);

public:
/// Determine whether any of the given template arguments are dependent.
Expand Down Expand Up @@ -6747,7 +6746,7 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {

void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
ArrayRef<TemplateArgument> Args,
ArrayRef<TemplateArgument> Args, QualType Underlying,
const ASTContext &Context);

static bool classof(const Type *T) {
Expand Down
30 changes: 5 additions & 25 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -737,39 +737,19 @@ let Class = DependentAddressSpaceType in {
}

let Class = TemplateSpecializationType in {
def : Property<"dependent", Bool> {
let Read = [{ node->isDependentType() }];
}
def : Property<"templateName", TemplateName> {
let Read = [{ node->getTemplateName() }];
}
def : Property<"templateArguments", Array<TemplateArgument>> {
def : Property<"args", Array<TemplateArgument>> {
let Read = [{ node->template_arguments() }];
}
def : Property<"underlyingType", Optional<QualType>> {
let Read = [{
node->isTypeAlias()
? std::optional<QualType>(node->getAliasedType())
: node->isCanonicalUnqualified()
? std::nullopt
: std::optional<QualType>(node->getCanonicalTypeInternal())
}];
def : Property<"UnderlyingType", QualType> {
let Read = [{ node->isCanonicalUnqualified() ? QualType() :
node->desugar() }];
}

def : Creator<[{
QualType result;
if (!underlyingType) {
result = ctx.getCanonicalTemplateSpecializationType(templateName,
templateArguments);
} else {
result = ctx.getTemplateSpecializationType(templateName,
templateArguments,
*underlyingType);
}
if (dependent)
const_cast<Type *>(result.getTypePtr())
->addDependence(TypeDependence::DependentInstantiation);
return result;
return ctx.getTemplateSpecializationType(templateName, args, std::nullopt, UnderlyingType);
}]>;
}

Expand Down
Loading
Loading