[clang] improved preservation of template keyword (#133610)

This commit is contained in:
Matheus Izvekov 2025-04-01 17:15:18 -03:00 committed by GitHub
parent 3c7a0e6c82
commit dc17429ae6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
66 changed files with 611 additions and 719 deletions

View File

@ -119,8 +119,7 @@ getQualification(ASTContext &Context, const DeclContext *DestContext,
// There can't be any more tag parents after hitting a namespace.
assert(!ReachedNS);
(void)ReachedNS;
NNS = NestedNameSpecifier::Create(Context, nullptr, false,
TD->getTypeForDecl());
NNS = NestedNameSpecifier::Create(Context, nullptr, TD->getTypeForDecl());
} else if (auto *NSD = llvm::dyn_cast<NamespaceDecl>(CurContext)) {
ReachedNS = true;
NNS = NestedNameSpecifier::Create(Context, nullptr, NSD);

View File

@ -1467,7 +1467,6 @@ bool allowIndex(CodeCompletionContext &CC) {
return true;
case NestedNameSpecifier::Super:
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
// Unresolved inside a template.
case NestedNameSpecifier::Identifier:
return false;

View File

@ -157,7 +157,6 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
NNS_KIND(Identifier);
NNS_KIND(Namespace);
NNS_KIND(TypeSpec);
NNS_KIND(TypeSpecWithTemplate);
NNS_KIND(Global);
NNS_KIND(Super);
NNS_KIND(NamespaceAlias);

View File

@ -500,7 +500,6 @@ public:
}
return;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
add(QualType(NNS->getAsType(), 0), Flags);
return;
case NestedNameSpecifier::Global:

View File

@ -144,7 +144,6 @@ public:
case NestedNameSpecifier::Global:
return true;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::Super:
case NestedNameSpecifier::Identifier:
return false;

View File

@ -275,6 +275,10 @@ Improvements to Clang's diagnostics
- Diagnostics on chained comparisons (``a < b < c``) are now an error by default. This can be disabled with
``-Wno-error=parentheses``.
- Clang now better preserves the sugared types of pointers to member.
- Clang now better preserves the presence of the template keyword with dependent
prefixes.
- When printing types for diagnostics, clang now doesn't suppress the scopes of
template arguments contained within nested names.
- The ``-Wshift-bool`` warning has been added to warn about shifting a boolean. (#GH28334)
- Fixed diagnostics adding a trailing ``::`` when printing some source code
constructs, like base classes.

View File

@ -1837,15 +1837,14 @@ public:
TagDecl *OwnedTagDecl = nullptr) const;
QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
QualType Canon = QualType()) const;
const IdentifierInfo *Name) const;
QualType getDependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
const IdentifierInfo *Name, ArrayRef<TemplateArgumentLoc> Args) const;
ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name,
ArrayRef<TemplateArgumentLoc> Args) const;
QualType getDependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args) const;
ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name,
ArrayRef<TemplateArgument> Args, bool IsCanonical = false) const;
TemplateArgument getInjectedTemplateArg(NamedDecl *ParamDecl) const;
@ -2393,11 +2392,9 @@ public:
TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,
bool TemplateKeyword,
TemplateName Template) const;
TemplateName
getDependentTemplateName(const DependentTemplateStorage &Name) const;
TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
const IdentifierInfo *Name) const;
TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
OverloadedOperatorKind Operator) const;
TemplateName
getSubstTemplateTemplateParm(TemplateName replacement, Decl *AssociatedDecl,
unsigned Index,

View File

@ -446,6 +446,14 @@ class TypeSourceInfo;
/// returns nullptr only if the FromId was nullptr.
IdentifierInfo *Import(const IdentifierInfo *FromId);
/// Import the given identifier or overloaded operator from the "from"
/// context into the "to" context.
///
/// \returns The equivalent identifier or overloaded operator in the "to"
/// context.
IdentifierOrOverloadedOperator
Import(IdentifierOrOverloadedOperator FromIO);
/// Import the given Objective-C selector from the "from"
/// context into the "to" context.
///

View File

@ -396,8 +396,7 @@ public:
// FIXME: Provide a NestedNameSpecifier visitor.
NestedNameSpecifier *Qualifier = T->getQualifier();
if (NestedNameSpecifier::SpecifierKind K = Qualifier->getKind();
K == NestedNameSpecifier::TypeSpec ||
K == NestedNameSpecifier::TypeSpecWithTemplate)
K == NestedNameSpecifier::TypeSpec)
Visit(Qualifier->getAsType());
if (T->isSugared())
Visit(T->getMostRecentCXXRecordDecl()->getTypeForDecl());

View File

@ -279,10 +279,8 @@ public:
continue;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
cur = NestedNameSpecifier::Create(ctx, cur,
kind == NestedNameSpecifier::TypeSpecWithTemplate,
asImpl().readQualType().getTypePtr());
asImpl().readQualType().getTypePtr());
continue;
case NestedNameSpecifier::Global:

View File

@ -260,7 +260,6 @@ public:
continue;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
asImpl().writeQualType(QualType(NNS->getAsType(), 0));
continue;

View File

@ -52,8 +52,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
enum StoredSpecifierKind {
StoredIdentifier = 0,
StoredDecl = 1,
StoredTypeSpec = 2,
StoredTypeSpecWithTemplate = 3
StoredTypeSpec = 2
};
/// The nested name specifier that precedes this nested name
@ -89,10 +88,6 @@ public:
/// A type, stored as a Type*.
TypeSpec,
/// A type that was preceded by the 'template' keyword,
/// stored as a Type*.
TypeSpecWithTemplate,
/// The global specifier '::'. There is no stored value.
Global,
@ -137,9 +132,8 @@ public:
const NamespaceAliasDecl *Alias);
/// Builds a nested name specifier that names a type.
static NestedNameSpecifier *Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
bool Template, const Type *T);
static NestedNameSpecifier *
Create(const ASTContext &Context, NestedNameSpecifier *Prefix, const Type *T);
/// Builds a specifier that consists of just an identifier.
///
@ -194,8 +188,7 @@ public:
/// Retrieve the type stored in this nested name specifier.
const Type *getAsType() const {
if (Prefix.getInt() == StoredTypeSpec ||
Prefix.getInt() == StoredTypeSpecWithTemplate)
if (Prefix.getInt() == StoredTypeSpec)
return (const Type *)Specifier;
return nullptr;
@ -401,13 +394,10 @@ public:
/// \param Context The AST context in which this nested-name-specifier
/// resides.
///
/// \param TemplateKWLoc The location of the 'template' keyword, if present.
///
/// \param TL The TypeLoc that describes the type preceding the '::'.
///
/// \param ColonColonLoc The location of the trailing '::'.
void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL,
SourceLocation ColonColonLoc);
void Extend(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc);
/// Extend the current nested-name-specifier by another
/// nested-name-specifier component of the form 'identifier::'.

View File

@ -94,6 +94,7 @@ public:
void AddStmt(const Stmt *S);
void AddIdentifierInfo(const IdentifierInfo *II);
void AddNestedNameSpecifier(const NestedNameSpecifier *NNS);
void AddDependentTemplateName(const DependentTemplateStorage &Name);
void AddTemplateName(TemplateName Name);
void AddDeclarationName(DeclarationName Name, bool TreatAsDecl = false);
void AddTemplateArgument(TemplateArgument TA);

View File

@ -692,25 +692,26 @@ let Class = PropertyTypeCase<TemplateName, "QualifiedTemplate"> in {
let Class = PropertyTypeCase<TemplateName, "DependentTemplate"> in {
def : ReadHelper<[{
auto dtn = node.getAsDependentTemplateName();
auto name = dtn->getName();
}]>;
def : Property<"qualifier", NestedNameSpecifier> {
let Read = [{ dtn->getQualifier() }];
}
def : Property<"identifier", Optional<Identifier>> {
let Read = [{ makeOptionalFromPointer(
dtn->isIdentifier()
? dtn->getIdentifier()
: nullptr) }];
let Read = [{ makeOptionalFromPointer(name.getIdentifier()) }];
}
def : Property<"operatorKind", OverloadedOperatorKind> {
let Conditional = [{ !identifier }];
let Read = [{ dtn->getOperator() }];
let Read = [{ name.getOperator() }];
}
def : Property<"HasTemplateKeyword", Bool> {
let Read = [{ dtn->hasTemplateKeyword() }];
}
def : Creator<[{
if (identifier) {
return ctx.getDependentTemplateName(qualifier, *identifier);
return ctx.getDependentTemplateName({qualifier, *identifier, HasTemplateKeyword});
} else {
return ctx.getDependentTemplateName(qualifier, *operatorKind);
return ctx.getDependentTemplateName({qualifier, *operatorKind, HasTemplateKeyword});
}
}]>;
}

View File

@ -795,7 +795,6 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier(
return true;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
TRY_TO(TraverseType(QualType(NNS->getAsType(), 0)));
}
@ -820,7 +819,6 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
return true;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
TRY_TO(TraverseTypeLoc(NNS.getTypeLoc()));
break;
}
@ -1172,7 +1170,8 @@ DEF_TRAVERSE_TYPE(DependentNameType,
{ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); })
DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, {
TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
const DependentTemplateStorage &S = T->getDependentTemplateName();
TRY_TO(TraverseNestedNameSpecifier(S.getQualifier()));
TRY_TO(TraverseTemplateArguments(T->template_arguments()));
})

View File

@ -16,6 +16,7 @@
#include "clang/AST/DependenceFlags.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
@ -537,6 +538,35 @@ public:
}
};
struct IdentifierOrOverloadedOperator {
IdentifierOrOverloadedOperator() = default;
IdentifierOrOverloadedOperator(const IdentifierInfo *II);
IdentifierOrOverloadedOperator(OverloadedOperatorKind OOK);
/// Returns the identifier to which this template name refers.
const IdentifierInfo *getIdentifier() const {
if (getOperator() != OO_None)
return nullptr;
return reinterpret_cast<const IdentifierInfo *>(PtrOrOp);
}
/// Return the overloaded operator to which this template name refers.
OverloadedOperatorKind getOperator() const {
uintptr_t OOK = -PtrOrOp;
return OOK < NUM_OVERLOADED_OPERATORS ? OverloadedOperatorKind(OOK)
: OO_None;
}
void Profile(llvm::FoldingSetNodeID &ID) const;
bool operator==(const IdentifierOrOverloadedOperator &Other) const {
return PtrOrOp == Other.PtrOrOp;
};
private:
uintptr_t PtrOrOp = 0;
};
/// Represents a dependent template name that cannot be
/// resolved prior to template instantiation.
///
@ -545,104 +575,53 @@ public:
/// DependentTemplateName can refer to "MetaFun::template apply",
/// where "MetaFun::" is the nested name specifier and "apply" is the
/// template name referenced. The "template" keyword is implied.
class DependentTemplateName : public llvm::FoldingSetNode {
friend class ASTContext;
class DependentTemplateStorage {
/// The nested name specifier that qualifies the template
/// name.
///
/// The bit stored in this qualifier describes whether the \c Name field
/// is interpreted as an IdentifierInfo pointer (when clear) or as an
/// overloaded operator kind (when set).
/// was preceeded by a template keyword.
llvm::PointerIntPair<NestedNameSpecifier *, 1, bool> Qualifier;
/// The dependent template name.
union {
/// The identifier template name.
///
/// Only valid when the bit on \c Qualifier is clear.
const IdentifierInfo *Identifier;
/// The overloaded operator name.
///
/// Only valid when the bit on \c Qualifier is set.
OverloadedOperatorKind Operator;
};
/// The canonical template name to which this dependent
/// template name refers.
///
/// The canonical template name for a dependent template name is
/// another dependent template name whose nested name specifier is
/// canonical.
TemplateName CanonicalTemplateName;
DependentTemplateName(NestedNameSpecifier *Qualifier,
const IdentifierInfo *Identifier)
: Qualifier(Qualifier, false), Identifier(Identifier),
CanonicalTemplateName(this) {}
DependentTemplateName(NestedNameSpecifier *Qualifier,
const IdentifierInfo *Identifier,
TemplateName Canon)
: Qualifier(Qualifier, false), Identifier(Identifier),
CanonicalTemplateName(Canon) {}
DependentTemplateName(NestedNameSpecifier *Qualifier,
OverloadedOperatorKind Operator)
: Qualifier(Qualifier, true), Operator(Operator),
CanonicalTemplateName(this) {}
DependentTemplateName(NestedNameSpecifier *Qualifier,
OverloadedOperatorKind Operator,
TemplateName Canon)
: Qualifier(Qualifier, true), Operator(Operator),
CanonicalTemplateName(Canon) {}
IdentifierOrOverloadedOperator Name;
public:
DependentTemplateStorage(NestedNameSpecifier *Qualifier,
IdentifierOrOverloadedOperator Name,
bool HasTemplateKeyword);
/// Return the nested name specifier that qualifies this name.
NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); }
/// Determine whether this template name refers to an identifier.
bool isIdentifier() const { return !Qualifier.getInt(); }
IdentifierOrOverloadedOperator getName() const { return Name; }
/// Returns the identifier to which this template name refers.
const IdentifierInfo *getIdentifier() const {
assert(isIdentifier() && "Template name isn't an identifier?");
return Identifier;
}
/// Was this template name was preceeded by the template keyword?
bool hasTemplateKeyword() const { return Qualifier.getInt(); }
/// Determine whether this template name refers to an overloaded
/// operator.
bool isOverloadedOperator() const { return Qualifier.getInt(); }
TemplateNameDependence getDependence() const;
/// Return the overloaded operator to which this template name refers.
OverloadedOperatorKind getOperator() const {
assert(isOverloadedOperator() &&
"Template name isn't an overloaded operator?");
return Operator;
}
void Profile(llvm::FoldingSetNodeID &ID) {
if (isIdentifier())
Profile(ID, getQualifier(), getIdentifier());
else
Profile(ID, getQualifier(), getOperator());
void Profile(llvm::FoldingSetNodeID &ID) const {
Profile(ID, getQualifier(), getName(), hasTemplateKeyword());
}
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
const IdentifierInfo *Identifier) {
IdentifierOrOverloadedOperator Name,
bool HasTemplateKeyword) {
ID.AddPointer(NNS);
ID.AddBoolean(false);
ID.AddPointer(Identifier);
ID.AddBoolean(HasTemplateKeyword);
Name.Profile(ID);
}
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
OverloadedOperatorKind Operator) {
ID.AddPointer(NNS);
ID.AddBoolean(true);
ID.AddInteger(Operator);
}
void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
};
class DependentTemplateName : public DependentTemplateStorage,
public llvm::FoldingSetNode {
friend class ASTContext;
using DependentTemplateStorage::DependentTemplateStorage;
DependentTemplateName(const DependentTemplateStorage &S)
: DependentTemplateStorage(S) {}
};
} // namespace clang.

