mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-13 08:46:22 +00:00
Reland: [clang] Improved canonicalization for template specialization types (#135414)
This relands https://github.com/llvm/llvm-project/pull/135119, after fixing crashes seen in LLDB CI reported here: https://github.com/llvm/llvm-project/pull/135119#issuecomment-2794910840 Fixes https://github.com/llvm/llvm-project/pull/135119 This changes the TemplateArgument representation to hold a flag indicating whether a tempalte argument of expression type is supposed to be canonical or not. This gets one step closer to solving https://github.com/llvm/llvm-project/issues/92292 This still doesn't try to unique as-written TSTs. While this would increase the amount of memory savings and make code dealing with the AST more well-behaved, profiling template argument lists is still too expensive for this to be worthwhile, at least for now. This also fixes the context creation of TSTs, so that they don't in some cases get incorrectly flagged as sugar over their own canonical form. This is captured in the test expectation change of some AST dumps. This fixes some places which were unnecessarily canonicalizing these TSTs.
This commit is contained in:
parent
009971a0d3
commit
761787d425
@ -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);
|
||||
}
|
||||
|
||||
|
@ -303,6 +303,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.
|
||||
|
@ -243,8 +243,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
mutable llvm::FoldingSet<PackExpansionType> PackExpansionTypes;
|
||||
mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
|
||||
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
|
||||
mutable llvm::FoldingSet<DependentUnaryTransformType>
|
||||
DependentUnaryTransformTypes;
|
||||
mutable llvm::FoldingSet<UnaryTransformType> UnaryTransformTypes;
|
||||
// An AutoType can have a dependency on another AutoType via its template
|
||||
// arguments. Since both dependent and dependency are on the same set,
|
||||
// we can end up in an infinite recursion when looking for a node if we used
|
||||
@ -367,9 +366,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;
|
||||
|
||||
@ -1811,22 +1807,26 @@ public:
|
||||
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;
|
||||
|
||||
@ -2942,6 +2942,21 @@ public:
|
||||
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
|
||||
|
@ -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 {
|
||||
|
@ -167,6 +167,8 @@ private:
|
||||
unsigned Kind : 31;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned IsDefaulted : 1;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned IsCanonicalExpr : 1;
|
||||
uintptr_t V;
|
||||
};
|
||||
union {
|
||||
@ -187,7 +189,8 @@ private:
|
||||
|
||||
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,
|
||||
@ -262,9 +265,10 @@ public:
|
||||
/// 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);
|
||||
}
|
||||
|
||||
@ -407,6 +411,11 @@ public:
|
||||
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 *;
|
||||
|
||||
|
@ -5918,7 +5918,7 @@ public:
|
||||
/// of this class via DecltypeType nodes.
|
||||
class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
|
||||
public:
|
||||
DependentDecltypeType(Expr *E, QualType UnderlyingTpe);
|
||||
DependentDecltypeType(Expr *E);
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
|
||||
Profile(ID, Context, getUnderlyingExpr());
|
||||
@ -6003,7 +6003,7 @@ private:
|
||||
};
|
||||
|
||||
/// A unary type transform, which is a type constructed from another.
|
||||
class UnaryTransformType : public Type {
|
||||
class UnaryTransformType : public Type, public llvm::FoldingSetNode {
|
||||
public:
|
||||
enum UTTKind {
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum,
|
||||
@ -6037,28 +6037,16 @@ public:
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == UnaryTransform;
|
||||
}
|
||||
};
|
||||
|
||||
/// Internal representation of canonical, dependent
|
||||
/// __underlying_type(type) types.
|
||||
///
|
||||
/// This class is used internally by the ASTContext to manage
|
||||
/// canonical, dependent types, only. Clients will only see instances
|
||||
/// of this class via UnaryTransformType nodes.
|
||||
class DependentUnaryTransformType : public UnaryTransformType,
|
||||
public llvm::FoldingSetNode {
|
||||
public:
|
||||
DependentUnaryTransformType(const ASTContext &C, QualType BaseType,
|
||||
UTTKind UKind);
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getBaseType(), getUTTKind());
|
||||
Profile(ID, getBaseType(), getUnderlyingType(), getUTTKind());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType,
|
||||
UTTKind UKind) {
|
||||
ID.AddPointer(BaseType.getAsOpaquePtr());
|
||||
ID.AddInteger((unsigned)UKind);
|
||||
QualType UnderlyingType, UTTKind UKind) {
|
||||
BaseType.Profile(ID);
|
||||
UnderlyingType.Profile(ID);
|
||||
ID.AddInteger(UKind);
|
||||
}
|
||||
};
|
||||
|
||||
@ -6676,10 +6664,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.
|
||||
@ -6747,7 +6734,7 @@ public:
|
||||
|
||||
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) {
|
||||
|
@ -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);
|
||||
}]>;
|
||||
}
|
||||
|
||||
|
@ -844,6 +844,31 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
|
||||
return CanonTTP;
|
||||
}
|
||||
|
||||
TemplateTemplateParmDecl *
|
||||
ASTContext::findCanonicalTemplateTemplateParmDeclInternal(
|
||||
TemplateTemplateParmDecl *TTP) const {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
CanonicalTemplateTemplateParm::Profile(ID, *this, TTP);
|
||||
void *InsertPos = nullptr;
|
||||
CanonicalTemplateTemplateParm *Canonical =
|
||||
CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos);
|
||||
return Canonical ? Canonical->getParam() : nullptr;
|
||||
}
|
||||
|
||||
TemplateTemplateParmDecl *
|
||||
ASTContext::insertCanonicalTemplateTemplateParmDeclInternal(
|
||||
TemplateTemplateParmDecl *CanonTTP) const {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
CanonicalTemplateTemplateParm::Profile(ID, *this, CanonTTP);
|
||||
void *InsertPos = nullptr;
|
||||
if (auto *Existing =
|
||||
CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return Existing->getParam();
|
||||
CanonTemplateTemplateParms.InsertNode(
|
||||
new (*this) CanonicalTemplateTemplateParm(CanonTTP), InsertPos);
|
||||
return CanonTTP;
|
||||
}
|
||||
|
||||
/// Check if a type can have its sanitizer instrumentation elided based on its
|
||||
/// presence within an ignorelist.
|
||||
bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
|
||||
@ -3083,12 +3108,19 @@ static auto getCanonicalTemplateArguments(const ASTContext &C,
|
||||
ArrayRef<TemplateArgument> Args,
|
||||
bool &AnyNonCanonArgs) {
|
||||
SmallVector<TemplateArgument, 16> CanonArgs(Args);
|
||||
for (auto &Arg : CanonArgs) {
|
||||
AnyNonCanonArgs |= C.canonicalizeTemplateArguments(CanonArgs);
|
||||
return CanonArgs;
|
||||
}
|
||||
|
||||
bool ASTContext::canonicalizeTemplateArguments(
|
||||
MutableArrayRef<TemplateArgument> Args) const {
|
||||
bool AnyNonCanonArgs = false;
|
||||
for (auto &Arg : Args) {
|
||||
TemplateArgument OrigArg = Arg;
|
||||
Arg = C.getCanonicalTemplateArgument(Arg);
|
||||
Arg = getCanonicalTemplateArgument(Arg);
|
||||
AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg);
|
||||
}
|
||||
return CanonArgs;
|
||||
return AnyNonCanonArgs;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -5538,129 +5570,118 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
||||
return QualType(TypeParm, 0);
|
||||
}
|
||||
|
||||
TypeSourceInfo *
|
||||
ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
|
||||
SourceLocation NameLoc,
|
||||
const TemplateArgumentListInfo &Args,
|
||||
QualType Underlying) const {
|
||||
assert(!Name.getAsDependentTemplateName() &&
|
||||
"No dependent template names here!");
|
||||
QualType TST =
|
||||
getTemplateSpecializationType(Name, Args.arguments(), Underlying);
|
||||
TypeSourceInfo *ASTContext::getTemplateSpecializationTypeInfo(
|
||||
TemplateName Name, SourceLocation NameLoc,
|
||||
const TemplateArgumentListInfo &SpecifiedArgs,
|
||||
ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
|
||||
QualType TST = getTemplateSpecializationType(Name, SpecifiedArgs.arguments(),
|
||||
CanonicalArgs, Underlying);
|
||||
|
||||
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
|
||||
TemplateSpecializationTypeLoc TL =
|
||||
DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>();
|
||||
TL.setTemplateKeywordLoc(SourceLocation());
|
||||
TL.setTemplateNameLoc(NameLoc);
|
||||
TL.setLAngleLoc(Args.getLAngleLoc());
|
||||
TL.setRAngleLoc(Args.getRAngleLoc());
|
||||
TL.setLAngleLoc(SpecifiedArgs.getLAngleLoc());
|
||||
TL.setRAngleLoc(SpecifiedArgs.getRAngleLoc());
|
||||
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
|
||||
TL.setArgLocInfo(i, Args[i].getLocInfo());
|
||||
TL.setArgLocInfo(i, SpecifiedArgs[i].getLocInfo());
|
||||
return DI;
|
||||
}
|
||||
|
||||
QualType
|
||||
ASTContext::getTemplateSpecializationType(TemplateName Template,
|
||||
ArrayRef<TemplateArgumentLoc> Args,
|
||||
QualType Underlying) const {
|
||||
assert(!Template.getAsDependentTemplateName() &&
|
||||
"No dependent template names here!");
|
||||
QualType ASTContext::getTemplateSpecializationType(
|
||||
TemplateName Template, ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
|
||||
ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
|
||||
SmallVector<TemplateArgument, 4> SpecifiedArgVec;
|
||||
SpecifiedArgVec.reserve(SpecifiedArgs.size());
|
||||
for (const TemplateArgumentLoc &Arg : SpecifiedArgs)
|
||||
SpecifiedArgVec.push_back(Arg.getArgument());
|
||||
|
||||
SmallVector<TemplateArgument, 4> ArgVec;
|
||||
ArgVec.reserve(Args.size());
|
||||
for (const TemplateArgumentLoc &Arg : Args)
|
||||
ArgVec.push_back(Arg.getArgument());
|
||||
|
||||
return getTemplateSpecializationType(Template, ArgVec, Underlying);
|
||||
return getTemplateSpecializationType(Template, SpecifiedArgVec, CanonicalArgs,
|
||||
Underlying);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static bool hasAnyPackExpansions(ArrayRef<TemplateArgument> Args) {
|
||||
[[maybe_unused]] static bool
|
||||
hasAnyPackExpansions(ArrayRef<TemplateArgument> Args) {
|
||||
for (const TemplateArgument &Arg : Args)
|
||||
if (Arg.isPackExpansion())
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
QualType
|
||||
ASTContext::getTemplateSpecializationType(TemplateName Template,
|
||||
ArrayRef<TemplateArgument> Args,
|
||||
QualType Underlying) const {
|
||||
assert(!Template.getAsDependentTemplateName() &&
|
||||
"No dependent template names here!");
|
||||
|
||||
const auto *TD = Template.getAsTemplateDecl(/*IgnoreDeduced=*/true);
|
||||
bool IsTypeAlias = TD && TD->isTypeAlias();
|
||||
QualType CanonType;
|
||||
if (!Underlying.isNull())
|
||||
CanonType = getCanonicalType(Underlying);
|
||||
else {
|
||||
// We can get here with an alias template when the specialization contains
|
||||
// a pack expansion that does not match up with a parameter pack.
|
||||
assert((!IsTypeAlias || hasAnyPackExpansions(Args)) &&
|
||||
"Caller must compute aliased type");
|
||||
IsTypeAlias = false;
|
||||
CanonType = getCanonicalTemplateSpecializationType(Template, Args);
|
||||
}
|
||||
|
||||
// Allocate the (non-canonical) template specialization type, but don't
|
||||
// try to unique it: these types typically have location information that
|
||||
// we don't unique and don't want to lose.
|
||||
void *Mem = Allocate(sizeof(TemplateSpecializationType) +
|
||||
sizeof(TemplateArgument) * Args.size() +
|
||||
(IsTypeAlias ? sizeof(QualType) : 0),
|
||||
alignof(TemplateSpecializationType));
|
||||
auto *Spec
|
||||
= new (Mem) TemplateSpecializationType(Template, Args, CanonType,
|
||||
IsTypeAlias ? Underlying : QualType());
|
||||
|
||||
Types.push_back(Spec);
|
||||
return QualType(Spec, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
QualType ASTContext::getCanonicalTemplateSpecializationType(
|
||||
TemplateName Template, ArrayRef<TemplateArgument> Args) const {
|
||||
assert(!Template.getAsDependentTemplateName() &&
|
||||
assert(Template ==
|
||||
getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true));
|
||||
assert(!Args.empty());
|
||||
#ifndef NDEBUG
|
||||
for (const auto &Arg : Args)
|
||||
assert(Arg.structurallyEquals(getCanonicalTemplateArgument(Arg)));
|
||||
#endif
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
TemplateSpecializationType::Profile(ID, Template, Args, QualType(), *this);
|
||||
void *InsertPos = nullptr;
|
||||
if (auto *T = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(T, 0);
|
||||
|
||||
void *Mem = Allocate(sizeof(TemplateSpecializationType) +
|
||||
sizeof(TemplateArgument) * Args.size(),
|
||||
alignof(TemplateSpecializationType));
|
||||
auto *Spec = new (Mem)
|
||||
TemplateSpecializationType(Template, /*IsAlias=*/false, Args, QualType());
|
||||
assert(Spec->isDependentType() &&
|
||||
"canonical template specialization must be dependent");
|
||||
Types.push_back(Spec);
|
||||
TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
|
||||
return QualType(Spec, 0);
|
||||
}
|
||||
|
||||
QualType ASTContext::getTemplateSpecializationType(
|
||||
TemplateName Template, ArrayRef<TemplateArgument> SpecifiedArgs,
|
||||
ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
|
||||
assert(!Template.getUnderlying().getAsDependentTemplateName() &&
|
||||
"No dependent template names here!");
|
||||
|
||||
// Build the canonical template specialization type.
|
||||
// Any DeducedTemplateNames are ignored, because the effective name of a TST
|
||||
// accounts for the TST arguments laid over any default arguments contained in
|
||||
// its name.
|
||||
TemplateName CanonTemplate =
|
||||
getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true);
|
||||
const auto *TD = Template.getAsTemplateDecl(/*IgnoreDeduced=*/true);
|
||||
bool IsTypeAlias = TD && TD->isTypeAlias();
|
||||
if (Underlying.isNull()) {
|
||||
TemplateName CanonTemplate =
|
||||
getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true);
|
||||
bool NonCanonical = Template != CanonTemplate;
|
||||
SmallVector<TemplateArgument, 4> CanonArgsVec;
|
||||
if (CanonicalArgs.empty()) {
|
||||
CanonArgsVec = SmallVector<TemplateArgument, 4>(SpecifiedArgs);
|
||||
NonCanonical |= canonicalizeTemplateArguments(CanonArgsVec);
|
||||
CanonicalArgs = CanonArgsVec;
|
||||
} else {
|
||||
NonCanonical |= !llvm::equal(
|
||||
SpecifiedArgs, CanonicalArgs,
|
||||
[](const TemplateArgument &A, const TemplateArgument &B) {
|
||||
return A.structurallyEquals(B);
|
||||
});
|
||||
}
|
||||
|
||||
bool AnyNonCanonArgs = false;
|
||||
auto CanonArgs =
|
||||
::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
|
||||
// We can get here with an alias template when the specialization
|
||||
// contains a pack expansion that does not match up with a parameter
|
||||
// pack, or a builtin template which cannot be resolved due to dependency.
|
||||
assert((!isa_and_nonnull<TypeAliasTemplateDecl>(TD) ||
|
||||
hasAnyPackExpansions(CanonicalArgs)) &&
|
||||
"Caller must compute aliased type");
|
||||
IsTypeAlias = false;
|
||||
|
||||
// Determine whether this canonical template specialization type already
|
||||
// exists.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
TemplateSpecializationType::Profile(ID, CanonTemplate,
|
||||
CanonArgs, *this);
|
||||
|
||||
void *InsertPos = nullptr;
|
||||
TemplateSpecializationType *Spec
|
||||
= TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
|
||||
if (!Spec) {
|
||||
// Allocate a new canonical template specialization type.
|
||||
void *Mem = Allocate((sizeof(TemplateSpecializationType) +
|
||||
sizeof(TemplateArgument) * CanonArgs.size()),
|
||||
alignof(TemplateSpecializationType));
|
||||
Spec = new (Mem) TemplateSpecializationType(CanonTemplate,
|
||||
CanonArgs,
|
||||
QualType(), QualType());
|
||||
Types.push_back(Spec);
|
||||
TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
|
||||
Underlying =
|
||||
getCanonicalTemplateSpecializationType(CanonTemplate, CanonicalArgs);
|
||||
if (!NonCanonical)
|
||||
return Underlying;
|
||||
}
|
||||
|
||||
assert(Spec->isDependentType() &&
|
||||
"Non-dependent template-id type must have a canonical type");
|
||||
void *Mem = Allocate(sizeof(TemplateSpecializationType) +
|
||||
sizeof(TemplateArgument) * SpecifiedArgs.size() +
|
||||
(IsTypeAlias ? sizeof(QualType) : 0),
|
||||
alignof(TemplateSpecializationType));
|
||||
auto *Spec = new (Mem) TemplateSpecializationType(Template, IsTypeAlias,
|
||||
SpecifiedArgs, Underlying);
|
||||
Types.push_back(Spec);
|
||||
return QualType(Spec, 0);
|
||||
}
|
||||
|
||||
@ -5853,7 +5874,7 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) const {
|
||||
|
||||
if (NTTP->isParameterPack())
|
||||
E = new (*this) PackExpansionExpr(E, NTTP->getLocation(), std::nullopt);
|
||||
Arg = TemplateArgument(E);
|
||||
Arg = TemplateArgument(E, /*IsCanonical=*/false);
|
||||
} else {
|
||||
auto *TTP = cast<TemplateTemplateParmDecl>(Param);
|
||||
TemplateName Name = getQualifiedTemplateName(
|
||||
@ -6334,34 +6355,36 @@ QualType ASTContext::getReferenceQualifiedType(const Expr *E) const {
|
||||
/// nodes. This would never be helpful, since each such type has its own
|
||||
/// expression, and would not give a significant memory saving, since there
|
||||
/// is an Expr tree under each such type.
|
||||
QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const {
|
||||
DecltypeType *dt;
|
||||
|
||||
QualType ASTContext::getDecltypeType(Expr *E, QualType UnderlyingType) const {
|
||||
// C++11 [temp.type]p2:
|
||||
// If an expression e involves a template parameter, decltype(e) denotes a
|
||||
// unique dependent type. Two such decltype-specifiers refer to the same
|
||||
// type only if their expressions are equivalent (14.5.6.1).
|
||||
if (e->isInstantiationDependent()) {
|
||||
QualType CanonType;
|
||||
if (!E->isInstantiationDependent()) {
|
||||
CanonType = getCanonicalType(UnderlyingType);
|
||||
} else if (!UnderlyingType.isNull()) {
|
||||
CanonType = getDecltypeType(E, QualType());
|
||||
} else {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
DependentDecltypeType::Profile(ID, *this, e);
|
||||
DependentDecltypeType::Profile(ID, *this, E);
|
||||
|
||||
void *InsertPos = nullptr;
|
||||
DependentDecltypeType *Canon
|
||||
= DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
if (!Canon) {
|
||||
// Build a new, canonical decltype(expr) type.
|
||||
Canon = new (*this, alignof(DependentDecltypeType))
|
||||
DependentDecltypeType(e, DependentTy);
|
||||
DependentDecltypeTypes.InsertNode(Canon, InsertPos);
|
||||
}
|
||||
dt = new (*this, alignof(DecltypeType))
|
||||
DecltypeType(e, UnderlyingType, QualType((DecltypeType *)Canon, 0));
|
||||
} else {
|
||||
dt = new (*this, alignof(DecltypeType))
|
||||
DecltypeType(e, UnderlyingType, getCanonicalType(UnderlyingType));
|
||||
if (DependentDecltypeType *Canon =
|
||||
DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(Canon, 0);
|
||||
|
||||
// Build a new, canonical decltype(expr) type.
|
||||
auto *DT =
|
||||
new (*this, alignof(DependentDecltypeType)) DependentDecltypeType(E);
|
||||
DependentDecltypeTypes.InsertNode(DT, InsertPos);
|
||||
Types.push_back(DT);
|
||||
return QualType(DT, 0);
|
||||
}
|
||||
Types.push_back(dt);
|
||||
return QualType(dt, 0);
|
||||
auto *DT = new (*this, alignof(DecltypeType))
|
||||
DecltypeType(E, UnderlyingType, CanonType);
|
||||
Types.push_back(DT);
|
||||
return QualType(DT, 0);
|
||||
}
|
||||
|
||||
QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
|
||||
@ -6401,36 +6424,41 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
|
||||
|
||||
/// getUnaryTransformationType - We don't unique these, since the memory
|
||||
/// savings are minimal and these are rare.
|
||||
QualType ASTContext::getUnaryTransformType(QualType BaseType,
|
||||
QualType UnderlyingType,
|
||||
UnaryTransformType::UTTKind Kind)
|
||||
const {
|
||||
UnaryTransformType *ut = nullptr;
|
||||
QualType
|
||||
ASTContext::getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
|
||||
UnaryTransformType::UTTKind Kind) const {
|
||||
|
||||
if (BaseType->isDependentType()) {
|
||||
// Look in the folding set for an existing type.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
DependentUnaryTransformType::Profile(ID, getCanonicalType(BaseType), Kind);
|
||||
llvm::FoldingSetNodeID ID;
|
||||
UnaryTransformType::Profile(ID, BaseType, UnderlyingType, Kind);
|
||||
|
||||
void *InsertPos = nullptr;
|
||||
DependentUnaryTransformType *Canon
|
||||
= DependentUnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
void *InsertPos = nullptr;
|
||||
if (UnaryTransformType *UT =
|
||||
UnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(UT, 0);
|
||||
|
||||
if (!Canon) {
|
||||
// Build a new, canonical __underlying_type(type) type.
|
||||
Canon = new (*this, alignof(DependentUnaryTransformType))
|
||||
DependentUnaryTransformType(*this, getCanonicalType(BaseType), Kind);
|
||||
DependentUnaryTransformTypes.InsertNode(Canon, InsertPos);
|
||||
}
|
||||
ut = new (*this, alignof(UnaryTransformType))
|
||||
UnaryTransformType(BaseType, QualType(), Kind, QualType(Canon, 0));
|
||||
QualType CanonType;
|
||||
if (!BaseType->isDependentType()) {
|
||||
CanonType = UnderlyingType.getCanonicalType();
|
||||
} else {
|
||||
QualType CanonType = getCanonicalType(UnderlyingType);
|
||||
ut = new (*this, alignof(UnaryTransformType))
|
||||
UnaryTransformType(BaseType, UnderlyingType, Kind, CanonType);
|
||||
assert(UnderlyingType.isNull() || BaseType == UnderlyingType);
|
||||
UnderlyingType = QualType();
|
||||
if (QualType CanonBase = BaseType.getCanonicalType();
|
||||
BaseType != CanonBase) {
|
||||
CanonType = getUnaryTransformType(CanonBase, QualType(), Kind);
|
||||
assert(CanonType.isCanonical());
|
||||
|
||||
// Find the insertion position again.
|
||||
[[maybe_unused]] UnaryTransformType *UT =
|
||||
UnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(!UT && "broken canonicalization");
|
||||
}
|
||||
}
|
||||
Types.push_back(ut);
|
||||
return QualType(ut, 0);
|
||||
|
||||
auto *UT = new (*this, alignof(UnaryTransformType))
|
||||
UnaryTransformType(BaseType, UnderlyingType, Kind, CanonType);
|
||||
UnaryTransformTypes.InsertNode(UT, InsertPos);
|
||||
Types.push_back(UT);
|
||||
return QualType(UT, 0);
|
||||
}
|
||||
|
||||
QualType ASTContext::getAutoTypeInternal(
|
||||
@ -6461,9 +6489,9 @@ QualType ASTContext::getAutoTypeInternal(
|
||||
auto CanonicalConceptArgs = ::getCanonicalTemplateArguments(
|
||||
*this, TypeConstraintArgs, AnyNonCanonArgs);
|
||||
if (CanonicalConcept != TypeConstraintConcept || AnyNonCanonArgs) {
|
||||
Canon =
|
||||
getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
|
||||
CanonicalConcept, CanonicalConceptArgs, true);
|
||||
Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
|
||||
CanonicalConcept, CanonicalConceptArgs,
|
||||
/*IsCanon=*/true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7543,7 +7571,8 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
|
||||
return Arg;
|
||||
|
||||
case TemplateArgument::Expression:
|
||||
return Arg;
|
||||
return TemplateArgument(Arg.getAsExpr(), /*IsCanonical=*/true,
|
||||
Arg.getIsDefaulted());
|
||||
|
||||
case TemplateArgument::Declaration: {
|
||||
auto *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl());
|
||||
@ -8199,8 +8228,7 @@ QualType ASTContext::getObjCSuperType() const {
|
||||
void ASTContext::setCFConstantStringType(QualType T) {
|
||||
const auto *TD = T->castAs<TypedefType>();
|
||||
CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl());
|
||||
const auto *TagType =
|
||||
CFConstantStringTypeDecl->getUnderlyingType()->castAs<RecordType>();
|
||||
const auto *TagType = TD->castAs<RecordType>();
|
||||
CFConstantStringTagDecl = TagType->getDecl();
|
||||
}
|
||||
|
||||
@ -14012,7 +14040,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
|
||||
::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(),
|
||||
TY->getTemplateName(),
|
||||
/*IgnoreDeduced=*/true),
|
||||
As, X->getCanonicalTypeInternal());
|
||||
As, /*CanonicalArgs=*/std::nullopt, X->getCanonicalTypeInternal());
|
||||
}
|
||||
case Type::Decltype: {
|
||||
const auto *DX = cast<DecltypeType>(X);
|
||||
@ -14252,11 +14280,12 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
|
||||
TY->getTemplateName(), /*IgnoreDeduced=*/true);
|
||||
if (!CTN.getAsVoidPointer())
|
||||
return QualType();
|
||||
SmallVector<TemplateArgument, 8> Args;
|
||||
if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(),
|
||||
SmallVector<TemplateArgument, 8> As;
|
||||
if (getCommonTemplateArguments(Ctx, As, TX->template_arguments(),
|
||||
TY->template_arguments()))
|
||||
return QualType();
|
||||
return Ctx.getTemplateSpecializationType(CTN, Args,
|
||||
return Ctx.getTemplateSpecializationType(CTN, As,
|
||||
/*CanonicalArgs=*/std::nullopt,
|
||||
Ctx.getQualifiedType(Underlying));
|
||||
}
|
||||
case Type::Typedef: {
|
||||
|
@ -128,7 +128,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
|
||||
if (DesugarArgument) {
|
||||
ShouldAKA = true;
|
||||
QT = Context.getTemplateSpecializationType(
|
||||
TST->getTemplateName(), Args, QT);
|
||||
TST->getTemplateName(), Args, /*CanonicalArgs=*/std::nullopt, QT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1142,9 +1142,9 @@ class TemplateDiff {
|
||||
return nullptr;
|
||||
|
||||
Ty = Context.getTemplateSpecializationType(
|
||||
TemplateName(CTSD->getSpecializedTemplate()),
|
||||
CTSD->getTemplateArgs().asArray(),
|
||||
Ty.getLocalUnqualifiedType().getCanonicalType());
|
||||
TemplateName(CTSD->getSpecializedTemplate()),
|
||||
CTSD->getTemplateArgs().asArray(), /*CanonicalArgs=*/std::nullopt,
|
||||
Ty.getLocalUnqualifiedType().getCanonicalType());
|
||||
|
||||
return Ty->getAs<TemplateSpecializationType>();
|
||||
}
|
||||
|
@ -893,7 +893,8 @@ ASTNodeImporter::import(const TemplateArgument &From) {
|
||||
|
||||
case TemplateArgument::Expression:
|
||||
if (ExpectedExpr ToExpr = import(From.getAsExpr()))
|
||||
return TemplateArgument(*ToExpr, From.getIsDefaulted());
|
||||
return TemplateArgument(*ToExpr, From.isCanonicalExpr(),
|
||||
From.getIsDefaulted());
|
||||
else
|
||||
return ToExpr.takeError();
|
||||
|
||||
@ -1660,18 +1661,12 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
|
||||
ImportTemplateArguments(T->template_arguments(), ToTemplateArgs))
|
||||
return std::move(Err);
|
||||
|
||||
QualType ToCanonType;
|
||||
if (!T->isCanonicalUnqualified()) {
|
||||
QualType FromCanonType
|
||||
= Importer.getFromContext().getCanonicalType(QualType(T, 0));
|
||||
if (ExpectedType TyOrErr = import(FromCanonType))
|
||||
ToCanonType = *TyOrErr;
|
||||
else
|
||||
return TyOrErr.takeError();
|
||||
}
|
||||
return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr,
|
||||
ToTemplateArgs,
|
||||
ToCanonType);
|
||||
ExpectedType ToUnderlyingOrErr =
|
||||
T->isCanonicalUnqualified() ? QualType() : import(T->desugar());
|
||||
if (!ToUnderlyingOrErr)
|
||||
return ToUnderlyingOrErr.takeError();
|
||||
return Importer.getToContext().getTemplateSpecializationType(
|
||||
*ToTemplateOrErr, ToTemplateArgs, std::nullopt, *ToUnderlyingOrErr);
|
||||
}
|
||||
|
||||
ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) {
|
||||
@ -6018,6 +6013,12 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
|
||||
|
||||
ExpectedDecl
|
||||
ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
|
||||
bool IsCanonical = false;
|
||||
if (auto *CanonD = Importer.getFromContext()
|
||||
.findCanonicalTemplateTemplateParmDeclInternal(D);
|
||||
CanonD == D)
|
||||
IsCanonical = true;
|
||||
|
||||
// Import the name of this declaration.
|
||||
auto NameOrErr = import(D->getDeclName());
|
||||
if (!NameOrErr)
|
||||
@ -6045,6 +6046,10 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
|
||||
if (Error Err = importTemplateParameterDefaultArgument(D, ToD))
|
||||
return Err;
|
||||
|
||||
if (IsCanonical)
|
||||
return Importer.getToContext()
|
||||
.insertCanonicalTemplateTemplateParmDeclInternal(ToD);
|
||||
|
||||
return ToD;
|
||||
}
|
||||
|
||||
|
@ -580,7 +580,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
const DependentTemplateStorage &S1,
|
||||
const DependentTemplateStorage &S2) {
|
||||
if (!IsStructurallyEquivalent(Context, S1.getQualifier(), S2.getQualifier()))
|
||||
if (NestedNameSpecifier *NNS1 = S1.getQualifier(), *NNS2 = S2.getQualifier();
|
||||
!NNS1 != !NNS2 ||
|
||||
(NNS1 && !IsStructurallyEquivalent(Context, NNS1, NNS2)))
|
||||
return false;
|
||||
|
||||
IdentifierOrOverloadedOperator IO1 = S1.getName(), IO2 = S2.getName();
|
||||
|
@ -671,8 +671,11 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
|
||||
ASTContext &Context = getASTContext();
|
||||
TemplateName Name = Context.getQualifiedTemplateName(
|
||||
/*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this));
|
||||
CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType(
|
||||
Name, getTemplateParameters()->getInjectedTemplateArgs(Context));
|
||||
auto TemplateArgs = getTemplateParameters()->getInjectedTemplateArgs(Context);
|
||||
CommonPtr->InjectedClassNameType =
|
||||
Context.getTemplateSpecializationType(Name,
|
||||
/*SpecifiedArgs=*/TemplateArgs,
|
||||
/*CanonicalArgs=*/std::nullopt);
|
||||
return CommonPtr->InjectedClassNameType;
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
|
||||
if (MightHaveChanged) {
|
||||
QualType QT = Ctx.getTemplateSpecializationType(
|
||||
TST->getTemplateName(), FQArgs,
|
||||
TST->getCanonicalTypeInternal());
|
||||
/*CanonicalArgs=*/std::nullopt, TST->desugar());
|
||||
// getTemplateSpecializationType returns a fully qualified
|
||||
// version of the specialization itself, so no need to qualify
|
||||
// it.
|
||||
@ -172,6 +172,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
|
||||
TemplateName TN(TSTDecl->getSpecializedTemplate());
|
||||
QualType QT = Ctx.getTemplateSpecializationType(
|
||||
TN, FQArgs,
|
||||
/*CanonicalArgs=*/std::nullopt,
|
||||
TSTRecord->getCanonicalTypeInternal());
|
||||
// getTemplateSpecializationType returns a fully qualified
|
||||
// version of the specialization itself, so no need to qualify
|
||||
|
@ -414,9 +414,16 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
|
||||
getAsStructuralValue().Profile(ID);
|
||||
break;
|
||||
|
||||
case Expression:
|
||||
getAsExpr()->Profile(ID, Context, true);
|
||||
case Expression: {
|
||||
const Expr *E = getAsExpr();
|
||||
bool IsCanonical = isCanonicalExpr();
|
||||
ID.AddBoolean(IsCanonical);
|
||||
if (IsCanonical)
|
||||
E->Profile(ID, Context, true);
|
||||
else
|
||||
ID.AddPointer(E);
|
||||
break;
|
||||
}
|
||||
|
||||
case Pack:
|
||||
ID.AddInteger(Args.NumArgs);
|
||||
@ -431,9 +438,11 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
|
||||
switch (getKind()) {
|
||||
case Null:
|
||||
case Type:
|
||||
case Expression:
|
||||
case NullPtr:
|
||||
return TypeOrValue.V == Other.TypeOrValue.V;
|
||||
case Expression:
|
||||
return TypeOrValue.V == Other.TypeOrValue.V &&
|
||||
TypeOrValue.IsCanonicalExpr == Other.TypeOrValue.IsCanonicalExpr;
|
||||
|
||||
case Template:
|
||||
case TemplateExpansion:
|
||||
@ -478,7 +487,8 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
|
||||
return getAsType()->castAs<PackExpansionType>()->getPattern();
|
||||
|
||||
case Expression:
|
||||
return TemplateArgument(cast<PackExpansionExpr>(getAsExpr())->getPattern());
|
||||
return TemplateArgument(cast<PackExpansionExpr>(getAsExpr())->getPattern(),
|
||||
isCanonicalExpr());
|
||||
|
||||
case TemplateExpansion:
|
||||
return TemplateArgument(getAsTemplateOrTemplatePattern());
|
||||
@ -655,6 +665,7 @@ static const T &DiagTemplateArg(const T &DB, const TemplateArgument &Arg) {
|
||||
return DB << Arg.getAsTemplateOrTemplatePattern() << "...";
|
||||
|
||||
case TemplateArgument::Expression:
|
||||
// FIXME: Support printing expressions as canonical
|
||||
return DB << Arg.getAsExpr();
|
||||
|
||||
case TemplateArgument::Pack: {
|
||||
|
@ -4055,8 +4055,8 @@ QualType DecltypeType::desugar() const {
|
||||
return QualType(this, 0);
|
||||
}
|
||||
|
||||
DependentDecltypeType::DependentDecltypeType(Expr *E, QualType UnderlyingType)
|
||||
: DecltypeType(E, UnderlyingType) {}
|
||||
DependentDecltypeType::DependentDecltypeType(Expr *E)
|
||||
: DecltypeType(E, QualType()) {}
|
||||
|
||||
void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
const ASTContext &Context, Expr *E) {
|
||||
@ -4127,11 +4127,6 @@ UnaryTransformType::UnaryTransformType(QualType BaseType,
|
||||
: Type(UnaryTransform, CanonicalType, BaseType->getDependence()),
|
||||
BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {}
|
||||
|
||||
DependentUnaryTransformType::DependentUnaryTransformType(const ASTContext &C,
|
||||
QualType BaseType,
|
||||
UTTKind UKind)
|
||||
: UnaryTransformType(BaseType, C.DependentTy, UKind, QualType()) {}
|
||||
|
||||
TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
|
||||
: Type(TC, can,
|
||||
D->isDependentType() ? TypeDependence::DependentInstantiation
|
||||
@ -4388,17 +4383,19 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
|
||||
}
|
||||
|
||||
TemplateSpecializationType::TemplateSpecializationType(
|
||||
TemplateName T, ArrayRef<TemplateArgument> Args, QualType Canon,
|
||||
QualType AliasedType)
|
||||
: Type(TemplateSpecialization, Canon.isNull() ? QualType(this, 0) : Canon,
|
||||
(Canon.isNull()
|
||||
TemplateName T, bool IsAlias, ArrayRef<TemplateArgument> Args,
|
||||
QualType Underlying)
|
||||
: Type(TemplateSpecialization,
|
||||
Underlying.isNull() ? QualType(this, 0)
|
||||
: Underlying.getCanonicalType(),
|
||||
(Underlying.isNull()
|
||||
? TypeDependence::DependentInstantiation
|
||||
: toSemanticDependence(Canon->getDependence())) |
|
||||
: toSemanticDependence(Underlying->getDependence())) |
|
||||
(toTypeDependence(T.getDependence()) &
|
||||
TypeDependence::UnexpandedPack)),
|
||||
Template(T) {
|
||||
TemplateSpecializationTypeBits.NumArgs = Args.size();
|
||||
TemplateSpecializationTypeBits.TypeAlias = !AliasedType.isNull();
|
||||
TemplateSpecializationTypeBits.TypeAlias = IsAlias;
|
||||
|
||||
assert(!T.getAsDependentTemplateName() &&
|
||||
"Use DependentTemplateSpecializationType for dependent template-name");
|
||||
@ -4410,7 +4407,8 @@ TemplateSpecializationType::TemplateSpecializationType(
|
||||
T.getKind() == TemplateName::DeducedTemplate) &&
|
||||
"Unexpected template name for TemplateSpecializationType");
|
||||
|
||||
auto *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1);
|
||||
auto *TemplateArgs =
|
||||
const_cast<TemplateArgument *>(template_arguments().data());
|
||||
for (const TemplateArgument &Arg : Args) {
|
||||
// Update instantiation-dependent, variably-modified, and error bits.
|
||||
// If the canonical type exists and is non-dependent, the template
|
||||
@ -4428,11 +4426,10 @@ TemplateSpecializationType::TemplateSpecializationType(
|
||||
new (TemplateArgs++) TemplateArgument(Arg);
|
||||
}
|
||||
|
||||
// Store the aliased type if this is a type alias template specialization.
|
||||
if (isTypeAlias()) {
|
||||
auto *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
|
||||
*reinterpret_cast<QualType *>(Begin + Args.size()) = AliasedType;
|
||||
}
|
||||
// Store the aliased type after the template arguments, if this is a type
|
||||
// alias template specialization.
|
||||
if (IsAlias)
|
||||
*reinterpret_cast<QualType *>(TemplateArgs) = Underlying;
|
||||
}
|
||||
|
||||
QualType TemplateSpecializationType::getAliasedType() const {
|
||||
@ -4442,17 +4439,19 @@ QualType TemplateSpecializationType::getAliasedType() const {
|
||||
|
||||
void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
const ASTContext &Ctx) {
|
||||
Profile(ID, Template, template_arguments(), Ctx);
|
||||
if (isTypeAlias())
|
||||
getAliasedType().Profile(ID);
|
||||
Profile(ID, Template, template_arguments(),
|
||||
isSugared() ? desugar() : QualType(), Ctx);
|
||||
}
|
||||
|
||||
void
|
||||
TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
TemplateName T,
|
||||
ArrayRef<TemplateArgument> Args,
|
||||
const ASTContext &Context) {
|
||||
void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
TemplateName T,
|
||||
ArrayRef<TemplateArgument> Args,
|
||||
QualType Underlying,
|
||||
const ASTContext &Context) {
|
||||
T.Profile(ID);
|
||||
Underlying.Profile(ID);
|
||||
|
||||
ID.AddInteger(Args.size());
|
||||
for (const TemplateArgument &Arg : Args)
|
||||
Arg.Profile(ID, Context);
|
||||
}
|
||||
@ -5264,9 +5263,9 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
|
||||
}
|
||||
|
||||
void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
|
||||
QualType Deduced, AutoTypeKeyword Keyword,
|
||||
bool IsDependent, ConceptDecl *CD,
|
||||
ArrayRef<TemplateArgument> Arguments) {
|
||||
QualType Deduced, AutoTypeKeyword Keyword,
|
||||
bool IsDependent, ConceptDecl *CD,
|
||||
ArrayRef<TemplateArgument> Arguments) {
|
||||
ID.AddPointer(Deduced.getAsOpaquePtr());
|
||||
ID.AddInteger((unsigned)Keyword);
|
||||
ID.AddBoolean(IsDependent);
|
||||
|
@ -69,17 +69,14 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
|
||||
|
||||
// Look through type alias templates, per C++0x [temp.dep.type]p1.
|
||||
NNSType = Context.getCanonicalType(NNSType);
|
||||
if (const TemplateSpecializationType *SpecType
|
||||
= NNSType->getAs<TemplateSpecializationType>()) {
|
||||
if (const auto *SpecType =
|
||||
dyn_cast<TemplateSpecializationType>(NNSType)) {
|
||||
// We are entering the context of the nested name specifier, so try to
|
||||
// match the nested name specifier to either a primary class template
|
||||
// or a class template partial specialization.
|
||||
if (ClassTemplateDecl *ClassTemplate
|
||||
= dyn_cast_or_null<ClassTemplateDecl>(
|
||||
SpecType->getTemplateName().getAsTemplateDecl())) {
|
||||
QualType ContextType =
|
||||
Context.getCanonicalType(QualType(SpecType, 0));
|
||||
|
||||
if (ClassTemplateDecl *ClassTemplate =
|
||||
dyn_cast_or_null<ClassTemplateDecl>(
|
||||
SpecType->getTemplateName().getAsTemplateDecl())) {
|
||||
// FIXME: The fallback on the search of partial
|
||||
// specialization using ContextType should be eventually removed since
|
||||
// it doesn't handle the case of constrained template parameters
|
||||
@ -100,7 +97,8 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
|
||||
SpecType->template_arguments(), *L, Pos);
|
||||
}
|
||||
} else {
|
||||
PartialSpec = ClassTemplate->findPartialSpecialization(ContextType);
|
||||
PartialSpec =
|
||||
ClassTemplate->findPartialSpecialization(QualType(SpecType, 0));
|
||||
}
|
||||
|
||||
if (PartialSpec) {
|
||||
@ -122,7 +120,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
|
||||
// into that class template definition.
|
||||
QualType Injected =
|
||||
ClassTemplate->getInjectedClassNameSpecialization();
|
||||
if (Context.hasSameType(Injected, ContextType))
|
||||
if (Context.hasSameType(Injected, QualType(SpecType, 0)))
|
||||
return ClassTemplate->getTemplatedDecl();
|
||||
}
|
||||
} else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) {
|
||||
|
@ -2183,7 +2183,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
|
||||
|
||||
case LOLR_Template: {
|
||||
TemplateArgumentListInfo ExplicitArgs;
|
||||
TemplateArgument Arg(Lit);
|
||||
TemplateArgument Arg(Lit, /*IsCanonical=*/false);
|
||||
TemplateArgumentLocInfo ArgInfo(Lit);
|
||||
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
|
||||
return BuildLiteralOperatorCall(R, OpNameInfo, {}, StringTokLocs.back(),
|
||||
@ -21108,8 +21108,22 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
|
||||
Diag(Temp->getLocation(), diag::note_referenced_type_template)
|
||||
<< IsTypeAliasTemplateDecl;
|
||||
|
||||
QualType TST =
|
||||
Context.getTemplateSpecializationType(TN, ULE->template_arguments());
|
||||
TemplateArgumentListInfo TAL(ULE->getLAngleLoc(), ULE->getRAngleLoc());
|
||||
bool HasAnyDependentTA = false;
|
||||
for (const TemplateArgumentLoc &Arg : ULE->template_arguments()) {
|
||||
HasAnyDependentTA |= Arg.getArgument().isDependent();
|
||||
TAL.addArgument(Arg);
|
||||
}
|
||||
|
||||
QualType TST;
|
||||
{
|
||||
SFINAETrap Trap(*this);
|
||||
TST = CheckTemplateIdType(TN, NameInfo.getBeginLoc(), TAL);
|
||||
}
|
||||
if (TST.isNull())
|
||||
TST = Context.getTemplateSpecializationType(
|
||||
TN, ULE->template_arguments(), /*CanonicalArgs=*/std::nullopt,
|
||||
HasAnyDependentTA ? Context.DependentTy : Context.IntTy);
|
||||
QualType ET =
|
||||
Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS, TST);
|
||||
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {},
|
||||
|
@ -3713,7 +3713,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
|
||||
if (StringLit) {
|
||||
SFINAETrap Trap(*this);
|
||||
CheckTemplateArgumentInfo CTAI;
|
||||
TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
|
||||
TemplateArgumentLoc Arg(
|
||||
TemplateArgument(StringLit, /*IsCanonical=*/false), StringLit);
|
||||
if (CheckTemplateArgument(
|
||||
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
|
||||
/*ArgumentPackIndex=*/0, CTAI, CTAK_Specified) ||
|
||||
|
@ -909,7 +909,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
|
||||
|
||||
case ParsedTemplateArgument::NonType: {
|
||||
Expr *E = static_cast<Expr *>(Arg.getAsExpr());
|
||||
return TemplateArgumentLoc(TemplateArgument(E), E);
|
||||
return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E);
|
||||
}
|
||||
|
||||
case ParsedTemplateArgument::Template: {
|
||||
@ -1576,8 +1576,9 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
|
||||
return Param;
|
||||
|
||||
Param->setDefaultArgument(
|
||||
Context, getTrivialTemplateArgumentLoc(TemplateArgument(Default),
|
||||
QualType(), SourceLocation()));
|
||||
Context, getTrivialTemplateArgumentLoc(
|
||||
TemplateArgument(Default, /*IsCanonical=*/false),
|
||||
QualType(), SourceLocation()));
|
||||
}
|
||||
|
||||
return Param;
|
||||
@ -3250,8 +3251,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
|
||||
|
||||
TemplateArgument NumArgsArg = Converted[2];
|
||||
if (NumArgsArg.isDependent())
|
||||
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
|
||||
Converted);
|
||||
return QualType();
|
||||
|
||||
TemplateArgumentListInfo SyntheticTemplateArgs;
|
||||
// The type argument, wrapped in substitution sugar, gets reused as the
|
||||
@ -3288,12 +3288,11 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
|
||||
// __type_pack_element<Index, T_1, ..., T_N>
|
||||
// are treated like T_Index.
|
||||
assert(Converted.size() == 2 &&
|
||||
"__type_pack_element should be given an index and a parameter pack");
|
||||
"__type_pack_element should be given an index and a parameter pack");
|
||||
|
||||
TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
|
||||
if (IndexArg.isDependent() || Ts.isDependent())
|
||||
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
|
||||
Converted);
|
||||
return QualType();
|
||||
|
||||
llvm::APSInt Index = IndexArg.getAsIntegral();
|
||||
assert(Index >= 0 && "the index used with __type_pack_element should be of "
|
||||
@ -3313,12 +3312,9 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
|
||||
case BTK__builtin_common_type: {
|
||||
assert(Converted.size() == 4);
|
||||
if (llvm::any_of(Converted, [](auto &C) { return C.isDependent(); }))
|
||||
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
|
||||
Converted);
|
||||
return QualType();
|
||||
|
||||
TemplateName BaseTemplate = Converted[0].getAsTemplate();
|
||||
TemplateName HasTypeMember = Converted[1].getAsTemplate();
|
||||
QualType HasNoTypeMember = Converted[2].getAsType();
|
||||
ArrayRef<TemplateArgument> Ts = Converted[3].getPackAsArray();
|
||||
if (auto CT = builtinCommonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts);
|
||||
!CT.isNull()) {
|
||||
@ -3326,9 +3322,10 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
|
||||
TAs.addArgument(TemplateArgumentLoc(
|
||||
TemplateArgument(CT), SemaRef.Context.getTrivialTypeSourceInfo(
|
||||
CT, TemplateArgs[1].getLocation())));
|
||||
|
||||
TemplateName HasTypeMember = Converted[1].getAsTemplate();
|
||||
return SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs);
|
||||
}
|
||||
QualType HasNoTypeMember = Converted[2].getAsType();
|
||||
return HasNoTypeMember;
|
||||
}
|
||||
}
|
||||
@ -3492,20 +3489,19 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
||||
resolveAssumedTemplateNameAsType(/*Scope=*/nullptr, Name, TemplateLoc))
|
||||
return QualType();
|
||||
|
||||
auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
|
||||
|
||||
if (!Template || isa<FunctionTemplateDecl>(Template) ||
|
||||
isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
|
||||
// We might have a substituted template template parameter pack. If so,
|
||||
// build a template specialization type for it.
|
||||
if (Name.getAsSubstTemplateTemplateParmPack())
|
||||
return Context.getTemplateSpecializationType(Name,
|
||||
TemplateArgs.arguments());
|
||||
|
||||
Diag(TemplateLoc, diag::err_template_id_not_a_type)
|
||||
<< Name;
|
||||
NoteAllFoundTemplates(Name);
|
||||
return QualType();
|
||||
TemplateDecl *Template;
|
||||
DefaultArguments DefaultArgs;
|
||||
if (const SubstTemplateTemplateParmPackStorage *S =
|
||||
Name.getAsSubstTemplateTemplateParmPack()) {
|
||||
Template = S->getParameterPack();
|
||||
} else {
|
||||
std::tie(Template, DefaultArgs) = Name.getTemplateDeclAndDefaultArgs();
|
||||
if (!Template || isa<FunctionTemplateDecl>(Template) ||
|
||||
isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
|
||||
Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name;
|
||||
NoteAllFoundTemplates(Name);
|
||||
return QualType();
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the template argument list is well-formed for this
|
||||
@ -3519,8 +3515,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
||||
|
||||
QualType CanonType;
|
||||
|
||||
if (TypeAliasTemplateDecl *AliasTemplate =
|
||||
dyn_cast<TypeAliasTemplateDecl>(Template)) {
|
||||
if (isa<TemplateTemplateParmDecl>(Template)) {
|
||||
// We might have a substituted template template parameter pack. If so,
|
||||
// build a template specialization type for it.
|
||||
} else if (TypeAliasTemplateDecl *AliasTemplate =
|
||||
dyn_cast<TypeAliasTemplateDecl>(Template)) {
|
||||
|
||||
// Find the canonical type for this type alias template specialization.
|
||||
TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
|
||||
@ -3602,7 +3601,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
||||
//
|
||||
// template<typename T, typename U = T> struct A;
|
||||
CanonType = Context.getCanonicalTemplateSpecializationType(
|
||||
Name, CTAI.CanonicalConverted);
|
||||
Context.getCanonicalTemplateName(Name, /*IgnoreDeduced=*/true),
|
||||
CTAI.CanonicalConverted);
|
||||
assert(CanonType->isCanonicalUnqualified());
|
||||
|
||||
// This might work out to be a current instantiation, in which
|
||||
// case the canonical type needs to be the InjectedClassNameType.
|
||||
@ -3688,8 +3689,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
||||
// Build the fully-sugared type for this class template
|
||||
// specialization, which refers back to the class template
|
||||
// specialization we created or found.
|
||||
return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(),
|
||||
CanonType);
|
||||
return Context.getTemplateSpecializationType(
|
||||
Name, TemplateArgs.arguments(), CTAI.CanonicalConverted, CanonType);
|
||||
}
|
||||
|
||||
void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName,
|
||||
@ -5286,7 +5287,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
|
||||
// If the resulting expression is new, then use it in place of the
|
||||
// old expression in the template argument.
|
||||
if (R != E) {
|
||||
TemplateArgument TA(R);
|
||||
TemplateArgument TA(R, /*IsCanonical=*/false);
|
||||
ArgLoc = TemplateArgumentLoc(TA, R);
|
||||
}
|
||||
break;
|
||||
@ -6476,7 +6477,7 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
|
||||
// Stop checking the precise nature of the argument if it is value dependent,
|
||||
// it should be checked when instantiated.
|
||||
if (Arg->isValueDependent()) {
|
||||
SugaredConverted = TemplateArgument(ArgIn);
|
||||
SugaredConverted = TemplateArgument(ArgIn, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
S.Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
return false;
|
||||
@ -6667,7 +6668,7 @@ CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
|
||||
if (VD->getType()->isMemberPointerType()) {
|
||||
if (isa<NonTypeTemplateParmDecl>(VD)) {
|
||||
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
S.Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
} else {
|
||||
@ -6733,7 +6734,7 @@ CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
|
||||
// Okay: this is the address of a non-static member, and therefore
|
||||
// a member pointer constant.
|
||||
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
S.Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
} else {
|
||||
@ -6784,7 +6785,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
if (DeductionArg->isTypeDependent()) {
|
||||
auto *AT = dyn_cast<AutoType>(DeducedT);
|
||||
if (AT && AT->isDecltypeAuto()) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted = TemplateArgument(
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted));
|
||||
return Arg;
|
||||
@ -6858,7 +6859,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
if (E.isInvalid())
|
||||
return ExprError();
|
||||
setDeductionArg(E.get());
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted = TemplateArgument(
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted));
|
||||
return Arg;
|
||||
@ -6889,7 +6890,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
// normal template rules apply: we accept the template if it would be valid
|
||||
// for any number of expansions (i.e. none).
|
||||
if (ArgPE && !StrictCheck) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted = TemplateArgument(
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted));
|
||||
return Arg;
|
||||
@ -6915,7 +6916,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
return Arg;
|
||||
}
|
||||
if (isa<NonTypeTemplateParmDecl>(ND)) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
return Arg;
|
||||
@ -6972,7 +6973,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
// permitted (and expected) to be unable to determine a value.
|
||||
if (ArgResult.get()->isValueDependent()) {
|
||||
setDeductionArg(ArgResult.get());
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
return Arg;
|
||||
@ -7010,7 +7011,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
Value.getLValuePath()[0].getAsArrayIndex() == 0 &&
|
||||
!Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) {
|
||||
if (ArgPE) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
} else {
|
||||
@ -7041,7 +7042,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff);
|
||||
|
||||
if (ArgPE) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
} else {
|
||||
@ -7086,7 +7087,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
|
||||
// We can't check arbitrary value-dependent arguments.
|
||||
if (DeductionArg->isValueDependent()) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
return Arg;
|
||||
@ -7103,7 +7104,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
: Context.getTypeSize(IntegerType));
|
||||
|
||||
if (ArgPE) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
} else {
|
||||
@ -7187,7 +7188,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
if (DeductionArg->isValueDependent()) {
|
||||
// The argument is value-dependent. Create a new
|
||||
// TemplateArgument with the converted expression.
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
return Arg;
|
||||
@ -7243,7 +7244,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
}
|
||||
|
||||
if (ArgPE) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
} else {
|
||||
@ -7366,7 +7367,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
// Deal with parameters of type std::nullptr_t.
|
||||
if (ParamType->isNullPtrType()) {
|
||||
if (DeductionArg->isTypeDependent() || DeductionArg->isValueDependent()) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
return Arg;
|
||||
@ -7386,7 +7387,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
case NPV_NullPointer:
|
||||
Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
|
||||
if (ArgPE) {
|
||||
SugaredConverted = TemplateArgument(Arg);
|
||||
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
|
||||
CanonicalConverted =
|
||||
Context.getCanonicalTemplateArgument(SugaredConverted);
|
||||
} else {
|
||||
@ -8523,17 +8524,34 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
|
||||
isPartialSpecialization))
|
||||
return true;
|
||||
|
||||
// The canonical type
|
||||
QualType CanonType;
|
||||
if (isPartialSpecialization) {
|
||||
// Build the canonical type that describes the converted template
|
||||
// arguments of the class template partial specialization.
|
||||
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
|
||||
CanonType = Context.getTemplateSpecializationType(CanonTemplate,
|
||||
CTAI.CanonicalConverted);
|
||||
if (!isPartialSpecialization) {
|
||||
// Create a new class template specialization declaration node for
|
||||
// this explicit specialization or friend declaration.
|
||||
Specialization = ClassTemplateSpecializationDecl::Create(
|
||||
Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
|
||||
ClassTemplate, CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl);
|
||||
Specialization->setTemplateArgsAsWritten(TemplateArgs);
|
||||
SetNestedNameSpecifier(*this, Specialization, SS);
|
||||
if (TemplateParameterLists.size() > 0) {
|
||||
Specialization->setTemplateParameterListsInfo(Context,
|
||||
TemplateParameterLists);
|
||||
}
|
||||
|
||||
if (Context.hasSameType(CanonType,
|
||||
ClassTemplate->getInjectedClassNameSpecialization()) &&
|
||||
if (!PrevDecl)
|
||||
ClassTemplate->AddSpecialization(Specialization, InsertPos);
|
||||
|
||||
if (!CurContext->isDependentContext())
|
||||
CanonType = Context.getTypeDeclType(Specialization);
|
||||
}
|
||||
|
||||
TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo(
|
||||
Name, TemplateNameLoc, TemplateArgs, CTAI.CanonicalConverted, CanonType);
|
||||
|
||||
if (isPartialSpecialization) {
|
||||
if (Context.hasSameType(
|
||||
WrittenTy->getType(),
|
||||
ClassTemplate->getInjectedClassNameSpecialization()) &&
|
||||
(!Context.getLangOpts().CPlusPlus20 ||
|
||||
!TemplateParams->hasAssociatedConstraints())) {
|
||||
// C++ [temp.class.spec]p9b3:
|
||||
@ -8560,7 +8578,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
|
||||
ClassTemplatePartialSpecializationDecl *Partial =
|
||||
ClassTemplatePartialSpecializationDecl::Create(
|
||||
Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
|
||||
ClassTemplate, CTAI.CanonicalConverted, CanonType, PrevPartial);
|
||||
ClassTemplate, CTAI.CanonicalConverted, WrittenTy->getType(),
|
||||
PrevPartial);
|
||||
Partial->setTemplateArgsAsWritten(TemplateArgs);
|
||||
SetNestedNameSpecifier(*this, Partial, SS);
|
||||
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
|
||||
@ -8578,29 +8597,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
|
||||
PrevPartial->setMemberSpecialization();
|
||||
|
||||
CheckTemplatePartialSpecialization(Partial);
|
||||
} else {
|
||||
// Create a new class template specialization declaration node for
|
||||
// this explicit specialization or friend declaration.
|
||||
Specialization = ClassTemplateSpecializationDecl::Create(
|
||||
Context, Kind, DC, KWLoc, TemplateNameLoc, ClassTemplate,
|
||||
CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl);
|
||||
Specialization->setTemplateArgsAsWritten(TemplateArgs);
|
||||
SetNestedNameSpecifier(*this, Specialization, SS);
|
||||
if (TemplateParameterLists.size() > 0) {
|
||||
Specialization->setTemplateParameterListsInfo(Context,
|
||||
TemplateParameterLists);
|
||||
}
|
||||
|
||||
if (!PrevDecl)
|
||||
ClassTemplate->AddSpecialization(Specialization, InsertPos);
|
||||
|
||||
if (CurContext->isDependentContext()) {
|
||||
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
|
||||
CanonType = Context.getTemplateSpecializationType(
|
||||
CanonTemplate, CTAI.CanonicalConverted);
|
||||
} else {
|
||||
CanonType = Context.getTypeDeclType(Specialization);
|
||||
}
|
||||
}
|
||||
|
||||
// C++ [temp.expl.spec]p6:
|
||||
@ -8690,8 +8686,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
|
||||
// actually wrote the specialization, rather than formatting the
|
||||
// name based on the "canonical" representation used to store the
|
||||
// template arguments in the specialization.
|
||||
TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo(
|
||||
Name, TemplateNameLoc, TemplateArgs, CanonType);
|
||||
FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
|
||||
TemplateNameLoc,
|
||||
WrittenTy,
|
||||
|
@ -493,8 +493,8 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
|
||||
: CK_NullToPointer)
|
||||
.get();
|
||||
return DeduceNonTypeTemplateArgument(
|
||||
S, TemplateParams, NTTP, TemplateArgument(Value), Value->getType(), Info,
|
||||
PartialOrdering, Deduced, HasDeducedAnyParam);
|
||||
S, TemplateParams, NTTP, TemplateArgument(Value, /*IsCanonical=*/false),
|
||||
Value->getType(), Info, PartialOrdering, Deduced, HasDeducedAnyParam);
|
||||
}
|
||||
|
||||
/// Deduce the value of the given non-type template parameter
|
||||
@ -508,8 +508,8 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
|
||||
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
|
||||
bool *HasDeducedAnyParam) {
|
||||
return DeduceNonTypeTemplateArgument(
|
||||
S, TemplateParams, NTTP, TemplateArgument(Value), Value->getType(), Info,
|
||||
PartialOrdering, Deduced, HasDeducedAnyParam);
|
||||
S, TemplateParams, NTTP, TemplateArgument(Value, /*IsCanonical=*/false),
|
||||
Value->getType(), Info, PartialOrdering, Deduced, HasDeducedAnyParam);
|
||||
}
|
||||
|
||||
/// Deduce the value of the given non-type template parameter
|
||||
@ -615,12 +615,15 @@ static TemplateDeductionResult DeduceTemplateArguments(
|
||||
/// but it may still fail, later, for other reasons.
|
||||
|
||||
static const TemplateSpecializationType *getLastTemplateSpecType(QualType QT) {
|
||||
const TemplateSpecializationType *LastTST = nullptr;
|
||||
for (const Type *T = QT.getTypePtr(); /**/; /**/) {
|
||||
const TemplateSpecializationType *TST =
|
||||
T->getAs<TemplateSpecializationType>();
|
||||
assert(TST && "Expected a TemplateSpecializationType");
|
||||
if (!TST)
|
||||
return LastTST;
|
||||
if (!TST->isSugared())
|
||||
return TST;
|
||||
LastTST = TST;
|
||||
T = TST->desugar().getTypePtr();
|
||||
}
|
||||
}
|
||||
@ -2899,7 +2902,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
|
||||
Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc,
|
||||
TemplateParam)
|
||||
.getAs<Expr>();
|
||||
return TemplateArgumentLoc(TemplateArgument(E), E);
|
||||
return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E);
|
||||
}
|
||||
|
||||
case TemplateArgument::NullPtr: {
|
||||
@ -2914,7 +2917,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
|
||||
case TemplateArgument::Integral:
|
||||
case TemplateArgument::StructuralValue: {
|
||||
Expr *E = BuildExpressionFromNonTypeTemplateArgument(Arg, Loc).get();
|
||||
return TemplateArgumentLoc(TemplateArgument(E), E);
|
||||
return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E);
|
||||
}
|
||||
|
||||
case TemplateArgument::Template:
|
||||
@ -6415,8 +6418,8 @@ Sema::getMoreSpecializedPartialSpecialization(
|
||||
ClassTemplatePartialSpecializationDecl *PS1,
|
||||
ClassTemplatePartialSpecializationDecl *PS2,
|
||||
SourceLocation Loc) {
|
||||
QualType PT1 = PS1->getInjectedSpecializationType();
|
||||
QualType PT2 = PS2->getInjectedSpecializationType();
|
||||
QualType PT1 = PS1->getInjectedSpecializationType().getCanonicalType();
|
||||
QualType PT2 = PS2->getInjectedSpecializationType().getCanonicalType();
|
||||
|
||||
TemplateDeductionInfo Info(Loc);
|
||||
return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info);
|
||||
@ -6425,8 +6428,9 @@ Sema::getMoreSpecializedPartialSpecialization(
|
||||
bool Sema::isMoreSpecializedThanPrimary(
|
||||
ClassTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
|
||||
ClassTemplateDecl *Primary = Spec->getSpecializedTemplate();
|
||||
QualType PrimaryT = Primary->getInjectedClassNameSpecialization();
|
||||
QualType PartialT = Spec->getInjectedSpecializationType();
|
||||
QualType PrimaryT =
|
||||
Primary->getInjectedClassNameSpecialization().getCanonicalType();
|
||||
QualType PartialT = Spec->getInjectedSpecializationType().getCanonicalType();
|
||||
|
||||
ClassTemplatePartialSpecializationDecl *MaybeSpec =
|
||||
getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info);
|
||||
@ -6444,10 +6448,10 @@ Sema::getMoreSpecializedPartialSpecialization(
|
||||
assert(PS1->getSpecializedTemplate() == PS2->getSpecializedTemplate() &&
|
||||
"the partial specializations being compared should specialize"
|
||||
" the same template.");
|
||||
TemplateName Name(PS1->getSpecializedTemplate());
|
||||
QualType PT1 = Context.getTemplateSpecializationType(
|
||||
TemplateName Name(PS1->getSpecializedTemplate()->getCanonicalDecl());
|
||||
QualType PT1 = Context.getCanonicalTemplateSpecializationType(
|
||||
Name, PS1->getTemplateArgs().asArray());
|
||||
QualType PT2 = Context.getTemplateSpecializationType(
|
||||
QualType PT2 = Context.getCanonicalTemplateSpecializationType(
|
||||
Name, PS2->getTemplateArgs().asArray());
|
||||
|
||||
TemplateDeductionInfo Info(Loc);
|
||||
@ -6457,10 +6461,15 @@ Sema::getMoreSpecializedPartialSpecialization(
|
||||
bool Sema::isMoreSpecializedThanPrimary(
|
||||
VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
|
||||
VarTemplateDecl *Primary = Spec->getSpecializedTemplate();
|
||||
TemplateName Name(Primary);
|
||||
QualType PrimaryT = Context.getTemplateSpecializationType(
|
||||
Name, Primary->getInjectedTemplateArgs(Context));
|
||||
QualType PartialT = Context.getTemplateSpecializationType(
|
||||
TemplateName Name(Primary->getCanonicalDecl());
|
||||
|
||||
SmallVector<TemplateArgument, 8> PrimaryCanonArgs(
|
||||
Primary->getInjectedTemplateArgs(Context));
|
||||
Context.canonicalizeTemplateArguments(PrimaryCanonArgs);
|
||||
|
||||
QualType PrimaryT =
|
||||
Context.getCanonicalTemplateSpecializationType(Name, PrimaryCanonArgs);
|
||||
QualType PartialT = Context.getCanonicalTemplateSpecializationType(
|
||||
Name, Spec->getTemplateArgs().asArray());
|
||||
|
||||
VarTemplatePartialSpecializationDecl *MaybeSpec =
|
||||
|
@ -4791,17 +4791,18 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
|
||||
ClassTemplate->findPartialSpecialization(CTAI.CanonicalConverted,
|
||||
InstParams, InsertPos);
|
||||
|
||||
// Build the canonical type that describes the converted template
|
||||
// arguments of the class template partial specialization.
|
||||
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
|
||||
TemplateName(ClassTemplate), CTAI.CanonicalConverted);
|
||||
// Build the type that describes the converted template arguments of the class
|
||||
// template partial specialization.
|
||||
TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo(
|
||||
TemplateName(ClassTemplate), TemplArgInfo->getLAngleLoc(),
|
||||
InstTemplateArgs, CTAI.CanonicalConverted);
|
||||
|
||||
// Create the class template partial specialization declaration.
|
||||
ClassTemplatePartialSpecializationDecl *InstPartialSpec =
|
||||
ClassTemplatePartialSpecializationDecl::Create(
|
||||
SemaRef.Context, PartialSpec->getTagKind(), Owner,
|
||||
PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
|
||||
ClassTemplate, CTAI.CanonicalConverted, CanonType,
|
||||
ClassTemplate, CTAI.CanonicalConverted, WrittenTy->getType(),
|
||||
/*PrevDecl=*/nullptr);
|
||||
|
||||
InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
|
||||
|
@ -1286,7 +1286,8 @@ TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern(
|
||||
Expr *Pattern = Expansion->getPattern();
|
||||
Ellipsis = Expansion->getEllipsisLoc();
|
||||
NumExpansions = Expansion->getNumExpansions();
|
||||
return TemplateArgumentLoc(TemplateArgument(Pattern), Pattern);
|
||||
return TemplateArgumentLoc(
|
||||
TemplateArgument(Pattern, Argument.isCanonicalExpr()), Pattern);
|
||||
}
|
||||
|
||||
case TemplateArgument::TemplateExpansion:
|
||||
|
@ -3981,7 +3981,9 @@ public:
|
||||
if (Result.isInvalid())
|
||||
return TemplateArgumentLoc();
|
||||
|
||||
return TemplateArgumentLoc(TemplateArgument(Result.get()), Result.get());
|
||||
return TemplateArgumentLoc(TemplateArgument(Result.get(),
|
||||
/*IsCanonical=*/false),
|
||||
Result.get());
|
||||
}
|
||||
|
||||
case TemplateArgument::Template:
|
||||
@ -4941,7 +4943,8 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
|
||||
E = SemaRef.ActOnConstantExpression(E);
|
||||
if (E.isInvalid())
|
||||
return true;
|
||||
Output = TemplateArgumentLoc(TemplateArgument(E.get()), E.get());
|
||||
Output = TemplateArgumentLoc(
|
||||
TemplateArgument(E.get(), /*IsCanonical=*/false), E.get());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -16131,8 +16134,10 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
|
||||
E->getPackLoc());
|
||||
if (DRE.isInvalid())
|
||||
return ExprError();
|
||||
ArgStorage = TemplateArgument(new (getSema().Context) PackExpansionExpr(
|
||||
DRE.get(), E->getPackLoc(), std::nullopt));
|
||||
ArgStorage = TemplateArgument(
|
||||
new (getSema().Context)
|
||||
PackExpansionExpr(DRE.get(), E->getPackLoc(), std::nullopt),
|
||||
/*IsCanonical=*/false);
|
||||
}
|
||||
PackArgs = ArgStorage;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ namespace CurrentInstantiation {
|
||||
struct A0<T>::B5<U>::C3 : A0, B5 { };
|
||||
|
||||
template<typename T>
|
||||
struct A0<T*> { // expected-note 2{{definition of 'A0<type-parameter-0-0 *>' is not complete until the closing '}'}}
|
||||
struct A0<T*> { // expected-note 2{{definition of 'A0<T *>' is not complete until the closing '}'}}
|
||||
struct B0 : A0 { }; // expected-error {{base class has incomplete type}}
|
||||
|
||||
template<typename U>
|
||||
|
@ -38,7 +38,7 @@ A<short>::C::B<int*> absip;
|
||||
template<typename T, typename U>
|
||||
struct Outer {
|
||||
template<typename X, typename Y> struct Inner;
|
||||
template<typename Y> struct Inner<T, Y> {}; // expected-note{{previous declaration of class template partial specialization 'Inner<int, type-parameter-0-0>' is here}}
|
||||
template<typename Y> struct Inner<T, Y> {}; // expected-note{{previous declaration of class template partial specialization 'Inner<int, Y>' is here}}
|
||||
template<typename Y> struct Inner<U, Y> {}; // expected-error{{cannot be redeclared}}
|
||||
};
|
||||
|
||||
@ -80,7 +80,7 @@ namespace print_dependent_TemplateSpecializationType {
|
||||
template <class T, class U> struct Foo {
|
||||
template <unsigned long, class X, class Y> struct Bar;
|
||||
template <class Y> struct Bar<0, T, Y> {};
|
||||
// expected-note-re@-1 {{previous declaration {{.*}} 'Bar<0, int, type-parameter-0-0>' is here}}
|
||||
// expected-note-re@-1 {{previous declaration {{.*}} 'Bar<0, int, Y>' is here}}
|
||||
template <class Y> struct Bar<0, U, Y> {};
|
||||
// expected-error@-1 {{partial specialization 'Bar<0, int, Y>' cannot be redeclared}}
|
||||
};
|
||||
|
@ -10,6 +10,6 @@ template <typename T>
|
||||
class boo<T, true>;
|
||||
|
||||
template<typename T>
|
||||
void boo<T, true>::foo(){} // expected-error{{out-of-line definition of 'foo' from class 'boo<type-parameter-0-0, true>' without definition}}
|
||||
void boo<T, true>::foo(){} // expected-error{{out-of-line definition of 'foo' from class 'boo<T, true>' without definition}}
|
||||
|
||||
}
|
||||
|
@ -73,76 +73,47 @@ using test2 = B<int, 1>;
|
||||
|
||||
template <template <class T, T...> class S, class T, int N> struct C {
|
||||
using test3 = __make_integer_seq<S, T, N>;
|
||||
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test3 '__make_integer_seq<S, T, N>':'__make_integer_seq<template-parameter-0-0, type-parameter-0-1, N>'
|
||||
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test3 '__make_integer_seq<S, T, N>'
|
||||
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' sugar dependent
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' sugar dependent alias
|
||||
// CHECK-NEXT: |-name: '__make_integer_seq' qualified
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' dependent
|
||||
// CHECK-NEXT: |-name: '__make_integer_seq'
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
|
||||
// CHECK-NEXT: |-TemplateArgument template 'S'
|
||||
// CHECK-NEXT: | | `-TemplateTemplateParmDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:11, col:42> col:42 depth 0 index 0 S
|
||||
// CHECK-NEXT: |-TemplateArgument type 'T'
|
||||
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1
|
||||
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T'
|
||||
// CHECK-NEXT: |-TemplateArgument expr 'N'
|
||||
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
|
||||
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<template-parameter-0-0, type-parameter-0-1, N>' dependent
|
||||
// CHECK-NEXT: |-name: '__make_integer_seq'
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
|
||||
// CHECK-NEXT: |-TemplateArgument template 'template-parameter-0-0'
|
||||
// CHECK-NEXT: | `-TemplateTemplateParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> depth 0 index 0
|
||||
// CHECK-NEXT: |-TemplateArgument type 'type-parameter-0-1'
|
||||
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent depth 0 index 1
|
||||
// CHECK-NEXT: `-TemplateArgument expr 'N'
|
||||
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'T' <Dependent>
|
||||
// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
|
||||
// CHECK-NEXT: `-TemplateArgument expr 'N'
|
||||
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
|
||||
// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
|
||||
|
||||
using test4 = __make_integer_seq<A, T, 1>;
|
||||
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test4 '__make_integer_seq<A, T, 1>':'__make_integer_seq<A, type-parameter-0-1, 1>'
|
||||
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test4 '__make_integer_seq<A, T, 1>'
|
||||
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' sugar dependent
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' sugar dependent alias
|
||||
// CHECK-NEXT: |-name: '__make_integer_seq' qualified
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' dependent
|
||||
// CHECK-NEXT: |-name: '__make_integer_seq'
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
|
||||
// CHECK-NEXT: |-TemplateArgument template 'A'
|
||||
// CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A
|
||||
// CHECK-NEXT: |-TemplateArgument type 'T'
|
||||
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1
|
||||
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T'
|
||||
// CHECK-NEXT: |-TemplateArgument expr '1'
|
||||
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
|
||||
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, type-parameter-0-1, 1>' dependent
|
||||
// CHECK-NEXT: |-name: '__make_integer_seq'
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
|
||||
// CHECK-NEXT: |-TemplateArgument template 'A'
|
||||
// CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A
|
||||
// CHECK-NEXT: |-TemplateArgument type 'type-parameter-0-1'
|
||||
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent depth 0 index 1
|
||||
// CHECK-NEXT: `-TemplateArgument expr '1'
|
||||
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
|
||||
// CHECK-NEXT: `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
|
||||
// CHECK-NEXT: `-TemplateArgument expr '1'
|
||||
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
|
||||
// CHECK-NEXT: `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
|
||||
|
||||
using test5 = __make_integer_seq<A, int, N>;
|
||||
// CHECK: `-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test5 '__make_integer_seq<A, int, N>'
|
||||
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' sugar dependent
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' sugar dependent alias
|
||||
// CHECK-NEXT: |-name: '__make_integer_seq' qualified
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' dependent
|
||||
// CHECK-NEXT: |-name: '__make_integer_seq'
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
|
||||
// CHECK-NEXT: |-TemplateArgument template 'A'
|
||||
// CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} <line:{{.+}}:1, col:41> col:38 A
|
||||
// CHECK-NEXT: |-TemplateArgument type 'int'
|
||||
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
|
||||
// CHECK-NEXT: |-TemplateArgument expr 'N'
|
||||
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' dependent
|
||||
// CHECK-NEXT: |-name: '__make_integer_seq'
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
|
||||
// CHECK-NEXT: |-TemplateArgument template 'A'
|
||||
// CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A
|
||||
// CHECK-NEXT: |-TemplateArgument type 'int'
|
||||
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
|
||||
// CHECK-NEXT: `-TemplateArgument expr 'N'
|
||||
// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
|
||||
// CHECK-NEXT: `-TemplateArgument expr 'N'
|
||||
// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
|
||||
};
|
||||
|
||||
// expected-no-diagnostics
|
||||
|
@ -17,33 +17,23 @@ using test1 = __type_pack_element<0, int>;
|
||||
|
||||
template<int N, class ...Ts> struct A {
|
||||
using test2 = __type_pack_element<N, Ts...>;
|
||||
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test2 '__type_pack_element<N, Ts...>':'__type_pack_element<N, type-parameter-0-1...>'
|
||||
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test2 '__type_pack_element<N, Ts...>'
|
||||
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' sugar dependent
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' sugar dependent alias
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' dependent
|
||||
// CHECK-NEXT: |-name: '__type_pack_element' qualified
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
|
||||
// CHECK-NEXT: |-TemplateArgument expr 'N'
|
||||
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
|
||||
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
|
||||
// CHECK-NEXT: |-TemplateArgument type 'Ts...'
|
||||
// CHECK-NEXT: | `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
|
||||
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
|
||||
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, type-parameter-0-1...>' dependent
|
||||
// CHECK-NEXT: |-name: '__type_pack_element'
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
|
||||
// CHECK-NEXT: |-TemplateArgument expr 'N'
|
||||
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
|
||||
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
|
||||
// CHECK-NEXT: `-TemplateArgument pack '<type-parameter-0-1...>'
|
||||
// CHECK-NEXT: `-TemplateArgument type 'type-parameter-0-1...'
|
||||
// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1...' dependent
|
||||
// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack
|
||||
// CHECK-NEXT: `-TemplateArgument type 'Ts...'
|
||||
// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
|
||||
// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
|
||||
// CHECK-NEXT: `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
|
||||
|
||||
using test3 = __type_pack_element<0, Ts...>;
|
||||
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test3 '__type_pack_element<0, Ts...>':'__type_pack_element<0, type-parameter-0-1...>'
|
||||
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test3 '__type_pack_element<0, Ts...>'
|
||||
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' sugar dependent
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' sugar dependent alias
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' dependent
|
||||
// CHECK-NEXT: |-name: '__type_pack_element' qualified
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
|
||||
// CHECK-NEXT: |-TemplateArgument expr '0'
|
||||
@ -51,39 +41,22 @@ template<int N, class ...Ts> struct A {
|
||||
// CHECK-NEXT: | |-value: Int 0
|
||||
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
|
||||
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:37> 'int' 0
|
||||
// CHECK-NEXT: |-TemplateArgument type 'Ts...'
|
||||
// CHECK-NEXT: | `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
|
||||
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
|
||||
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, type-parameter-0-1...>' dependent
|
||||
// CHECK-NEXT: |-name: '__type_pack_element'
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
|
||||
// CHECK-NEXT: |-TemplateArgument integral '0UL'
|
||||
// CHECK-NEXT: `-TemplateArgument pack '<type-parameter-0-1...>'
|
||||
// CHECK-NEXT: `-TemplateArgument type 'type-parameter-0-1...'
|
||||
// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1...' dependent
|
||||
// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack
|
||||
// CHECK-NEXT: `-TemplateArgument type 'Ts...'
|
||||
// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
|
||||
// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
|
||||
// CHECK-NEXT: `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
|
||||
|
||||
using test4 = __type_pack_element<N, int>;
|
||||
// CHECK: `-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test4 '__type_pack_element<N, int>'
|
||||
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' sugar dependent
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' sugar dependent alias
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' dependent
|
||||
// CHECK-NEXT: |-name: '__type_pack_element' qualified
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
|
||||
// CHECK-NEXT: |-TemplateArgument expr 'N'
|
||||
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
|
||||
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
|
||||
// CHECK-NEXT: |-TemplateArgument type 'int'
|
||||
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
|
||||
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' dependent
|
||||
// CHECK-NEXT: |-name: '__type_pack_element'
|
||||
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
|
||||
// CHECK-NEXT: |-TemplateArgument expr 'N'
|
||||
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
|
||||
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
|
||||
// CHECK-NEXT: `-TemplateArgument pack '<int>'
|
||||
// CHECK-NEXT: `-TemplateArgument type 'int'
|
||||
// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
|
||||
// CHECK-NEXT: `-TemplateArgument type 'int'
|
||||
// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
|
||||
};
|
||||
|
||||
// expected-no-diagnostics
|
||||
|
@ -257,7 +257,7 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
|
||||
const int Result = 42;
|
||||
auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
|
||||
// Arg is instantiated with '40 + 2'
|
||||
TemplateArgument Arg(ConstExpr);
|
||||
TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false);
|
||||
|
||||
// Param has default expr of '42'
|
||||
auto const *Param = Params->getParam(1);
|
||||
@ -273,7 +273,7 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
|
||||
auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
|
||||
|
||||
// Arg is instantiated with '40 + 1'
|
||||
TemplateArgument Arg(ConstExpr);
|
||||
TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false);
|
||||
|
||||
// Param has default expr of '42'
|
||||
auto const *Param = Params->getParam(1);
|
||||
@ -289,7 +289,7 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
|
||||
auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
|
||||
|
||||
// Arg is instantiated with '4 + 0'
|
||||
TemplateArgument Arg(ConstExpr);
|
||||
TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false);
|
||||
|
||||
// Param has is value-dependent expression (i.e., sizeof(T))
|
||||
auto const *Param = Params->getParam(3);
|
||||
|
Loading…
x
Reference in New Issue
Block a user