View File

@ -7098,21 +7098,17 @@ class DependentTemplateSpecializationType : public TypeWithKeyword,
public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these
/// The nested name specifier containing the qualifier.
NestedNameSpecifier *NNS;
/// The identifier of the template.
const IdentifierInfo *Name;
DependentTemplateStorage Name;
DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
const DependentTemplateStorage &Name,
ArrayRef<TemplateArgument> Args,
QualType Canon);
public:
NestedNameSpecifier *getQualifier() const { return NNS; }
const IdentifierInfo *getIdentifier() const { return Name; }
const DependentTemplateStorage &getDependentTemplateName() const {
return Name;
}
ArrayRef<TemplateArgument> template_arguments() const {
return {reinterpret_cast<const TemplateArgument *>(this + 1),
@ -7123,14 +7119,12 @@ public:
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
Profile(ID, Context, getKeyword(), NNS, Name, template_arguments());
Profile(ID, Context, getKeyword(), Name, template_arguments());
}
static void Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context,
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *Qualifier,
const IdentifierInfo *Name,
const DependentTemplateStorage &Name,
ArrayRef<TemplateArgument> Args);
static bool classof(const Type *T) {

View File

@ -2502,8 +2502,9 @@ public:
if (!getLocalData()->QualifierData)
return NestedNameSpecifierLoc();
return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
getLocalData()->QualifierData);
return NestedNameSpecifierLoc(
getTypePtr()->getDependentTemplateName().getQualifier(),
getLocalData()->QualifierData);
}
void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
@ -2516,8 +2517,8 @@ public:
return;
}
assert(QualifierLoc.getNestedNameSpecifier()
== getTypePtr()->getQualifier() &&
assert(QualifierLoc.getNestedNameSpecifier() ==
getTypePtr()->getDependentTemplateName().getQualifier() &&
"Inconsistent nested-name-specifier pointer");
getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
}

View File

@ -774,22 +774,37 @@ let Class = TemplateSpecializationType in {
}
let Class = DependentTemplateSpecializationType in {
def : ReadHelper<[{
const auto &dtn = node->getDependentTemplateName();
auto name = dtn.getName();
}]>;
def : Property<"qualifier", NestedNameSpecifier> {
let Read = [{ dtn.getQualifier() }];
}
def : Property<"identifier", Optional<Identifier>> {
let Read = [{ makeOptionalFromPointer(name.getIdentifier()) }];
}
def : Property<"operatorKind", OverloadedOperatorKind> {
let Conditional = [{ !identifier }];
let Read = [{ name.getOperator() }];
}
def : Property<"HasTemplateKeyword", Bool> {
let Read = [{ dtn.hasTemplateKeyword() }];
}
def : Property<"keyword", ElaboratedTypeKeyword> {
let Read = [{ node->getKeyword() }];
}
def : Property<"qualifier", NestedNameSpecifier> {
let Read = [{ node->getQualifier() }];
}
def : Property<"name", Identifier> {
let Read = [{ node->getIdentifier() }];
}
def : Property<"templateArguments", Array<TemplateArgument>> {
let Read = [{ node->template_arguments() }];
}
def : Creator<[{
return ctx.getDependentTemplateSpecializationType(keyword, qualifier,
name, templateArguments);
DependentTemplateStorage S(qualifier, identifier ? IdentifierOrOverloadedOperator(*identifier) :
IdentifierOrOverloadedOperator(*operatorKind),
HasTemplateKeyword);
return ctx.getDependentTemplateSpecializationType(keyword, S, templateArguments);
}]>;
}
@ -926,22 +941,10 @@ let Class = DependentNameType in {
def : Property<"qualifier", NestedNameSpecifier> {
let Read = [{ node->getQualifier() }];
}
def : Property<"name", Identifier> {
let Read = [{ node->getIdentifier() }];
}
def : Property<"underlyingType", Optional<QualType>> {
let Read = [{
node->isCanonicalUnqualified()
? std::nullopt
: std::optional<QualType>(node->getCanonicalTypeInternal())
}];
}
def : Property<"name", Identifier> { let Read = [{ node->getIdentifier() }]; }
def : Creator<[{
QualType canon = (underlyingType
? ctx.getCanonicalType(*underlyingType)
: QualType());
return ctx.getDependentNameType(keyword, qualifier, name, canon);
return ctx.getDependentNameType(keyword, qualifier, name);
}]>;
}

View File

@ -107,8 +107,7 @@ public:
/// \param TL The TypeLoc that describes the type preceding the '::'.
///
/// \param ColonColonLoc The location of the trailing '::'.
void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL,
SourceLocation ColonColonLoc);
void Extend(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc);
/// Extend the current nested-name-specifier by another
/// nested-name-specifier component of the form 'identifier::'.

View File

@ -4033,7 +4033,6 @@ QualType ASTContext::getMemberPointerType(QualType T,
if (!Qualifier) {
assert(Cls && "At least one of Qualifier or Cls must be provided");
Qualifier = NestedNameSpecifier::Create(*this, /*Prefix=*/nullptr,
/*Template=*/false,
getTypeDeclType(Cls).getTypePtr());
} else if (!Cls) {
Cls = Qualifier->getAsRecordDecl();
@ -4052,8 +4051,7 @@ QualType ASTContext::getMemberPointerType(QualType T,
if (!Cls)
return getCanonicalNestedNameSpecifier(Qualifier);
NestedNameSpecifier *R = NestedNameSpecifier::Create(
*this, /*Prefix=*/nullptr, /*Template=*/false,
Cls->getCanonicalDecl()->getTypeForDecl());
*this, /*Prefix=*/nullptr, Cls->getCanonicalDecl()->getTypeForDecl());
assert(R == getCanonicalNestedNameSpecifier(R));
return R;
}();
@ -5739,24 +5737,26 @@ ASTContext::getMacroQualifiedType(QualType UnderlyingTy,
QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
QualType Canon) const {
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
if (CanonNNS != NNS)
Canon = getDependentNameType(Keyword, CanonNNS, Name);
}
const IdentifierInfo *Name) const {
llvm::FoldingSetNodeID ID;
DependentNameType::Profile(ID, Keyword, NNS, Name);
void *InsertPos = nullptr;
DependentNameType *T
= DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
if (DependentNameType *T =
DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(T, 0);
T = new (*this, alignof(DependentNameType))
QualType Canon;
if (NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
CanonNNS != NNS) {
Canon = getDependentNameType(Keyword, CanonNNS, Name);
[[maybe_unused]] DependentNameType *T =
DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(!T && "broken canonicalization");
assert(Canon.isCanonical());
}
DependentNameType *T = new (*this, alignof(DependentNameType))
DependentNameType(Keyword, NNS, Name, Canon);
Types.push_back(T);
DependentNameTypes.InsertNode(T, InsertPos);
@ -5764,61 +5764,63 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
}
QualType ASTContext::getDependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
const IdentifierInfo *Name, ArrayRef<TemplateArgumentLoc> Args) const {
ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name,
ArrayRef<TemplateArgumentLoc> Args) const {
// TODO: avoid this copy
SmallVector<TemplateArgument, 16> ArgCopy;
for (unsigned I = 0, E = Args.size(); I != E; ++I)
ArgCopy.push_back(Args[I].getArgument());
return getDependentTemplateSpecializationType(Keyword, NNS, Name, ArgCopy);
return getDependentTemplateSpecializationType(Keyword, Name, ArgCopy);
}
QualType
ASTContext::getDependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
ArrayRef<TemplateArgument> Args) const {
assert((!NNS || NNS->isDependent()) &&
"nested-name-specifier must be dependent");
QualType ASTContext::getDependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name,
ArrayRef<TemplateArgument> Args, bool IsCanonical) const {
llvm::FoldingSetNodeID ID;
DependentTemplateSpecializationType::Profile(ID, *this, Keyword, NNS,
Name, Args);
DependentTemplateSpecializationType::Profile(ID, *this, Keyword, Name, Args);
void *InsertPos = nullptr;
DependentTemplateSpecializationType *T
= DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
if (auto *T = DependentTemplateSpecializationTypes.FindNodeOrInsertPos(
ID, InsertPos))
return QualType(T, 0);
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
ElaboratedTypeKeyword CanonKeyword = Keyword;
if (Keyword == ElaboratedTypeKeyword::None)
CanonKeyword = ElaboratedTypeKeyword::Typename;
bool AnyNonCanonArgs = false;
auto CanonArgs =
::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
NestedNameSpecifier *NNS = Name.getQualifier();
QualType Canon;
if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) {
Canon = getDependentTemplateSpecializationType(CanonKeyword, CanonNNS,
Name,
CanonArgs);
if (!IsCanonical) {
ElaboratedTypeKeyword CanonKeyword = Keyword != ElaboratedTypeKeyword::None
? Keyword
: ElaboratedTypeKeyword::Typename;
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
bool AnyNonCanonArgs = false;
auto CanonArgs =
::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
// Find the insert position again.
[[maybe_unused]] auto *Nothing =
DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(!Nothing && "canonical type broken");
if (AnyNonCanonArgs || CanonNNS != NNS || !Name.hasTemplateKeyword() ||
CanonKeyword != Keyword) {
Canon = getDependentTemplateSpecializationType(
CanonKeyword, {CanonNNS, Name.getName(), /*HasTemplateKeyword=*/true},
CanonArgs, /*IsCanonical=*/true);
// Find the insert position again.
[[maybe_unused]] auto *Nothing =
DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID,
InsertPos);
assert(!Nothing && "canonical type broken");
}
} else {
assert(Keyword != ElaboratedTypeKeyword::None);
assert(Name.hasTemplateKeyword());
assert(NNS == getCanonicalNestedNameSpecifier(NNS));
#ifndef NDEBUG
for (const auto &Arg : Args)
assert(Arg.structurallyEquals(getCanonicalTemplateArgument(Arg)));
#endif
}
void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) +
sizeof(TemplateArgument) * Args.size()),
alignof(DependentTemplateSpecializationType));
T = new (Mem) DependentTemplateSpecializationType(Keyword, NNS,
Name, Args, Canon);
auto *T =
new (Mem) DependentTemplateSpecializationType(Keyword, Name, Args, Canon);
Types.push_back(T);
DependentTemplateSpecializationTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
@ -6916,12 +6918,13 @@ ASTContext::getNameForTemplate(TemplateName Name,
case TemplateName::DependentTemplate: {
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
IdentifierOrOverloadedOperator TN = DTN->getName();
DeclarationName DName;
if (DTN->isIdentifier()) {
DName = DeclarationNames.getIdentifier(DTN->getIdentifier());
if (const IdentifierInfo *II = TN.getIdentifier()) {
DName = DeclarationNames.getIdentifier(II);
return DeclarationNameInfo(DName, NameLoc);
} else {
DName = DeclarationNames.getCXXOperatorName(DTN->getOperator());
DName = DeclarationNames.getCXXOperatorName(TN.getOperator());
// DNInfo work in progress: FIXME: source locations?
DeclarationNameLoc DNLoc =
DeclarationNameLoc::makeCXXOperatorNameLoc(SourceRange());
@ -6996,7 +6999,13 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name,
case TemplateName::DependentTemplate: {
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
assert(DTN && "Non-dependent template names must refer to template decls.");
return DTN->CanonicalTemplateName;
NestedNameSpecifier *Qualifier = DTN->getQualifier();
NestedNameSpecifier *CanonQualifier =
getCanonicalNestedNameSpecifier(Qualifier);
if (Qualifier != CanonQualifier || !DTN->hasTemplateKeyword())
return getDependentTemplateName({CanonQualifier, DTN->getName(),
/*HasTemplateKeyword=*/true});
return Name;
}
case TemplateName::SubstTemplateTemplateParmPack: {
@ -7229,7 +7238,6 @@ static bool isSameQualifier(const NestedNameSpecifier *X,
// We've already checked that we named the same namespace.
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
if (X->getAsType()->getCanonicalTypeInternal() !=
Y->getAsType()->getCanonicalTypeInternal())
return false;
@ -7608,8 +7616,7 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
// The difference between TypeSpec and TypeSpecWithTemplate is that the
// latter will have the 'template' keyword when printed.
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
case NestedNameSpecifier::TypeSpec: {
const Type *T = getCanonicalType(NNS->getAsType());
// If we have some kind of dependent-named type (e.g., "typename T::type"),
@ -7622,11 +7629,19 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
if (const auto *DNT = T->getAs<DependentNameType>())
return NestedNameSpecifier::Create(*this, DNT->getQualifier(),
DNT->getIdentifier());
if (const auto *DTST = T->getAs<DependentTemplateSpecializationType>())
return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true, T);
// TODO: Set 'Template' parameter to true for other template types.
return NestedNameSpecifier::Create(*this, nullptr, false, T);
if (const auto *DTST = T->getAs<DependentTemplateSpecializationType>()) {
const DependentTemplateStorage &DTN = DTST->getDependentTemplateName();
QualType NewT = getDependentTemplateSpecializationType(
ElaboratedTypeKeyword::Typename,
{/*NNS=*/nullptr, DTN.getName(), /*HasTemplateKeyword=*/true},
DTST->template_arguments(), /*IsCanonical=*/true);
assert(NewT.isCanonical());
NestedNameSpecifier *Prefix = DTN.getQualifier();
if (!Prefix)
Prefix = getCanonicalNestedNameSpecifier(NNS->getPrefix());
return NestedNameSpecifier::Create(*this, Prefix, NewT.getTypePtr());
}
return NestedNameSpecifier::Create(*this, nullptr, T);
}
case NestedNameSpecifier::Global:
@ -10056,75 +10071,20 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
return TemplateName(QTN);
}
/// Retrieve the template name that represents a dependent
/// template name such as \c MetaFun::template apply.
TemplateName
ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
const IdentifierInfo *Name) const {
assert((!NNS || NNS->isDependent()) &&
"Nested name specifier must be dependent");
llvm::FoldingSetNodeID ID;
DependentTemplateName::Profile(ID, NNS, Name);
void *InsertPos = nullptr;
DependentTemplateName *QTN =
DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
if (QTN)
return TemplateName(QTN);
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
if (CanonNNS == NNS) {
QTN = new (*this, alignof(DependentTemplateName))
DependentTemplateName(NNS, Name);
} else {
TemplateName Canon = getDependentTemplateName(CanonNNS, Name);
QTN = new (*this, alignof(DependentTemplateName))
DependentTemplateName(NNS, Name, Canon);
DependentTemplateName *CheckQTN =
DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
assert(!CheckQTN && "Dependent type name canonicalization broken");
(void)CheckQTN;
}
DependentTemplateNames.InsertNode(QTN, InsertPos);
return TemplateName(QTN);
}
/// Retrieve the template name that represents a dependent
/// template name such as \c MetaFun::template operator+.
TemplateName
ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
OverloadedOperatorKind Operator) const {
assert((!NNS || NNS->isDependent()) &&
"Nested name specifier must be dependent");
ASTContext::getDependentTemplateName(const DependentTemplateStorage &S) const {
llvm::FoldingSetNodeID ID;
DependentTemplateName::Profile(ID, NNS, Operator);
S.Profile(ID);
void *InsertPos = nullptr;
DependentTemplateName *QTN
= DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
if (QTN)
if (DependentTemplateName *QTN =
DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos))
return TemplateName(QTN);
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
if (CanonNNS == NNS) {
QTN = new (*this, alignof(DependentTemplateName))
DependentTemplateName(NNS, Operator);
} else {
TemplateName Canon = getDependentTemplateName(CanonNNS, Operator);
QTN = new (*this, alignof(DependentTemplateName))
DependentTemplateName(NNS, Operator, Canon);
DependentTemplateName *CheckQTN
= DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
assert(!CheckQTN && "Dependent template name canonicalization broken");
(void)CheckQTN;
}
DependentTemplateName *QTN =
new (*this, alignof(DependentTemplateName)) DependentTemplateName(S);
DependentTemplateNames.InsertNode(QTN, InsertPos);
return TemplateName(QTN);
}
@ -13543,19 +13503,12 @@ static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx,
R = NestedNameSpecifier::Create(Ctx, P, ::getCommonDeclChecked(N1, N2));
break;
}
case NestedNameSpecifier::SpecifierKind::TypeSpec:
case NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate: {
case NestedNameSpecifier::SpecifierKind::TypeSpec: {
// FIXME: See comment below, on Super case.
if (K2 == NestedNameSpecifier::SpecifierKind::Super)
return Ctx.getCanonicalNestedNameSpecifier(NNS1);
assert(K2 == NestedNameSpecifier::SpecifierKind::TypeSpec ||
K2 == NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate);
// Only keep the template keyword if both sides have it.
bool Template =
K1 == NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate &&
K2 == NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate;
assert(K2 == NestedNameSpecifier::SpecifierKind::TypeSpec);
const Type *T1 = NNS1->getAsType(), *T2 = NNS2->getAsType();
if (T1 == T2) {
@ -13569,13 +13522,12 @@ static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx,
bool IsSame = isa<DependentTemplateSpecializationType>(T1);
NestedNameSpecifier *P =
::getCommonNNS(Ctx, NNS1->getPrefix(), NNS2->getPrefix(), IsSame);
R = NestedNameSpecifier::Create(Ctx, P, Template, T1);
R = NestedNameSpecifier::Create(Ctx, P, T1);
break;
}
// TODO: Try to salvage the original prefix.
// If getCommonSugaredType removed any top level sugar, the original prefix
// is not applicable anymore.
NestedNameSpecifier *P = nullptr;
const Type *T = Ctx.getCommonSugaredType(QualType(T1, 0), QualType(T2, 0),
/*Unqualified=*/true)
.getTypePtr();
@ -13585,7 +13537,7 @@ static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx,
case Type::Elaborated: {
// An ElaboratedType is stripped off, it's Qualifier becomes the prefix.
auto *ET = cast<ElaboratedType>(T);
R = NestedNameSpecifier::Create(Ctx, ET->getQualifier(), Template,
R = NestedNameSpecifier::Create(Ctx, ET->getQualifier(),
ET->getNamedType().getTypePtr());
break;
}
@ -13600,16 +13552,17 @@ static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx,
// A DependentTemplateSpecializationType loses it's Qualifier, which
// is turned into the prefix.
auto *DTST = cast<DependentTemplateSpecializationType>(T);
T = Ctx.getDependentTemplateSpecializationType(
DTST->getKeyword(), /*NNS=*/nullptr, DTST->getIdentifier(),
DTST->template_arguments())
const DependentTemplateStorage &DTN = DTST->getDependentTemplateName();
DependentTemplateStorage NewDTN(/*Qualifier=*/nullptr, DTN.getName(),
DTN.hasTemplateKeyword());
T = Ctx.getDependentTemplateSpecializationType(DTST->getKeyword(), NewDTN,
DTST->template_arguments())
.getTypePtr();
P = DTST->getQualifier();
R = NestedNameSpecifier::Create(Ctx, DTST->getQualifier(), Template, T);
R = NestedNameSpecifier::Create(Ctx, DTN.getQualifier(), T);
break;
}
default:
R = NestedNameSpecifier::Create(Ctx, P, Template, T);
R = NestedNameSpecifier::Create(Ctx, /*Prefix=*/nullptr, T);
break;
}
break;
@ -14052,19 +14005,22 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
assert(NX->getIdentifier() == NY->getIdentifier());
return Ctx.getDependentNameType(
getCommonTypeKeyword(NX, NY),
getCommonQualifier(Ctx, NX, NY, /*IsSame=*/true), NX->getIdentifier(),
NX->getCanonicalTypeInternal());
getCommonQualifier(Ctx, NX, NY, /*IsSame=*/true), NX->getIdentifier());
}
case Type::DependentTemplateSpecialization: {
const auto *TX = cast<DependentTemplateSpecializationType>(X),
*TY = cast<DependentTemplateSpecializationType>(Y);
assert(TX->getIdentifier() == TY->getIdentifier());
auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
TY->template_arguments());
const DependentTemplateStorage &SX = TX->getDependentTemplateName(),
&SY = TY->getDependentTemplateName();
assert(SX.getName() == SY.getName());
DependentTemplateStorage Name(
getCommonNNS(Ctx, SX.getQualifier(), SY.getQualifier(),
/*IsSame=*/true),
SX.getName(), SX.hasTemplateKeyword() || SY.hasTemplateKeyword());
return Ctx.getDependentTemplateSpecializationType(
getCommonTypeKeyword(TX, TY),
getCommonQualifier(Ctx, TX, TY, /*IsSame=*/true), TX->getIdentifier(),
As);
getCommonTypeKeyword(TX, TY), Name, As);
}
case Type::UnaryTransform: {
const auto *TX = cast<UnaryTransformType>(X),

View File

@ -1707,11 +1707,10 @@ ASTNodeImporter::VisitPackExpansionType(const PackExpansionType *T) {
ExpectedType ASTNodeImporter::VisitDependentTemplateSpecializationType(
const DependentTemplateSpecializationType *T) {
auto ToQualifierOrErr = import(T->getQualifier());
if (!ToQualifierOrErr)
return ToQualifierOrErr.takeError();
IdentifierInfo *ToName = Importer.Import(T->getIdentifier());
const DependentTemplateStorage &DTN = T->getDependentTemplateName();
auto QualifierOrErr = import(DTN.getQualifier());
if (!QualifierOrErr)
return QualifierOrErr.takeError();
SmallVector<TemplateArgument, 2> ToPack;
ToPack.reserve(T->template_arguments().size());
@ -1719,7 +1718,10 @@ ExpectedType ASTNodeImporter::VisitDependentTemplateSpecializationType(
return std::move(Err);
return Importer.getToContext().getDependentTemplateSpecializationType(
T->getKeyword(), *ToQualifierOrErr, ToName, ToPack);
T->getKeyword(),
{*QualifierOrErr, Importer.Import(DTN.getName()),
DTN.hasTemplateKeyword()},
ToPack);
}
ExpectedType
@ -1729,18 +1731,8 @@ ASTNodeImporter::VisitDependentNameType(const DependentNameType *T) {
return ToQualifierOrErr.takeError();
IdentifierInfo *Name = Importer.Import(T->getIdentifier());
QualType Canon;
if (T != T->getCanonicalTypeInternal().getTypePtr()) {
if (ExpectedType TyOrErr = import(T->getCanonicalTypeInternal()))
Canon = (*TyOrErr).getCanonicalType();
else
return TyOrErr.takeError();
}
return Importer.getToContext().getDependentNameType(T->getKeyword(),
*ToQualifierOrErr,
Name, Canon);
*ToQualifierOrErr, Name);
}
ExpectedType
@ -9788,12 +9780,8 @@ ASTImporter::Import(NestedNameSpecifier *FromNNS) {
return RDOrErr.takeError();
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
if (ExpectedTypePtr TyOrErr = Import(FromNNS->getAsType())) {
bool TSTemplate =
FromNNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate;
return NestedNameSpecifier::Create(ToContext, Prefix, TSTemplate,
*TyOrErr);
return NestedNameSpecifier::Create(ToContext, Prefix, *TyOrErr);
} else {
return TyOrErr.takeError();
}
@ -9851,21 +9839,13 @@ ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
ToLocalBeginLoc, ToLocalEndLoc);
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
case NestedNameSpecifier::TypeSpec: {
SourceLocation ToTLoc;
if (Error Err = importInto(ToTLoc, NNS.getTypeLoc().getBeginLoc()))
return std::move(Err);
TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo(
QualType(Spec->getAsType(), 0), ToTLoc);
if (Kind == NestedNameSpecifier::TypeSpecWithTemplate)
// ToLocalBeginLoc is here the location of the 'template' keyword.
Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(),
ToLocalEndLoc);
else
// No location for 'template' keyword here.
Builder.Extend(getToContext(), SourceLocation{}, TSI->getTypeLoc(),
ToLocalEndLoc);
QualType(Spec->getAsType(), 0), ToTLoc);
Builder.Extend(getToContext(), TSI->getTypeLoc(), ToLocalEndLoc);
break;
}
@ -9934,14 +9914,8 @@ Expected<TemplateName> ASTImporter::Import(TemplateName From) {
auto QualifierOrErr = Import(DTN->getQualifier());
if (!QualifierOrErr)
return QualifierOrErr.takeError();
if (DTN->isIdentifier()) {
return ToContext.getDependentTemplateName(*QualifierOrErr,
Import(DTN->getIdentifier()));
}
return ToContext.getDependentTemplateName(*QualifierOrErr,
DTN->getOperator());
return ToContext.getDependentTemplateName(
{*QualifierOrErr, Import(DTN->getName()), DTN->hasTemplateKeyword()});
}
case TemplateName::SubstTemplateTemplateParm: {
@ -10312,6 +10286,13 @@ IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) {
return ToId;
}
IdentifierOrOverloadedOperator
ASTImporter::Import(IdentifierOrOverloadedOperator FromIO) {
if (const IdentifierInfo *FromII = FromIO.getIdentifier())
return Import(FromII);
return FromIO.getOperator();
}
Expected<Selector> ASTImporter::Import(Selector FromSel) {
if (FromSel.isNull())
return Selector{};

View File

@ -566,7 +566,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(),
NNS2->getAsNamespaceAlias());
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0),
QualType(NNS2->getAsType(), 0));
case NestedNameSpecifier::Global:
@ -578,6 +577,19 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const DependentTemplateStorage &S1,
const DependentTemplateStorage &S2) {
if (!IsStructurallyEquivalent(Context, S1.getQualifier(), S2.getQualifier()))
return false;
IdentifierOrOverloadedOperator IO1 = S1.getName(), IO2 = S2.getName();
const IdentifierInfo *II1 = IO1.getIdentifier(), *II2 = IO2.getIdentifier();
if (!II1 || !II2)
return IO1.getOperator() == IO2.getOperator();
return IsStructurallyEquivalent(II1, II2);
}
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const TemplateName &N1,
const TemplateName &N2) {
@ -614,19 +626,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return TN1->getDeclName() == TN2->getDeclName();
}
case TemplateName::DependentTemplate: {
DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),
*DN2 = N2.getAsDependentTemplateName();
if (!IsStructurallyEquivalent(Context, DN1->getQualifier(),
DN2->getQualifier()))
return false;
if (DN1->isIdentifier() && DN2->isIdentifier())
return IsStructurallyEquivalent(DN1->getIdentifier(),
DN2->getIdentifier());
else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator())
return DN1->getOperator() == DN2->getOperator();
return false;
}
case TemplateName::DependentTemplate:
return IsStructurallyEquivalent(Context, *N1.getAsDependentTemplateName(),
*N2.getAsDependentTemplateName());
case TemplateName::SubstTemplateTemplateParmPack: {
SubstTemplateTemplateParmPackStorage
@ -1315,11 +1317,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case Type::DependentTemplateSpecialization: {
const auto *Spec1 = cast<DependentTemplateSpecializationType>(T1);
const auto *Spec2 = cast<DependentTemplateSpecializationType>(T2);
if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(),
Spec2->getQualifier()))
if (Spec1->getKeyword() != Spec2->getKeyword())
return false;
if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
Spec2->getIdentifier()))
if (!IsStructurallyEquivalent(Context, Spec1->getDependentTemplateName(),
Spec2->getDependentTemplateName()))
return false;
if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(),
Spec2->template_arguments()))

View File

@ -1327,7 +1327,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
type->getAs<DependentTemplateSpecializationType>()) {
if (!mangleSubstitution(QualType(DTST, 0))) {
TemplateName Template = getASTContext().getDependentTemplateName(
DTST->getQualifier(), DTST->getIdentifier());
DTST->getDependentTemplateName());
mangleTemplatePrefix(Template);
// FIXME: GCC does not appear to mangle the template arguments when
@ -1395,8 +1395,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
mangleSourceNameWithAbiTags(qualifier->getAsNamespaceAlias());
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
case NestedNameSpecifier::TypeSpec: {
const Type *type = qualifier->getAsType();
// We only want to use an unresolved-type encoding if this is one of:
@ -2181,7 +2180,17 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
return;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
if (NestedNameSpecifier *Prefix = qualifier->getPrefix()) {
const auto *DTST =
cast<DependentTemplateSpecializationType>(qualifier->getAsType());
QualType NewT = getASTContext().getDependentTemplateSpecializationType(
DTST->getKeyword(),
{Prefix, DTST->getDependentTemplateName().getName(),
/*HasTemplateKeyword=*/true},
DTST->template_arguments(), /*IsCanonical=*/true);
manglePrefix(NewT);
return;
}
manglePrefix(QualType(qualifier->getAsType(), 0));
return;
@ -2265,10 +2274,11 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
if (Clang11Compat && mangleSubstitution(Template))
return;
if (const IdentifierInfo *Id = Dependent->getIdentifier())
if (IdentifierOrOverloadedOperator Name = Dependent->getName();
const IdentifierInfo *Id = Name.getIdentifier())
mangleSourceName(Id);
else
mangleOperatorName(Dependent->getOperator(), UnknownArity);
mangleOperatorName(Name.getOperator(), UnknownArity);
addSubstitution(Template);
}
@ -2376,12 +2386,13 @@ void CXXNameMangler::mangleType(TemplateName TN) {
case TemplateName::DependentTemplate: {
const DependentTemplateName *Dependent = TN.getAsDependentTemplateName();
assert(Dependent->isIdentifier());
const IdentifierInfo *II = Dependent->getName().getIdentifier();
assert(II);
// <class-enum-type> ::= <name>
// <name> ::= <nested-name>
mangleUnresolvedPrefix(Dependent->getQualifier());
mangleSourceName(Dependent->getIdentifier());
mangleSourceName(II);
break;
}
@ -2572,8 +2583,8 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
const DependentTemplateSpecializationType *DTST =
cast<DependentTemplateSpecializationType>(Ty);
TemplateName Template = getASTContext().getDependentTemplateName(
DTST->getQualifier(), DTST->getIdentifier());
mangleSourceName(DTST->getIdentifier());
DTST->getDependentTemplateName());
mangleTemplatePrefix(Template);
mangleTemplateArgs(Template, DTST->template_arguments());
break;
}
@ -4481,10 +4492,8 @@ void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
// Dependently-scoped template types are nested if they have a prefix.
Out << 'N';
// TODO: avoid making this TemplateName.
TemplateName Prefix =
getASTContext().getDependentTemplateName(T->getQualifier(),
T->getIdentifier());
getASTContext().getDependentTemplateName(T->getDependentTemplateName());
mangleTemplatePrefix(Prefix);
// FIXME: GCC does not appear to mangle the template arguments when

View File

@ -98,14 +98,13 @@ NestedNameSpecifier::Create(const ASTContext &Context,
return FindOrInsert(Context, Mockup);
}
NestedNameSpecifier *
NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
bool Template, const Type *T) {
NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
const Type *T) {
assert(T && "Type cannot be NULL");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
Mockup.Prefix.setInt(Template? StoredTypeSpecWithTemplate : StoredTypeSpec);
Mockup.Prefix.setInt(StoredTypeSpec);
Mockup.Specifier = const_cast<Type*>(T);
return FindOrInsert(Context, Mockup);
}
@ -155,9 +154,6 @@ NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
case StoredTypeSpec:
return TypeSpec;
case StoredTypeSpecWithTemplate:
return TypeSpecWithTemplate;
}
llvm_unreachable("Invalid NNS Kind!");
@ -189,7 +185,6 @@ CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const {
return dyn_cast<CXXRecordDecl>(static_cast<NamedDecl *>(Specifier));
case StoredTypeSpec:
case StoredTypeSpecWithTemplate:
return getAsType()->getAsCXXRecordDecl();
}
@ -222,9 +217,13 @@ NestedNameSpecifierDependence NestedNameSpecifier::getDependence() const {
return NestedNameSpecifierDependence::None;
}
case TypeSpec:
case TypeSpecWithTemplate:
return toNestedNameSpecifierDependendence(getAsType()->getDependence());
case TypeSpec: {
NestedNameSpecifierDependence Dep =
toNestedNameSpecifierDependendence(getAsType()->getDependence());
if (NestedNameSpecifier *Prefix = getPrefix())
Dep |= Prefix->getDependence();
return Dep;
}
}
llvm_unreachable("Invalid NNS Kind!");
}
@ -254,17 +253,17 @@ NestedNameSpecifier::translateToType(const ASTContext &Context) const {
.getDependentNameType(ElaboratedTypeKeyword::None, Prefix,
getAsIdentifier())
.getTypePtr();
case SpecifierKind::TypeSpec:
case SpecifierKind::TypeSpecWithTemplate: {
case SpecifierKind::TypeSpec: {
const Type *T = getAsType();
switch (T->getTypeClass()) {
case Type::DependentTemplateSpecialization: {
const auto *DT = cast<DependentTemplateSpecializationType>(T);
// FIXME: The type node can't represent the template keyword.
const DependentTemplateStorage &DTN = DT->getDependentTemplateName();
return Context
.getDependentTemplateSpecializationType(ElaboratedTypeKeyword::None,
Prefix, DT->getIdentifier(),
DT->template_arguments())
.getDependentTemplateSpecializationType(
ElaboratedTypeKeyword::None,
{Prefix, DTN.getName(), DTN.hasTemplateKeyword()},
DT->template_arguments())
.getTypePtr();
}
case Type::Record:
@ -324,59 +323,11 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
OS << "__super";
break;
case TypeSpecWithTemplate:
OS << "template ";
// Fall through to print the type.
[[fallthrough]];
case TypeSpec: {
const auto *Record =
dyn_cast_or_null<ClassTemplateSpecializationDecl>(getAsRecordDecl());
if (ResolveTemplateArguments && Record) {
// Print the type trait with resolved template parameters.
Record->printName(OS, Policy);
printTemplateArgumentList(
OS, Record->getTemplateArgs().asArray(), Policy,
Record->getSpecializedTemplate()->getTemplateParameters());
break;
}
const Type *T = getAsType();
PrintingPolicy InnerPolicy(Policy);
InnerPolicy.SuppressScope = true;
InnerPolicy.SuppressTagKeyword = true;
// Nested-name-specifiers are intended to contain minimally-qualified
// types. An actual ElaboratedType will not occur, since we'll store
// just the type that is referred to in the nested-name-specifier (e.g.,
// a TypedefType, TagType, etc.). However, when we are dealing with
// dependent template-id types (e.g., Outer<T>::template Inner<U>),
// the type requires its own nested-name-specifier for uniqueness, so we
// suppress that nested-name-specifier during printing.
assert(!isa<ElaboratedType>(T) &&
"Elaborated type in nested-name-specifier");
if (const TemplateSpecializationType *SpecType
= dyn_cast<TemplateSpecializationType>(T)) {
// Print the template name without its corresponding
// nested-name-specifier.
SpecType->getTemplateName().print(OS, InnerPolicy,
TemplateName::Qualified::None);
// Print the template argument list.
printTemplateArgumentList(OS, SpecType->template_arguments(),
InnerPolicy);
} else if (const auto *DepSpecType =
dyn_cast<DependentTemplateSpecializationType>(T)) {
// Print the template name without its corresponding
// nested-name-specifier.
OS << DepSpecType->getIdentifier()->getName();
// Print the template argument list.
printTemplateArgumentList(OS, DepSpecType->template_arguments(),
InnerPolicy);
} else {
// Print the type normally
QualType(T, 0).print(OS, InnerPolicy);
}
QualType(getAsType(), 0).print(OS, InnerPolicy);
break;
}
}
@ -421,7 +372,6 @@ NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) {
Length += sizeof(SourceLocation::UIntTy);
break;
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec:
// The "void*" that points at the TypeLoc data.
// Note: the 'template' keyword is part of the TypeLoc.
@ -485,7 +435,6 @@ SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const {
LoadSourceLocation(Data, Offset),
LoadSourceLocation(Data, Offset + sizeof(SourceLocation::UIntTy)));
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec: {
// The "void*" that points at the TypeLoc data.
// Note: the 'template' keyword is part of the TypeLoc.
@ -500,8 +449,7 @@ SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const {
}
TypeLoc NestedNameSpecifierLoc::getTypeLoc() const {
if (Qualifier->getKind() != NestedNameSpecifier::TypeSpec &&
Qualifier->getKind() != NestedNameSpecifier::TypeSpecWithTemplate)
if (Qualifier->getKind() != NestedNameSpecifier::TypeSpec)
return TypeLoc();
// The "void*" that points at the TypeLoc data.
@ -609,13 +557,10 @@ operator=(const NestedNameSpecifierLocBuilder &Other) {
return *this;
}
void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
SourceLocation TemplateKWLoc,
TypeLoc TL,
void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, TypeLoc TL,
SourceLocation ColonColonLoc) {
Representation = NestedNameSpecifier::Create(Context, Representation,
TemplateKWLoc.isValid(),
TL.getTypePtr());
Representation =
NestedNameSpecifier::Create(Context, Representation, TL.getTypePtr());
// Push source-location info into the buffer.
SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity);
@ -697,8 +642,7 @@ void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context,
SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
case NestedNameSpecifier::TypeSpec: {
TypeSourceInfo *TSInfo
= Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0),
R.getBegin());

View File

@ -128,7 +128,6 @@ void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
AddDecl(NNS->getAsNamespaceAlias());
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
AddType(NNS->getAsType());
break;
case NestedNameSpecifier::Global:
@ -137,6 +136,16 @@ void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
}
}
void ODRHash::AddDependentTemplateName(const DependentTemplateStorage &Name) {
if (NestedNameSpecifier *NNS = Name.getQualifier())
AddNestedNameSpecifier(NNS);
if (IdentifierOrOverloadedOperator IO = Name.getName();
const IdentifierInfo *II = IO.getIdentifier())
AddIdentifierInfo(II);
else
ID.AddInteger(IO.getOperator());
}
void ODRHash::AddTemplateName(TemplateName Name) {
auto Kind = Name.getKind();
ID.AddInteger(Kind);
@ -153,10 +162,13 @@ void ODRHash::AddTemplateName(TemplateName Name) {
AddTemplateName(QTN->getUnderlyingTemplate());
break;
}
case TemplateName::DependentTemplate: {
AddDependentTemplateName(*Name.getAsDependentTemplateName());
break;
}
// TODO: Support these cases.
case TemplateName::OverloadedTemplate:
case TemplateName::AssumedTemplate:
case TemplateName::DependentTemplate:
case TemplateName::SubstTemplateTemplateParm:
case TemplateName::SubstTemplateTemplateParmPack:
case TemplateName::UsingTemplate:
@ -1221,8 +1233,7 @@ public:
void VisitDependentTemplateSpecializationType(
const DependentTemplateSpecializationType *T) {
AddIdentifierInfo(T->getIdentifier());
AddNestedNameSpecifier(T->getQualifier());
Hash.AddDependentTemplateName(T->getDependentTemplateName());
ID.AddInteger(T->template_arguments().size());
for (const auto &TA : T->template_arguments()) {
Hash.AddTemplateArgument(TA);

View File

@ -212,6 +212,7 @@ static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
bool WithGlobalNsPrefix) {
switch (Scope->getKind()) {
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Super:
// Already fully qualified
return Scope;
case NestedNameSpecifier::Namespace:
@ -232,9 +233,7 @@ static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
// but use the name of it's prefix.
return getFullyQualifiedNestedNameSpecifier(
Ctx, Scope->getPrefix(), WithGlobalNsPrefix);
case NestedNameSpecifier::Super:
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
case NestedNameSpecifier::TypeSpec: {
const Type *Type = Scope->getAsType();
// Find decl context.
const TagDecl *TD = nullptr;
@ -366,8 +365,7 @@ NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
}
return NestedNameSpecifier::Create(
Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
false /*No TemplateKeyword*/, TypePtr);
Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), TypePtr);
}
/// Return the fully qualified type, including fully-qualified

View File

@ -122,6 +122,31 @@ void SubstTemplateTemplateParmPackStorage::Profile(
ID.AddBoolean(Final);
}
IdentifierOrOverloadedOperator::IdentifierOrOverloadedOperator(
const IdentifierInfo *II)
: PtrOrOp(reinterpret_cast<uintptr_t>(II)) {
static_assert(NUM_OVERLOADED_OPERATORS <= 4096,
"NUM_OVERLOADED_OPERATORS is too large");
assert(II);
assert(getIdentifier() == II);
}
IdentifierOrOverloadedOperator::IdentifierOrOverloadedOperator(
OverloadedOperatorKind OOK)
: PtrOrOp(-uintptr_t(OOK)) {
assert(OOK != OO_None);
assert(getOperator() == OOK);
}
void IdentifierOrOverloadedOperator::Profile(llvm::FoldingSetNodeID &ID) const {
if (auto *Identifier = getIdentifier()) {
ID.AddBoolean(false);
ID.AddPointer(Identifier);
} else {
ID.AddBoolean(true);
ID.AddInteger(getOperator());
}
}
TemplateName::TemplateName(void *Ptr) {
Storage = StorageType::getFromOpaqueValue(Ptr);
}
@ -275,6 +300,36 @@ UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const {
return nullptr;
}
DependentTemplateStorage::DependentTemplateStorage(
NestedNameSpecifier *Qualifier, IdentifierOrOverloadedOperator Name,
bool HasTemplateKeyword)
: Qualifier(Qualifier, HasTemplateKeyword), Name(Name) {
assert((!Qualifier || Qualifier->isDependent()) &&
"Qualifier must be dependent");
}
TemplateNameDependence DependentTemplateStorage::getDependence() const {
auto D = TemplateNameDependence::DependentInstantiation;
if (NestedNameSpecifier *Qualifier = getQualifier())
D |= toTemplateNameDependence(Qualifier->getDependence());
return D;
}
void DependentTemplateStorage::print(raw_ostream &OS,
const PrintingPolicy &Policy) const {
if (NestedNameSpecifier *NNS = getQualifier())
NNS->print(OS, Policy);
if (hasTemplateKeyword())
OS << "template ";
IdentifierOrOverloadedOperator Name = getName();
if (const IdentifierInfo *II = Name.getIdentifier())
OS << II->getName();
else
OS << "operator " << getOperatorSpelling(Name.getOperator());
}
DeducedTemplateStorage *TemplateName::getAsDeducedTemplateName() const {
if (UncommonTemplateNameStorage *Uncommon =
dyn_cast_if_present<UncommonTemplateNameStorage *>(Storage))
@ -313,7 +368,8 @@ TemplateNameDependence TemplateName::getDependence() const {
case NameKind::DependentTemplate: {
DependentTemplateName *S = getAsDependentTemplateName();
auto D = TemplateNameDependence::DependentInstantiation;
D |= toTemplateNameDependence(S->getQualifier()->getDependence());
if (NestedNameSpecifier *Qualifier = S->getQualifier())
D |= toTemplateNameDependence(Qualifier->getDependence());
return D;
}
case NameKind::SubstTemplateTemplateParm: {
@ -401,14 +457,7 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
else
OS << *UTD;
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
if (NestedNameSpecifier *NNS = DTN->getQualifier())
NNS->print(OS, Policy);
OS << "template ";
if (DTN->isIdentifier())
OS << DTN->getIdentifier()->getName();
else
OS << "operator " << getOperatorSpelling(DTN->getOperator());
DTN->print(OS, Policy);
} else if (SubstTemplateTemplateParmStorage *subst =
getAsSubstTemplateTemplateParm()) {
subst->getReplacement().print(OS, Policy, Qual);

View File

@ -1027,10 +1027,6 @@ void clang::TextNodeDumper::dumpNestedNameSpecifier(const NestedNameSpecifier *N
OS << " TypeSpec";
dumpType(QualType(NNS->getAsType(), 0));
break;
case NestedNameSpecifier::TypeSpecWithTemplate:
OS << " TypeSpecWithTemplate";
dumpType(QualType(NNS->getAsType(), 0));
break;
case NestedNameSpecifier::Global:
OS << " Global";
break;

View File

@ -3270,16 +3270,13 @@ StringRef TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
}
DependentTemplateSpecializationType::DependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args, QualType Canon)
ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name,
ArrayRef<TemplateArgument> Args, QualType Canon)
: TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon,
TypeDependence::DependentInstantiation |
(NNS ? toTypeDependence(NNS->getDependence())
: TypeDependence::None)),
NNS(NNS), Name(Name) {
toTypeDependence(Name.getDependence())),
Name(Name) {
DependentTemplateSpecializationTypeBits.NumArgs = Args.size();
assert((!NNS || NNS->isDependent()) &&
"DependentTemplateSpecializatonType requires dependent qualifier");
auto *ArgBuffer = const_cast<TemplateArgument *>(template_arguments().data());
for (const TemplateArgument &Arg : Args) {
addDependence(toTypeDependence(Arg.getDependence() &
@ -3289,16 +3286,12 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType(
}
}
void
DependentTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context,
ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *Qualifier,
const IdentifierInfo *Name,
ArrayRef<TemplateArgument> Args) {
void DependentTemplateSpecializationType::Profile(
llvm::FoldingSetNodeID &ID, const ASTContext &Context,
ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name,
ArrayRef<TemplateArgument> Args) {
ID.AddInteger(llvm::to_underlying(Keyword));
ID.AddPointer(Qualifier);
ID.AddPointer(Name);
Name.Profile(ID);
for (const TemplateArgument &Arg : Args)
Arg.Profile(ID, Context);
}

View File

@ -569,9 +569,10 @@ void
DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
setElaboratedKeywordLoc(Loc);
if (getTypePtr()->getQualifier()) {
if (NestedNameSpecifier *Qualifier =
getTypePtr()->getDependentTemplateName().getQualifier()) {
NestedNameSpecifierLocBuilder Builder;
Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
Builder.MakeTrivial(Context, Qualifier, Loc);
setQualifierLoc(Builder.getWithLocInContext(Context));
} else {
setQualifierLoc(NestedNameSpecifierLoc());

View File

@ -1793,9 +1793,7 @@ void TypePrinter::printDependentTemplateSpecializationBefore(
if (T->getKeyword() != ElaboratedTypeKeyword::None)
OS << " ";
if (T->getQualifier())
T->getQualifier()->print(OS, Policy);
OS << "template " << T->getIdentifier()->getName();
T->getDependentTemplateName().print(OS, Policy);
printTemplateArgumentList(OS, T->template_arguments(), Policy);
spaceBeforePlaceHolder(OS);
}
@ -2498,14 +2496,18 @@ void clang::printTemplateArgumentList(raw_ostream &OS,
ArrayRef<TemplateArgument> Args,
const PrintingPolicy &Policy,
const TemplateParameterList *TPL) {
printTo(OS, Args, Policy, TPL, /*isPack*/ false, /*parmIndex*/ 0);
PrintingPolicy InnerPolicy = Policy;
InnerPolicy.SuppressScope = false;
printTo(OS, Args, InnerPolicy, TPL, /*isPack*/ false, /*parmIndex*/ 0);
}
void clang::printTemplateArgumentList(raw_ostream &OS,
ArrayRef<TemplateArgumentLoc> Args,
const PrintingPolicy &Policy,
const TemplateParameterList *TPL) {
printTo(OS, Args, Policy, TPL, /*isPack*/ false, /*parmIndex*/ 0);
PrintingPolicy InnerPolicy = Policy;
InnerPolicy.SuppressScope = false;
printTo(OS, Args, InnerPolicy, TPL, /*isPack*/ false, /*parmIndex*/ 0);
}
std::string Qualifiers::getAsString() const {

View File

@ -249,13 +249,6 @@ DeclarationFragmentsBuilder::getFragmentsForNNS(const NestedNameSpecifier *NNS,
Fragments.append("__super", DeclarationFragments::FragmentKind::Keyword);
break;
case NestedNameSpecifier::TypeSpecWithTemplate:
// A type prefixed by the `template` keyword.
Fragments.append("template", DeclarationFragments::FragmentKind::Keyword);
Fragments.appendSpace();
// Fallthrough after adding the keyword to handle the actual type.
[[fallthrough]];
case NestedNameSpecifier::TypeSpec: {
const Type *T = NNS->getAsType();
// FIXME: Handle C++ template specialization type

View File

@ -277,7 +277,6 @@ void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
indexTypeLoc(NNS.getTypeLoc(), Parent, DC);
break;
}

View File

@ -587,12 +587,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
<< II.getName()
<< FixItHint::CreateInsertion(Tok.getLocation(), "template ");
}
SourceLocation TemplateNameLoc = ConsumeToken();
ConsumeToken();
TemplateNameKind TNK = Actions.ActOnTemplateName(
getCurScope(), SS, TemplateNameLoc, TemplateName, ObjectType,
EnteringContext, Template, /*AllowInjectedClassName*/ true);
getCurScope(), SS, /*TemplateKWLoc=*/SourceLocation(), TemplateName,
ObjectType, EnteringContext, Template,
/*AllowInjectedClassName=*/true);
if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
TemplateName, false))
return true;

View File

@ -48,9 +48,9 @@ void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) {
EndLocation = TemplateId->RAngleLoc;
}
void CXXScopeSpec::Extend(ASTContext &Context, SourceLocation TemplateKWLoc,
TypeLoc TL, SourceLocation ColonColonLoc) {
Builder.Extend(Context, TemplateKWLoc, TL, ColonColonLoc);
void CXXScopeSpec::Extend(ASTContext &Context, TypeLoc TL,
SourceLocation ColonColonLoc) {
Builder.Extend(Context, TL, ColonColonLoc);
if (Range.getBegin().isInvalid())
Range.setBegin(TL.getBeginLoc());
Range.setEnd(ColonColonLoc);

View File

@ -365,9 +365,10 @@ HeuristicResolverImpl::resolveDependentNameType(const DependentNameType *DNT) {
std::vector<const NamedDecl *>
HeuristicResolverImpl::resolveTemplateSpecializationType(
const DependentTemplateSpecializationType *DTST) {
const DependentTemplateStorage &DTN = DTST->getDependentTemplateName();
return resolveDependentMember(
resolveNestedNameSpecifierToType(DTST->getQualifier()),
DTST->getIdentifier(), TemplateFilter);
resolveNestedNameSpecifierToType(DTN.getQualifier()),
DTN.getName().getIdentifier(), TemplateFilter);
}
std::vector<const NamedDecl *>
@ -409,7 +410,6 @@ QualType HeuristicResolverImpl::resolveNestedNameSpecifierToType(
// the TypeSpec cases too.
switch (NNS->getKind()) {
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
return QualType(NNS->getAsType(), 0);
case NestedNameSpecifier::Identifier: {
return resolveDeclsToType(

View File

@ -145,8 +145,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
case NestedNameSpecifier::NamespaceAlias:
return NNS->getAsNamespaceAlias()->getNamespace();
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
case NestedNameSpecifier::TypeSpec: {
const TagType *Tag = NNS->getAsType()->getAs<TagType>();
assert(Tag && "Non-tag type in nested-name-specifier");
return Tag->getDecl();
@ -687,8 +686,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier");
}
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
IdInfo.CCLoc);
SS.Extend(Context, TLB.getTypeLocInContext(Context, T), IdInfo.CCLoc);
return false;
}
@ -735,8 +733,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
QualType T = Context.getTypeDeclType(ContainingClass);
TypeLocBuilder TLB;
TLB.pushTrivial(Context, T, IdInfo.IdentifierLoc);
SS.Extend(Context, /*TemplateKWLoc=*/SourceLocation(),
TLB.getTypeLocInContext(Context, T), IdInfo.IdentifierLoc);
SS.Extend(Context, TLB.getTypeLocInContext(Context, T),
IdInfo.IdentifierLoc);
// Add the identifier to form a dependent name.
SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc,
IdInfo.CCLoc);
@ -804,8 +802,7 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
ColonColonLoc);
SS.Extend(Context, TLB.getTypeLocInContext(Context, T), ColonColonLoc);
return false;
}
@ -827,8 +824,7 @@ bool Sema::ActOnCXXNestedNameSpecifierIndexedPack(CXXScopeSpec &SS,
DS.getBeginLoc());
PackIndexingTypeLoc PIT = TLB.push<PackIndexingTypeLoc>(Type);
PIT.setEllipsisLoc(DS.getEllipsisLoc());
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, Type),
ColonColonLoc);
SS.Extend(Context, TLB.getTypeLocInContext(Context, Type), ColonColonLoc);
return false;
}
@ -862,12 +858,14 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
DependentTemplateName *DTN = Template.getAsDependentTemplateName();
if (DTN && DTN->isIdentifier()) {
if (DTN && DTN->getName().getIdentifier()) {
// Handle a dependent template specialization for which we cannot resolve
// the template name.
assert(DTN->getQualifier() == SS.getScopeRep());
QualType T = Context.getDependentTemplateSpecializationType(
ElaboratedTypeKeyword::None, DTN->getQualifier(), DTN->getIdentifier(),
ElaboratedTypeKeyword::None,
{/*Qualifier=*/nullptr, DTN->getName().getIdentifier(),
TemplateKWLoc.isValid()},
TemplateArgs.arguments());
// Create source-location information for this type.
@ -875,7 +873,6 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
DependentTemplateSpecializationTypeLoc SpecTL
= Builder.push<DependentTemplateSpecializationTypeLoc>(T);
SpecTL.setElaboratedKeywordLoc(SourceLocation());
SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
SpecTL.setTemplateNameLoc(TemplateNameLoc);
SpecTL.setLAngleLoc(LAngleLoc);
@ -883,8 +880,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
SS.Extend(Context, TemplateKWLoc, Builder.getTypeLocInContext(Context, T),
CCLoc);
SS.Extend(Context, Builder.getTypeLocInContext(Context, T), CCLoc);
return false;
}
@ -932,9 +928,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
SS.Extend(Context, TemplateKWLoc, Builder.getTypeLocInContext(Context, T),
CCLoc);
SS.Extend(Context, Builder.getTypeLocInContext(Context, T), CCLoc);
return false;
}
@ -1007,7 +1001,6 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::Super:
// These are never namespace scopes.
return true;

View File

@ -755,7 +755,7 @@ getRequiredQualification(ASTContext &Context, const DeclContext *CurContext,
Result = NestedNameSpecifier::Create(Context, Result, Namespace);
} else if (const auto *TD = dyn_cast<TagDecl>(Parent))
Result = NestedNameSpecifier::Create(
Context, Result, false, Context.getTypeDeclType(TD).getTypePtr());
Context, Result, Context.getTypeDeclType(TD).getTypePtr());
}
return Result;
}
@ -1216,7 +1216,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
NestedNameSpecifier::Create(SemaRef.Context, nullptr, Namespace);
else if (const TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
R.Qualifier = NestedNameSpecifier::Create(
SemaRef.Context, nullptr, false,
SemaRef.Context, nullptr,
SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
else
R.QualifierIsInformative = false;
@ -1405,7 +1405,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
NestedNameSpecifier::Create(SemaRef.Context, nullptr, Namespace);
else if (const auto *Tag = dyn_cast<TagDecl>(Ctx))
R.Qualifier = NestedNameSpecifier::Create(
SemaRef.Context, nullptr, false,
SemaRef.Context, nullptr,
SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
else
R.QualifierIsInformative = false;

View File

@ -116,8 +116,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
auto buildElaboratedType = [&]() {
auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, S.getStdNamespace());
NNS = NestedNameSpecifier::Create(S.Context, NNS, false,
CoroTrait.getTypePtr());
NNS = NestedNameSpecifier::Create(S.Context, NNS, CoroTrait.getTypePtr());
return S.Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS,
PromiseType);
};

View File

@ -252,8 +252,8 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
S.Diag(NameLoc, diag::ext_found_in_dependent_base) << &II;
ASTContext &Context = S.Context;
auto *NNS = NestedNameSpecifier::Create(Context, nullptr, false,
cast<Type>(Context.getRecordType(RD)));
auto *NNS = NestedNameSpecifier::Create(
Context, nullptr, cast<Type>(Context.getRecordType(RD)));
QualType T =
Context.getDependentNameType(ElaboratedTypeKeyword::Typename, NNS, &II);
@ -580,10 +580,10 @@ synthesizeCurrentNestedNameSpecifier(ASTContext &Context, DeclContext *DC) {
auto *ND = dyn_cast<NamespaceDecl>(DC);
if (ND && !ND->isInline() && !ND->isAnonymousNamespace())
return NestedNameSpecifier::Create(Context, nullptr, ND);
else if (auto *RD = dyn_cast<CXXRecordDecl>(DC))
return NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(),
if (auto *RD = dyn_cast<CXXRecordDecl>(DC))
return NestedNameSpecifier::Create(Context, nullptr,
RD->getTypeForDecl());
else if (isa<TranslationUnitDecl>(DC))
if (isa<TranslationUnitDecl>(DC))
return NestedNameSpecifier::GlobalSpecifier(Context);
}
llvm_unreachable("something isn't in TU scope?");
@ -624,8 +624,7 @@ ParsedType Sema::ActOnMSVCUnknownTypeName(const IdentifierInfo &II,
findRecordWithDependentBasesOfEnclosingMethod(CurContext)) {
// Build a DependentNameType that will perform lookup into RD at
// instantiation time.
NNS = NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(),
RD->getTypeForDecl());
NNS = NestedNameSpecifier::Create(Context, nullptr, RD->getTypeForDecl());
// Diagnose that this identifier was undeclared, and retry the lookup during
// template instantiation.
@ -6243,11 +6242,12 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
NestedNameSpecifierLoc SpecLoc(SS.getScopeRep(), SS.location_data());
do {
if (SpecLoc.getNestedNameSpecifier()->getKind() ==
NestedNameSpecifier::TypeSpecWithTemplate)
Diag(Loc, diag::ext_template_after_declarative_nns)
<< FixItHint::CreateRemoval(
SpecLoc.getTypeLoc().getTemplateKeywordLoc());
if (TypeLoc TL = SpecLoc.getTypeLoc()) {
if (SourceLocation TemplateKeywordLoc = TL.getTemplateKeywordLoc();
TemplateKeywordLoc.isValid())
Diag(Loc, diag::ext_template_after_declarative_nns)
<< FixItHint::CreateRemoval(TemplateKeywordLoc);
}
if (const Type *T = SpecLoc.getNestedNameSpecifier()->getAsType()) {
if (const auto *TST = T->getAsAdjusted<TemplateSpecializationType>()) {

View File

@ -14799,8 +14799,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
CXXScopeSpec SS;
const Type *CanonicalT = S.Context.getCanonicalType(T.getTypePtr());
SS.MakeTrivial(S.Context,
NestedNameSpecifier::Create(S.Context, nullptr, false,
CanonicalT),
NestedNameSpecifier::Create(S.Context, nullptr, CanonicalT),
Loc);
// Create the reference to operator=.

View File

@ -2684,7 +2684,7 @@ recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context,
// perform name lookup during template instantiation.
CXXScopeSpec SS;
auto *NNS =
NestedNameSpecifier::Create(Context, nullptr, true, RD->getTypeForDecl());
NestedNameSpecifier::Create(Context, nullptr, RD->getTypeForDecl());
SS.MakeTrivial(Context, NNS, SourceRange(Loc, Loc));
return DependentScopeDeclRefExpr::Create(
Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,

View File

@ -508,7 +508,6 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
switch (SS.getScopeRep()->getKind()) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
// Per C++11 [over.literal]p2, literal operators can only be declared at
// namespace scope. Therefore, this unqualified-id cannot name anything.
// Reject it early, because we have no AST representation for this in the

View File

@ -4530,7 +4530,6 @@ static void getNestedNameSpecifierIdentifiers(
II = NNS->getAsNamespaceAlias()->getIdentifier();
break;
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec:
II = QualType(NNS->getAsType(), 0).getBaseTypeIdentifier();
break;
@ -4895,8 +4894,7 @@ TypoCorrectionConsumer::NamespaceSpecifierSet::buildNestedNameSpecifier(
NNS = NestedNameSpecifier::Create(Context, NNS, ND);
++NumSpecifiers;
} else if (auto *RD = dyn_cast_or_null<RecordDecl>(C)) {
NNS = NestedNameSpecifier::Create(Context, NNS, RD->isTemplateDecl(),
RD->getTypeForDecl());
NNS = NestedNameSpecifier::Create(Context, NNS, RD->getTypeForDecl());
++NumSpecifiers;
}
}

View File

@ -364,8 +364,8 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
// The code is missing a 'template' keyword prior to the dependent template
// name.
NestedNameSpecifier *Qualifier = (NestedNameSpecifier *)SS->getScopeRep();
SuggestedTemplate
= TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II));
SuggestedTemplate = TemplateTy::make(Context.getDependentTemplateName(
{Qualifier, &II, /*HasTemplateKeyword=*/false}));
Diag(IILoc, diag::err_template_kw_missing)
<< SuggestedTemplate.get()
<< FixItHint::CreateInsertion(IILoc, "template ");
@ -2777,7 +2777,8 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// Look one step prior in a dependent template specialization type.
if (const DependentTemplateSpecializationType *DependentTST
= T->getAs<DependentTemplateSpecializationType>()) {
if (NestedNameSpecifier *NNS = DependentTST->getQualifier())
if (NestedNameSpecifier *NNS =
DependentTST->getDependentTemplateName().getQualifier())
T = QualType(NNS->getAsType(), 0);
else
T = QualType();
@ -3480,16 +3481,17 @@ Sema::findFailedBooleanCondition(Expr *Cond) {
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
DependentTemplateName *DTN =
Name.getUnderlying().getAsDependentTemplateName();
if (DTN && DTN->isIdentifier())
// FIXME: 'getUnderlying' loses SubstTemplateTemplateParm nodes from alias
// template substitutions.
if (DependentTemplateName *DTN =
Name.getUnderlying().getAsDependentTemplateName();
DTN && DTN->getName().getIdentifier())
// When building a template-id where the template-name is dependent,
// assume the template is a type template. Either our assumption is
// correct, or the code is ill-formed and will be diagnosed when the
// dependent name is substituted.
return Context.getDependentTemplateSpecializationType(
ElaboratedTypeKeyword::None, DTN->getQualifier(), DTN->getIdentifier(),
TemplateArgs.arguments());
ElaboratedTypeKeyword::None, *DTN, TemplateArgs.arguments());
if (Name.getAsAssumedTemplateName() &&
resolveAssumedTemplateNameAsType(/*Scope=*/nullptr, Name, TemplateLoc))
@ -3824,8 +3826,7 @@ TypeResult Sema::ActOnTemplateIdType(
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
assert(SS.getScopeRep() == DTN->getQualifier());
QualType T = Context.getDependentTemplateSpecializationType(
ElaboratedTypeKeyword::None, DTN->getQualifier(), DTN->getIdentifier(),
TemplateArgs.arguments());
ElaboratedTypeKeyword::None, *DTN, TemplateArgs.arguments());
// Build type-source information.
TypeLocBuilder TLB;
DependentTemplateSpecializationTypeLoc SpecTL
@ -3894,8 +3895,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
assert(SS.getScopeRep() == DTN->getQualifier());
QualType T = Context.getDependentTemplateSpecializationType(
Keyword, DTN->getQualifier(), DTN->getIdentifier(),
TemplateArgs.arguments());
Keyword, *DTN, TemplateArgs.arguments());
// Build type-source information.
TypeLocBuilder TLB;
@ -4812,13 +4812,14 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
switch (Name.getKind()) {
case UnqualifiedIdKind::IK_Identifier:
Result = TemplateTy::make(
Context.getDependentTemplateName(Qualifier, Name.Identifier));
Result = TemplateTy::make(Context.getDependentTemplateName(
{Qualifier, Name.Identifier, TemplateKWLoc.isValid()}));
return TNK_Dependent_template_name;
case UnqualifiedIdKind::IK_OperatorFunctionId:
Result = TemplateTy::make(Context.getDependentTemplateName(
Qualifier, Name.OperatorFunctionId.Operator));
{Qualifier, Name.OperatorFunctionId.Operator,
TemplateKWLoc.isValid()}));
return TNK_Function_template;
case UnqualifiedIdKind::IK_LiteralOperatorId:
@ -5332,7 +5333,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
// know that we need a non-type template argument, convert this
// template name into an expression.
DeclarationNameInfo NameInfo(DTN->getIdentifier(),
DeclarationNameInfo NameInfo(DTN->getName().getIdentifier(),
ArgLoc.getTemplateNameLoc());
CXXScopeSpec SS;
@ -6071,8 +6072,9 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentNameType(
bool UnnamedLocalNoLinkageFinder::VisitDependentTemplateSpecializationType(
const DependentTemplateSpecializationType* T) {
if (auto *Q = T->getQualifier())
if (auto *Q = T->getDependentTemplateName().getQualifier())
return VisitNestedNameSpecifier(Q);
return false;
}
@ -6154,7 +6156,6 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier(
return false;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
return Visit(QualType(NNS->getAsType(), 0));
}
llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
@ -7526,9 +7527,8 @@ ExprResult Sema::BuildExpressionFromDeclTemplateArgument(
isa<IndirectFieldDecl>(VD)));
QualType ClassType
= Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext()));
NestedNameSpecifier *Qualifier
= NestedNameSpecifier::Create(Context, nullptr, false,
ClassType.getTypePtr());
NestedNameSpecifier *Qualifier =
NestedNameSpecifier::Create(Context, nullptr, ClassType.getTypePtr());
SS.MakeTrivial(Context, Qualifier, Loc);
}
@ -10694,15 +10694,14 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
assert(DTN && "dependent template has non-dependent name?");
assert(DTN->getQualifier() == SS.getScopeRep());
if (!DTN->isIdentifier()) {
if (!DTN->getName().getIdentifier()) {
Diag(TemplateIILoc, diag::err_template_id_not_a_type) << Template;
NoteAllFoundTemplates(Template);
return true;
}
QualType T = Context.getDependentTemplateSpecializationType(
ElaboratedTypeKeyword::Typename, DTN->getQualifier(),
DTN->getIdentifier(), TemplateArgs.arguments());
ElaboratedTypeKeyword::Typename, *DTN, TemplateArgs.arguments());
// Create source-location information for this type.
TypeLocBuilder Builder;

View File

@ -7031,7 +7031,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
const DependentTemplateSpecializationType *Spec
= cast<DependentTemplateSpecializationType>(T);
MarkUsedTemplateParameters(Ctx, Spec->getQualifier(),
MarkUsedTemplateParameters(Ctx,
Spec->getDependentTemplateName().getQualifier(),
OnlyDeduced, Depth, Used);
for (const auto &Arg : Spec->template_arguments())

View File

@ -705,7 +705,7 @@ public:
QualType TransformDependentTemplateSpecializationType(
TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL,
NestedNameSpecifierLoc QualifierLoc);
CXXScopeSpec &SS);
/// Transforms the parameters of a function type into the
/// given vectors.
@ -1132,38 +1132,21 @@ public:
/// nested-name-specifier and the given type. Subclasses may override
/// this routine to provide different behavior.
QualType RebuildDependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const IdentifierInfo *Name,
SourceLocation NameLoc,
TemplateArgumentListInfo &Args,
bool AllowInjectedClassName) {
// Rebuild the template name.
// TODO: avoid TemplateName abstraction
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
TemplateName InstName = getDerived().RebuildTemplateName(
SS, TemplateKWLoc, *Name, NameLoc, QualType(), nullptr,
AllowInjectedClassName);
if (InstName.isNull())
return QualType();
ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
SourceLocation TemplateKWLoc, TemplateName Name, SourceLocation NameLoc,
TemplateArgumentListInfo &Args, bool AllowInjectedClassName) {
// If it's still dependent, make a dependent specialization.
if (InstName.getAsDependentTemplateName())
if (const DependentTemplateStorage *S = Name.getAsDependentTemplateName())
return SemaRef.Context.getDependentTemplateSpecializationType(
Keyword, QualifierLoc.getNestedNameSpecifier(), Name,
Args.arguments());
Keyword, *S, Args.arguments());
// Otherwise, make an elaborated type wrapping a non-dependent
// specialization.
QualType T =
getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args);
getDerived().RebuildTemplateSpecializationType(Name, NameLoc, Args);
if (T.isNull())
return QualType();
return SemaRef.Context.getElaboratedType(
Keyword, QualifierLoc.getNestedNameSpecifier(), T);
return SemaRef.Context.getElaboratedType(Keyword, NNS, T);
}
/// Build a new typename type that refers to an identifier.
@ -1332,6 +1315,13 @@ public:
SourceLocation NameLoc, QualType ObjectType,
bool AllowInjectedClassName);
TemplateName RebuildTemplateName(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
IdentifierOrOverloadedOperator IO,
SourceLocation NameLoc, QualType ObjectType,
NamedDecl *FirstQualifierInScope,
bool AllowInjectedClassName);
/// Build a new template name given a template template parameter pack
/// and the
///
@ -4634,7 +4624,6 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
break;
}
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec: {
TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType,
FirstQualifierInScope, SS);
@ -4654,8 +4643,7 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
TL = ETL.getNamedTypeLoc();
}
SS.Extend(SemaRef.Context, TL.getTemplateKeywordLoc(), TL,
Q.getLocalEndLoc());
SS.Extend(SemaRef.Context, TL, Q.getLocalEndLoc());
break;
}
// If the nested-name-specifier is an invalid type def, don't emit an
@ -4753,6 +4741,22 @@ TreeTransform<Derived>
llvm_unreachable("Unknown name kind.");
}
template <typename Derived>
TemplateName TreeTransform<Derived>::RebuildTemplateName(
CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
IdentifierOrOverloadedOperator IO, SourceLocation NameLoc,
QualType ObjectType, NamedDecl *FirstQualifierInScope,
bool AllowInjectedClassName) {
if (const IdentifierInfo *II = IO.getIdentifier()) {
return getDerived().RebuildTemplateName(SS, TemplateKWLoc, *II, NameLoc,
ObjectType, FirstQualifierInScope,
AllowInjectedClassName);
}
return getDerived().RebuildTemplateName(SS, TemplateKWLoc, IO.getOperator(),
NameLoc, ObjectType,
AllowInjectedClassName);
}
template<typename Derived>
TemplateName
TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
@ -4794,20 +4798,9 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
// FIXME: Preserve the location of the "template" keyword.
SourceLocation TemplateKWLoc = NameLoc;
if (DTN->isIdentifier()) {
return getDerived().RebuildTemplateName(SS,
TemplateKWLoc,
*DTN->getIdentifier(),
NameLoc,
ObjectType,
FirstQualifierInScope,
AllowInjectedClassName);
}
return getDerived().RebuildTemplateName(SS, TemplateKWLoc,
DTN->getOperator(), NameLoc,
ObjectType, AllowInjectedClassName);
return getDerived().RebuildTemplateName(
SS, TemplateKWLoc, DTN->getName(), NameLoc, ObjectType,
FirstQualifierInScope, AllowInjectedClassName);
}
// FIXME: Try to preserve more of the TemplateName.
@ -5401,13 +5394,14 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
DependentTemplateSpecializationTypeLoc SpecTL =
TL.castAs<DependentTemplateSpecializationTypeLoc>();
TemplateName Template
= getDerived().RebuildTemplateName(SS,
SpecTL.getTemplateKeywordLoc(),
*SpecTL.getTypePtr()->getIdentifier(),
SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup,
/*AllowInjectedClassName*/true);
const IdentifierInfo *II = SpecTL.getTypePtr()
->getDependentTemplateName()
.getName()
.getIdentifier();
TemplateName Template = getDerived().RebuildTemplateName(
SS, SpecTL.getTemplateKeywordLoc(), *II, SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup,
/*AllowInjectedClassName*/ true);
if (Template.isNull())
return nullptr;
@ -7430,9 +7424,9 @@ QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
// FIXME: maybe don't rebuild if all the template arguments are the same.
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
assert(DTN->getQualifier() == SS.getScopeRep());
QualType Result = getSema().Context.getDependentTemplateSpecializationType(
TL.getTypePtr()->getKeyword(), DTN->getQualifier(),
DTN->getIdentifier(), NewTemplateArgs.arguments());
TL.getTypePtr()->getKeyword(), *DTN, NewTemplateArgs.arguments());
DependentTemplateSpecializationTypeLoc NewTL
= TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
@ -7755,15 +7749,15 @@ QualType TreeTransform<Derived>::
return QualType();
}
return getDerived()
.TransformDependentTemplateSpecializationType(TLB, TL, QualifierLoc);
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
return getDerived().TransformDependentTemplateSpecializationType(TLB, TL, SS);
}
template<typename Derived>
QualType TreeTransform<Derived>::
TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
DependentTemplateSpecializationTypeLoc TL,
NestedNameSpecifierLoc QualifierLoc) {
template <typename Derived>
QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL,
CXXScopeSpec &SS) {
const DependentTemplateSpecializationType *T = TL.getTypePtr();
TemplateArgumentListInfo NewTemplateArgs;
@ -7777,13 +7771,25 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
NewTemplateArgs))
return QualType();
QualType Result = getDerived().RebuildDependentTemplateSpecializationType(
T->getKeyword(), QualifierLoc, TL.getTemplateKeywordLoc(),
T->getIdentifier(), TL.getTemplateNameLoc(), NewTemplateArgs,
/*AllowInjectedClassName*/ false);
if (Result.isNull())
return QualType();
const DependentTemplateStorage &DTN = T->getDependentTemplateName();
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || SS.getScopeRep() != DTN.getQualifier()) {
TemplateName Name = getDerived().RebuildTemplateName(
SS, TL.getTemplateKeywordLoc(), DTN.getName(), TL.getTemplateNameLoc(),
/*ObjectType=*/QualType(), /*FirstQualifierInScope=*/nullptr,
/*AllowInjectedClassName=*/false);
if (Name.isNull())
return QualType();
Result = getDerived().RebuildDependentTemplateSpecializationType(
T->getKeyword(), SS.getScopeRep(), TL.getTemplateKeywordLoc(), Name,
TL.getTemplateNameLoc(), NewTemplateArgs,
/*AllowInjectedClassName=*/false);
if (Result.isNull())
return QualType();
}
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(SemaRef.Context);
if (const ElaboratedType *ElabT = dyn_cast<ElaboratedType>(Result)) {
QualType NamedT = ElabT->getNamedType();
@ -7801,7 +7807,8 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc());
NewTL.setQualifierLoc(QualifierLoc);
} else if (isa<DependentTemplateSpecializationType>(Result)) {
} else {
assert(isa<DependentTemplateSpecializationType>(Result));
DependentTemplateSpecializationTypeLoc SpecTL
= TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
SpecTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc());
@ -7812,15 +7819,6 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
SpecTL.setRAngleLoc(TL.getRAngleLoc());
for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I)
SpecTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo());
} else {
TemplateSpecializationTypeLoc SpecTL
= TLB.push<TemplateSpecializationTypeLoc>(Result);
SpecTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc());
SpecTL.setTemplateNameLoc(TL.getTemplateNameLoc());
SpecTL.setLAngleLoc(TL.getLAngleLoc());
SpecTL.setRAngleLoc(TL.getRAngleLoc());
for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I)
SpecTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo());
}
return Result;
}
@ -17532,8 +17530,7 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
<< ScopeType->getType() << getSema().getLangOpts().CPlusPlus;
return ExprError();
}
SS.Extend(SemaRef.Context, SourceLocation(), ScopeType->getTypeLoc(),
CCLoc);
SS.Extend(SemaRef.Context, ScopeType->getTypeLoc(), CCLoc);
}
SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.

View File

@ -9914,18 +9914,12 @@ ASTRecordReader::readNestedNameSpecifierLoc() {
break;
}
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
bool Template = readBool();
case NestedNameSpecifier::TypeSpec: {
TypeSourceInfo *T = readTypeSourceInfo();
if (!T)
return NestedNameSpecifierLoc();
SourceLocation ColonColonLoc = readSourceLocation();
// FIXME: 'template' keyword location not saved anywhere, so we fake it.
Builder.Extend(Context,
Template? T->getTypeLoc().getBeginLoc() : SourceLocation(),
T->getTypeLoc(), ColonColonLoc);
Builder.Extend(Context, T->getTypeLoc(), ColonColonLoc);
break;
}

View File

@ -7022,8 +7022,6 @@ void ASTRecordWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
Record->push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate);
AddTypeRef(NNS.getTypeLoc().getType());
AddTypeLoc(NNS.getTypeLoc());
AddSourceLocation(NNS.getLocalSourceRange().getEnd());

View File

@ -959,8 +959,6 @@ public:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Identifier:
return syntax::NodeKind::IdentifierNameSpecifier;
case NestedNameSpecifier::TypeSpecWithTemplate:
return syntax::NodeKind::SimpleTemplateNameSpecifier;
case NestedNameSpecifier::TypeSpec: {
const auto *NNSType = NNS.getAsType();
assert(NNSType);

View File

@ -351,8 +351,8 @@ namespace testClassTemplateDecl {
// CHECK-NEXT: | |-CXXDestructorDecl 0x{{.+}} <line:[[@LINE-67]]:5, col:24> col:5 used ~TestClassTemplate 'void () noexcept' implicit_instantiation instantiated_from 0x[[#TEMPLATE_DESTRUCTOR_DECL]]{{$}}
// CHECK-NEXT: | |-CXXMethodDecl 0x{{.+}} <line:[[@LINE-67]]:5, col:11> col:9 j 'int ()' implicit_instantiation instantiated_from 0x[[#TEMPLATE_METHOD_DECL]]{{$}}
// CHECK-NEXT: | |-FieldDecl 0x{{.+}} <line:[[@LINE-67]]:5, col:9> col:9 i 'int'{{$}}
// CHECK-NEXT: | `-CXXConstructorDecl 0x{{.+}} <line:[[@LINE-73]]:30> col:30 implicit constexpr TestClassTemplate 'void (const TestClassTemplate<A> &)' inline default trivial noexcept-unevaluated 0x{{.+}}{{$}}
// CHECK-NEXT: | `-ParmVarDecl 0x{{.+}} <col:30> col:30 'const TestClassTemplate<A> &'{{$}}
// CHECK-NEXT: | `-CXXConstructorDecl 0x{{.+}} <line:[[@LINE-73]]:30> col:30 implicit constexpr TestClassTemplate 'void (const TestClassTemplate<testClassTemplateDecl::A> &)' inline default trivial noexcept-unevaluated 0x{{.+}}{{$}}
// CHECK-NEXT: | `-ParmVarDecl 0x{{.+}} <col:30> col:30 'const TestClassTemplate<testClassTemplateDecl::A> &'{{$}}
// CHECK-NEXT: |-ClassTemplateSpecialization 0x{{.+}} 'TestClassTemplate'{{$}}
// CHECK-NEXT: |-ClassTemplateSpecialization 0x{{.+}} 'TestClassTemplate'{{$}}
// CHECK-NEXT: `-ClassTemplateSpecialization 0x{{.+}} 'TestClassTemplate'{{$}}
@ -654,10 +654,10 @@ namespace testCanonicalTemplate {
// CHECK-NEXT: | `-ClassTemplateSpecialization 0x{{.+}} 'TestClassTemplate'{{$}}
// CHECK-NEXT: |-CXXConstructorDecl 0x{{.+}} <line:[[@LINE-36]]:31> col:31 implicit used constexpr TestClassTemplate 'void () noexcept' inline default trivial{{$}}
// CHECK-NEXT: | `-CompoundStmt 0x{{.+}} <col:31>{{$}}
// CHECK-NEXT: |-CXXConstructorDecl 0x{{.+}} <col:31> col:31 implicit constexpr TestClassTemplate 'void (const TestClassTemplate<A> &)' inline default trivial noexcept-unevaluated 0x{{.+}}{{$}}
// CHECK-NEXT: | `-ParmVarDecl 0x{{.+}} <col:31> col:31 'const TestClassTemplate<A> &'{{$}}
// CHECK-NEXT: `-CXXConstructorDecl 0x{{.+}} <col:31> col:31 implicit constexpr TestClassTemplate 'void (TestClassTemplate<A> &&)' inline default trivial noexcept-unevaluated 0x{{.+}}{{$}}
// CHECK-NEXT: `-ParmVarDecl 0x{{.+}} <col:31> col:31 'TestClassTemplate<A> &&'{{$}}
// CHECK-NEXT: |-CXXConstructorDecl 0x{{.+}} <col:31> col:31 implicit constexpr TestClassTemplate 'void (const TestClassTemplate<testCanonicalTemplate::A> &)' inline default trivial noexcept-unevaluated 0x{{.+}}{{$}}
// CHECK-NEXT: | `-ParmVarDecl 0x{{.+}} <col:31> col:31 'const TestClassTemplate<testCanonicalTemplate::A> &'{{$}}
// CHECK-NEXT: `-CXXConstructorDecl 0x{{.+}} <col:31> col:31 implicit constexpr TestClassTemplate 'void (TestClassTemplate<testCanonicalTemplate::A> &&)' inline default trivial noexcept-unevaluated 0x{{.+}}{{$}}
// CHECK-NEXT: `-ParmVarDecl 0x{{.+}} <col:31> col:31 'TestClassTemplate<testCanonicalTemplate::A> &&'{{$}}
template<typename T1> class TestClassTemplate2;
@ -682,10 +682,10 @@ namespace testCanonicalTemplate {
// CHECK-NEXT: |-CXXRecordDecl 0x{{.+}} <col:25, col:31> col:31 implicit class TestClassTemplate2{{$}}
// CHECK-NEXT: |-CXXConstructorDecl 0x{{.+}} <col:31> col:31 implicit used constexpr TestClassTemplate2 'void () noexcept' inline default trivial{{$}}
// CHECK-NEXT: | `-CompoundStmt 0x{{.+}} <col:31>{{$}}
// CHECK-NEXT: |-CXXConstructorDecl 0x{{.+}} <col:31> col:31 implicit constexpr TestClassTemplate2 'void (const TestClassTemplate2<A> &)' inline default trivial noexcept-unevaluated 0x{{.+}}{{$}}
// CHECK-NEXT: | `-ParmVarDecl 0x{{.+}} <col:31> col:31 'const TestClassTemplate2<A> &'{{$}}
// CHECK-NEXT: `-CXXConstructorDecl 0x{{.+}} <col:31> col:31 implicit constexpr TestClassTemplate2 'void (TestClassTemplate2<A> &&)' inline default trivial noexcept-unevaluated 0x{{.+}}{{$}}
// CHECK-NEXT: `-ParmVarDecl 0x{{.+}} <col:31> col:31 'TestClassTemplate2<A> &&'{{$}}
// CHECK-NEXT: |-CXXConstructorDecl 0x{{.+}} <col:31> col:31 implicit constexpr TestClassTemplate2 'void (const TestClassTemplate2<testCanonicalTemplate::A> &)' inline default trivial noexcept-unevaluated 0x{{.+}}{{$}}
// CHECK-NEXT: | `-ParmVarDecl 0x{{.+}} <col:31> col:31 'const TestClassTemplate2<testCanonicalTemplate::A> &'{{$}}
// CHECK-NEXT: `-CXXConstructorDecl 0x{{.+}} <col:31> col:31 implicit constexpr TestClassTemplate2 'void (TestClassTemplate2<testCanonicalTemplate::A> &&)' inline default trivial noexcept-unevaluated 0x{{.+}}{{$}}
// CHECK-NEXT: `-ParmVarDecl 0x{{.+}} <col:31> col:31 'TestClassTemplate2<testCanonicalTemplate::A> &&'{{$}}
// CHECK: ClassTemplateDecl 0x{{.+}} prev 0x{{.+}} <{{.+}}:[[@LINE-26]]:3, col:31> col:31 TestClassTemplate2{{$}}
// CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <col:12, col:21> col:21 typename depth 0 index 0 T1{{$}}

View File

@ -229,11 +229,10 @@ void PostfixExpressions(S a, S *p, U<int> *r) {
// CHECK-NEXT: ImplicitCastExpr
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:3> 'S *' lvalue ParmVar 0x{{[^ ]*}} 'p' 'S *'
// FIXME: there is no mention that this used the template keyword.
r->template U<int>::~U();
// CHECK: CXXMemberCallExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:26> 'void'
// CHECK-NEXT: MemberExpr 0x{{[^ ]*}} <col:3, col:24> '<bound member function type>' ->~U 0x{{[^ ]*}}
// CHECK-NEXT: NestedNameSpecifier TypeSpecWithTemplate 'template U<int>':'U<int>'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'template U<int>':'U<int>'
// CHECK-NEXT: ImplicitCastExpr
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:3> 'U<int> *' lvalue ParmVar 0x{{[^ ]*}} 'r' 'U<int> *'

View File

@ -174,7 +174,7 @@ namespace TestDependentMemberPointer {
// DUMP-NEXT: | `-BuiltinType {{.+}} 'int'
// DUMP-NEXT: `-TypeAliasDecl {{.+}} Z 'int U::template V<int>::*'{{$}}
// DUMP-NEXT: `-MemberPointerType {{.+}} 'int U::template V<int>::*' dependent
// DUMP-NEXT: |-DependentTemplateSpecializationType {{.+}} 'U::template V<int>' dependent
// DUMP-NEXT: |-DependentTemplateSpecializationType {{.+}} 'template V<int>' dependent
// DUMP-NEXT: `-BuiltinType {{.+}} 'int'
} // namespace TestDependentMemberPointer
@ -6588,7 +6588,7 @@ namespace TestDependentMemberPointer {
// JSON-NEXT: "tokLen": 9
// JSON-NEXT: },
// JSON-NEXT: "end": {
// JSON-NEXT: "offset": 6359,
// JSON-NEXT: "offset": 6356,
// JSON-NEXT: "line": 179,
// JSON-NEXT: "col": 1,
// JSON-NEXT: "tokLen": 1
@ -6896,7 +6896,7 @@ namespace TestDependentMemberPointer {
// JSON-NEXT: "id": "0x{{.*}}",
// JSON-NEXT: "kind": "DependentTemplateSpecializationType",
// JSON-NEXT: "type": {
// JSON-NEXT: "qualType": "U::template V<int>"
// JSON-NEXT: "qualType": "template V<int>"
// JSON-NEXT: },
// JSON-NEXT: "isDependent": true,
// JSON-NEXT: "isInstantiationDependent": true

View File

@ -92,7 +92,7 @@ namespace test3 {
template <class T> class Outer::A<T, typename T::nature> {
public:
static void foo(); // expected-note {{'Outer::A<B, Green>::foo' declared here}}
static void foo(); // expected-note {{'Outer::A<test3::B, test3::Green>::foo' declared here}}
};
class B {
@ -102,7 +102,7 @@ namespace test3 {
void test() {
Outer::A<B, Green>::foo();
Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo' in 'test3::Outer::A<test3::B, test3::Blue>'; did you mean 'Outer::A<B, Green>::foo'?}}
Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo' in 'test3::Outer::A<test3::B, test3::Blue>'; did you mean 'Outer::A<test3::B, test3::Green>::foo'?}}
}
}

View File

@ -98,8 +98,8 @@ public:
void foo() { Templ<Derived> x(&Derived::func); }
// expected-error@-1 {{no matching constructor for initialization of 'Templ<Derived>'}}
// expected-note@#cwg203-ex3-Templ {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int (Derived::*)() const' (aka 'int (Base::*)() const') to 'const Templ<Derived>' for 1st argument}}
// since-cxx11-note@#cwg203-ex3-Templ {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int (Derived::*)() const' (aka 'int (Base::*)() const') to 'Templ<Derived>' for 1st argument}}
// expected-note@#cwg203-ex3-Templ {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int (Derived::*)() const' (aka 'int (Base::*)() const') to 'const Templ<cwg203::ex3::Derived>' for 1st argument}}
// since-cxx11-note@#cwg203-ex3-Templ {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int (Derived::*)() const' (aka 'int (Base::*)() const') to 'Templ<cwg203::ex3::Derived>' for 1st argument}}
// expected-note@#cwg203-ex3-Templ-ctor {{candidate template ignored: could not match 'cwg203::ex3::Derived' against 'cwg203::ex3::Base'}}
} // namespace ex3

View File

@ -150,7 +150,7 @@ void func() {
// expected-note@#bar {{while substituting template arguments into constraint expression here}}
// expected-note@#bar {{while checking the satisfaction of nested requirement requested here}}
// expected-note@#bar {{candidate template ignored: constraints not satisfied [with T = False]}}
// expected-note@#bar {{because 'X<False>::value' evaluated to false}}
// expected-note@#bar {{because 'X<SubstitutionFailureNestedRequires::ErrorExpressions_NotSF::False>::value' evaluated to false}}
bar<int>();
// expected-note@-1 {{while checking constraint satisfaction for template 'bar<int>' required here}} \

View File

@ -196,8 +196,10 @@ struct NestedTemplates1 {
template <typename T, typename U, int a>
void foo2() {
// FIXME: Here the template keyword is dropped because the failed condition
// for a static assert is always printed with canonical types.
static_assert(::ns::NestedTemplates1<T, a>::NestedTemplates2::template NestedTemplates3<U>::value, "message");
// expected-error@-1{{static assertion failed due to requirement '::ns::NestedTemplates1<int, 3>::NestedTemplates2::template NestedTemplates3<float>::value': message}}
// expected-error@-1{{static assertion failed due to requirement '::ns::NestedTemplates1<int, 3>::NestedTemplates2::NestedTemplates3<float>::value': message}}
}
template void foo2<int, float, 3>();
// expected-note@-1{{in instantiation of function template specialization 'foo2<int, float, 3>' requested here}}

View File

@ -331,7 +331,7 @@ namespace DeduceArity {
// CHECK: | |-ParmVarDecl {{.*}} 'Types<T...>'
// CHECK: | `-ParmVarDecl {{.*}} 'T...' pack
// CHECK: |-CXXDeductionGuideDecl {{.*}} implicit used <deduction guide for F>
// CHECK-SAME: 'auto (Types<X, Y, Z>, DeduceArity::X, DeduceArity::Y, DeduceArity::Z) ->
// CHECK-SAME: 'auto (Types<DeduceArity::X, DeduceArity::Y, DeduceArity::Z>, DeduceArity::X, DeduceArity::Y, DeduceArity::Z) ->
// CHECK-SAME: DeduceArity::F<DeduceArity::X, DeduceArity::Y, DeduceArity::Z>'
// CHECK: | |-TemplateArgument pack
// CHECK: | | |-TemplateArgument type 'DeduceArity::X'
@ -343,16 +343,16 @@ namespace DeduceArity {
// CHECK: | | `-TemplateArgument type 'DeduceArity::Z'
// CHECK: | | `-RecordType {{.*}} 'DeduceArity::Z'
// CHECK: | | `-CXXRecord {{.*}} 'Z'
// CHECK: | |-ParmVarDecl {{.*}} 'Types<X, Y, Z>':'DeduceArity::Types<DeduceArity::X, DeduceArity::Y, DeduceArity::Z>'
// CHECK: | |-ParmVarDecl {{.*}} 'Types<DeduceArity::X, DeduceArity::Y, DeduceArity::Z>':'DeduceArity::Types<DeduceArity::X, DeduceArity::Y, DeduceArity::Z>'
// CHECK: | |-ParmVarDecl {{.*}} 'DeduceArity::X'
// CHECK: | |-ParmVarDecl {{.*}} 'DeduceArity::Y'
// CHECK: | `-ParmVarDecl {{.*}} 'DeduceArity::Z'
// CHECK: `-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for F> 'auto (Types<X>, DeduceArity::X) -> DeduceArity::F<DeduceArity::X>'
// CHECK: `-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for F> 'auto (Types<DeduceArity::X>, DeduceArity::X) -> DeduceArity::F<DeduceArity::X>'
// CHECK: |-TemplateArgument pack
// CHECK: | `-TemplateArgument type 'DeduceArity::X'
// CHECK: | `-RecordType {{.*}} 'DeduceArity::X'
// CHECK: | `-CXXRecord {{.*}} 'X'
// CHECK: |-ParmVarDecl {{.*}} 'Types<X>':'DeduceArity::Types<DeduceArity::X>'
// CHECK: |-ParmVarDecl {{.*}} 'Types<DeduceArity::X>':'DeduceArity::Types<DeduceArity::X>'
// CHECK: `-ParmVarDecl {{.*}} 'DeduceArity::X'
// CHECK: FunctionProtoType {{.*}} 'auto (Types<T...>, T...) -> F<T...>' dependent trailing_return cdecl
// CHECK: |-InjectedClassNameType {{.*}} 'F<T...>' dependent

View File

@ -134,3 +134,21 @@ namespace PR9401 {
const D<typename C<S, T>::template B<U>::template E<D<F> > >
A<S, T>::B<U>::a = typename C<S, T>::template B<U>::template E<D<F> >(g);
}
namespace templ_spec {
template <class U> using A = void; // expected-note 2{{template parameter is declared here}}
template <class T> struct B {
A<typename T::template X<int>> t1;
// expected-error@-1 {{'A<typename T::template X<int>>' (aka 'void')}}
A<typename T::X<int>> t2; // expected-error {{use 'template' keyword}}
// expected-error@-1 {{'A<typename T::X<int>>' (aka 'void')}}
// FIXME: Why error recovery for the non-typename case is so bad?
A<T::template X<int>> t3; // expected-error {{did you forget 'typename'}}
// expected-error@-1 {{'A<typename T::X>' (aka 'void')}}
A<T::X<int>> t4; // expected-error {{use 'template' keyword}} expected-error {{did you forget 'typename'}}
// expected-error@-1 {{'A<typename T::X>' (aka 'void')}}
};
} // namespace templ_spec

View File

@ -72,8 +72,8 @@ namespace type_requirement {
template<typename T> requires
false_v<requires { typename T::template temp<T>; }>
// expected-note@-1 {{because 'false_v<requires { typename contains_template<int>::template temp<contains_template<int> >; }>' evaluated to false}}
// expected-note@-2 {{because 'false_v<requires { typename contains_template<short>::template temp<contains_template<short> >; }>' evaluated to false}}
// expected-note@-1 {{because 'false_v<requires { typename contains_template<int>::template temp<type_requirement::contains_template<int> >; }>' evaluated to false}}
// expected-note@-2 {{because 'false_v<requires { typename contains_template<short>::template temp<type_requirement::contains_template<short> >; }>' evaluated to false}}
struct r2 {};
using r2i1 = r2<contains_template<int>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<int>]}}

View File

@ -1457,7 +1457,6 @@ bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS,
break;
}
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Super:
@ -1492,7 +1491,6 @@ bool CursorVisitor::VisitNestedNameSpecifierLoc(
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
if (Visit(Q.getTypeLoc()))
return true;

View File

@ -61,7 +61,7 @@ using E = test<std::array<NotALiteral, 1>{}>;
// expected-error@-1 {{non-type template parameter has non-literal type 'std::array<NotALiteral, 1>'}}
using F = test<std::array<std::string, 2>{}>;
// expected-error@-1 {{type 'std::array<string, 2>' (aka 'std::array<std::string, 2>') of non-type template parameter is not a structural type}}
// expected-error-re@-1 {{type 'std::array<{{(std::)?}}string, 2>'{{( \(aka 'std::array<std::string, 2>'\))?}} of non-type template parameter is not a structural type}}
} // namespace test_ctad
namespace test_auto {

View File

@ -26,7 +26,7 @@ int main(int, char**) {
// expected-error-re@*:* {{static assertion failed due to requirement {{.*}}std::shared_ptr<> is not supported}}
std::ignore = std::inout_ptr(sPtr);
// expected-error@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr<int>' to 'std::inout_ptr_t<shared_ptr<int>, _Ptr>' (aka 'inout_ptr_t<std::shared_ptr<int>, int *>'}}
// expected-error-re@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr<int>' to 'std::inout_ptr_t<{{(std::)?}}shared_ptr<int>, _Ptr>'{{( \(aka 'inout_ptr_t<std::shared_ptr<int>, int *>')?}}}}
std::ignore = std::inout_ptr<int*>(sPtr);
}

View File

@ -26,7 +26,7 @@ int main(int, char**) {
// expected-error-re@*:* {{static assertion failed due to requirement {{.*}}Using std::shared_ptr<> without a deleter in std::out_ptr is not supported.}}
std::ignore = std::out_ptr(sPtr);
// expected-error@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr<int>' to 'std::out_ptr_t<shared_ptr<int>, _Ptr>' (aka 'out_ptr_t<std::shared_ptr<int>, int *>')}}
// expected-error-re@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr<int>' to 'std::out_ptr_t<{{(std::)?}}shared_ptr<int>, _Ptr>'{{( \(aka 'out_ptr_t<std::shared_ptr<int>, int *>'\))?}}}}
std::ignore = std::out_ptr<int*>(sPtr);
}

View File

@ -74,7 +74,7 @@ using H = test<std::pair<NotALiteral, NotALiteral>{}>;
// expected-error@-1 {{non-type template parameter has non-literal type 'std::pair<NotALiteral, NotALiteral>'}}
using I = test<std::pair<std::string, std::string>{}>;
// expected-error@-1 {{type 'std::pair<string, string>' (aka 'std::pair<std::string, std::string>') of non-type template parameter is not a structural type}}
// expected-error-re@-1 {{type 'std::pair<{{(std::)?}}string, {{(std::)?}}string>'{{( \(aka 'std::pair<std::string, std::string>'\))?}} of non-type template parameter is not a structural type}}
} // namespace test_ctad
namespace test_auto {