зеркало из https://github.com/microsoft/clang.git
Create a new InjectedClassNameType to represent bare-word references to the
injected class name of a class template or class template partial specialization. This is a non-canonical type; the canonical type is still a template specialization type. This becomes the TypeForDecl of the pattern declaration, which cleans up some amount of code (and complicates some other parts, but whatever). Fixes PR6326 and probably a few others, primarily by re-establishing a few invariants about TypeLoc sizes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98134 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
d7fdae5ea0
Коммит
3cb0ebd5f7
|
@ -586,6 +586,8 @@ public:
|
|||
/// specified typename decl.
|
||||
QualType getTypedefType(const TypedefDecl *Decl);
|
||||
|
||||
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST);
|
||||
|
||||
QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced,
|
||||
QualType Replacement);
|
||||
|
||||
|
@ -602,6 +604,11 @@ public:
|
|||
const TemplateArgumentListInfo &Args,
|
||||
QualType Canon = QualType());
|
||||
|
||||
TypeSourceInfo *
|
||||
getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc,
|
||||
const TemplateArgumentListInfo &Args,
|
||||
QualType Canon = QualType());
|
||||
|
||||
QualType getQualifiedNameType(NestedNameSpecifier *NNS,
|
||||
QualType NamedType);
|
||||
QualType getTypenameType(NestedNameSpecifier *NNS,
|
||||
|
|
|
@ -1429,7 +1429,6 @@ class TypeDecl : public NamedDecl {
|
|||
friend class DeclContext;
|
||||
friend class TagDecl;
|
||||
friend class TemplateTypeParmDecl;
|
||||
friend class ClassTemplateSpecializationDecl;
|
||||
friend class TagType;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -771,6 +771,10 @@ class ClassTemplateSpecializationDecl
|
|||
llvm::PointerUnion<ClassTemplateDecl *, SpecializedPartialSpecialization *>
|
||||
SpecializedTemplate;
|
||||
|
||||
/// \brief The type-as-written of an explicit template specialization.
|
||||
/// Does not apply to implicit specializations.
|
||||
TypeSourceInfo *TypeAsWritten;
|
||||
|
||||
/// \brief The template arguments used to describe this specialization.
|
||||
TemplateArgumentList TemplateArgs;
|
||||
|
||||
|
@ -883,8 +887,14 @@ public:
|
|||
|
||||
/// \brief Sets the type of this specialization as it was written by
|
||||
/// the user. This will be a class template specialization type.
|
||||
void setTypeAsWritten(QualType T) {
|
||||
TypeForDecl = T.getTypePtr();
|
||||
void setTypeAsWritten(TypeSourceInfo *T) {
|
||||
TypeAsWritten = T;
|
||||
}
|
||||
|
||||
/// \brief Gets the type of this specialization as it was written by
|
||||
/// the user, if it was so written.
|
||||
TypeSourceInfo *getTypeAsWritten() const {
|
||||
return TypeAsWritten;
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
|
@ -921,6 +931,7 @@ class ClassTemplatePartialSpecializationDecl
|
|||
TemplateParameterList* TemplateParams;
|
||||
|
||||
/// \brief The source info for the template arguments as written.
|
||||
/// FIXME: redundant with TypeAsWritten?
|
||||
TemplateArgumentLoc *ArgsAsWritten;
|
||||
unsigned NumArgsAsWritten;
|
||||
|
||||
|
@ -954,6 +965,7 @@ public:
|
|||
ClassTemplateDecl *SpecializedTemplate,
|
||||
TemplateArgumentListBuilder &Builder,
|
||||
const TemplateArgumentListInfo &ArgInfos,
|
||||
QualType CanonInjectedType,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl);
|
||||
|
||||
/// Get the list of template parameters
|
||||
|
@ -1139,8 +1151,8 @@ public:
|
|||
/// the type \p T, or NULL if no such partial specialization exists.
|
||||
ClassTemplatePartialSpecializationDecl *findPartialSpecialization(QualType T);
|
||||
|
||||
/// \brief Retrieve the type of the injected-class-name for this
|
||||
/// class template.
|
||||
/// \brief Retrieve the template specialization type of the
|
||||
/// injected-class-name for this class template.
|
||||
///
|
||||
/// The injected-class-name for a class template \c X is \c
|
||||
/// X<template-args>, where \c template-args is formed from the
|
||||
|
@ -1153,7 +1165,7 @@ public:
|
|||
/// typedef array this_type; // "array" is equivalent to "array<T, N>"
|
||||
/// };
|
||||
/// \endcode
|
||||
QualType getInjectedClassNameType(ASTContext &Context);
|
||||
QualType getInjectedClassNameSpecialization(ASTContext &Context);
|
||||
|
||||
/// \brief Retrieve the member class template that this class template was
|
||||
/// derived from.
|
||||
|
|
|
@ -2440,6 +2440,47 @@ public:
|
|||
static bool classof(const TemplateSpecializationType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief The injected class name of a C++ class template. Used to
|
||||
/// record that a type was spelled with a bare identifier rather than
|
||||
/// as a template-id; the equivalent for non-templated classes is just
|
||||
/// RecordType.
|
||||
///
|
||||
/// For consistency, template instantiation turns these into RecordTypes.
|
||||
///
|
||||
/// The desugared form is always a unqualified TemplateSpecializationType.
|
||||
/// The canonical form is always either a TemplateSpecializationType
|
||||
/// (when dependent) or a RecordType (otherwise).
|
||||
class InjectedClassNameType : public Type {
|
||||
CXXRecordDecl *Decl;
|
||||
|
||||
QualType UnderlyingType;
|
||||
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
InjectedClassNameType(CXXRecordDecl *D, QualType TST, QualType Canon)
|
||||
: Type(InjectedClassName, Canon, Canon->isDependentType()),
|
||||
Decl(D), UnderlyingType(TST) {
|
||||
assert(isa<TemplateSpecializationType>(TST));
|
||||
assert(!TST.hasQualifiers());
|
||||
assert(TST->getCanonicalTypeInternal() == Canon);
|
||||
}
|
||||
|
||||
public:
|
||||
QualType getUnderlyingType() const { return UnderlyingType; }
|
||||
const TemplateSpecializationType *getUnderlyingTST() const {
|
||||
return cast<TemplateSpecializationType>(UnderlyingType.getTypePtr());
|
||||
}
|
||||
|
||||
CXXRecordDecl *getDecl() const { return Decl; }
|
||||
|
||||
bool isSugared() const { return true; }
|
||||
QualType desugar() const { return UnderlyingType; }
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == InjectedClassName;
|
||||
}
|
||||
static bool classof(const InjectedClassNameType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Represents a type that was referred to via a qualified
|
||||
/// name, e.g., N::M::type.
|
||||
///
|
||||
|
|
|
@ -488,6 +488,14 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for injected class names of class
|
||||
/// templates.
|
||||
class InjectedClassNameTypeLoc :
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
InjectedClassNameTypeLoc,
|
||||
InjectedClassNameType> {
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for unresolved typename using decls.
|
||||
class UnresolvedUsingTypeLoc :
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
|
|
|
@ -91,6 +91,7 @@ DEPENDENT_TYPE(TemplateTypeParm, Type)
|
|||
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
|
||||
NON_CANONICAL_TYPE(QualifiedName, Type)
|
||||
NON_CANONICAL_TYPE(InjectedClassName, Type)
|
||||
DEPENDENT_TYPE(Typename, Type)
|
||||
TYPE(ObjCInterface, Type)
|
||||
TYPE(ObjCObjectPointer, Type)
|
||||
|
|
|
@ -408,7 +408,9 @@ namespace clang {
|
|||
/// \brief A SubstTemplateTypeParmType record.
|
||||
TYPE_SUBST_TEMPLATE_TYPE_PARM = 25,
|
||||
/// \brief An UnresolvedUsingType record.
|
||||
TYPE_UNRESOLVED_USING = 26
|
||||
TYPE_UNRESOLVED_USING = 26,
|
||||
/// \brief An InjectedClassNameType record.
|
||||
TYPE_INJECTED_CLASS_NAME = 27
|
||||
};
|
||||
|
||||
/// \brief The type IDs for special types constructed by semantic
|
||||
|
|
|
@ -888,6 +888,10 @@ ASTContext::getTypeInfo(const Type *T) {
|
|||
case Type::QualifiedName:
|
||||
return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
|
||||
|
||||
case Type::InjectedClassName:
|
||||
return getTypeInfo(cast<InjectedClassNameType>(T)
|
||||
->getUnderlyingType().getTypePtr());
|
||||
|
||||
case Type::TemplateSpecialization:
|
||||
assert(getCanonicalType(T) != T &&
|
||||
"Cannot request the size of a dependent type");
|
||||
|
@ -1918,6 +1922,39 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
|
|||
return QualType(FTP, 0);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static bool NeedsInjectedClassNameType(const RecordDecl *D) {
|
||||
if (!isa<CXXRecordDecl>(D)) return false;
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(D);
|
||||
if (isa<ClassTemplatePartialSpecializationDecl>(RD))
|
||||
return true;
|
||||
if (RD->getDescribedClassTemplate() &&
|
||||
!isa<ClassTemplateSpecializationDecl>(RD))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// getInjectedClassNameType - Return the unique reference to the
|
||||
/// injected class name type for the specified templated declaration.
|
||||
QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl,
|
||||
QualType TST) {
|
||||
assert(NeedsInjectedClassNameType(Decl));
|
||||
if (Decl->TypeForDecl) {
|
||||
assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
|
||||
} else if (CXXRecordDecl *PrevDecl
|
||||
= cast_or_null<CXXRecordDecl>(Decl->getPreviousDeclaration())) {
|
||||
assert(PrevDecl->TypeForDecl && "previous declaration has no type");
|
||||
Decl->TypeForDecl = PrevDecl->TypeForDecl;
|
||||
assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
|
||||
} else {
|
||||
Decl->TypeForDecl = new (*this, TypeAlignment)
|
||||
InjectedClassNameType(Decl, TST, TST->getCanonicalTypeInternal());
|
||||
Types.push_back(Decl->TypeForDecl);
|
||||
}
|
||||
return QualType(Decl->TypeForDecl, 0);
|
||||
}
|
||||
|
||||
/// getTypeDeclType - Return the unique reference to the type for the
|
||||
/// specified type declaration.
|
||||
QualType ASTContext::getTypeDeclType(const TypeDecl *Decl,
|
||||
|
@ -1936,8 +1973,10 @@ QualType ASTContext::getTypeDeclType(const TypeDecl *Decl,
|
|||
if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
|
||||
if (PrevDecl)
|
||||
Decl->TypeForDecl = PrevDecl->TypeForDecl;
|
||||
else
|
||||
else {
|
||||
assert(!NeedsInjectedClassNameType(Record));
|
||||
Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Record);
|
||||
}
|
||||
} else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
|
||||
if (PrevDecl)
|
||||
Decl->TypeForDecl = PrevDecl->TypeForDecl;
|
||||
|
@ -2022,6 +2061,24 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
|||
return QualType(TypeParm, 0);
|
||||
}
|
||||
|
||||
TypeSourceInfo *
|
||||
ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
|
||||
SourceLocation NameLoc,
|
||||
const TemplateArgumentListInfo &Args,
|
||||
QualType CanonType) {
|
||||
QualType TST = getTemplateSpecializationType(Name, Args, CanonType);
|
||||
|
||||
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
|
||||
TemplateSpecializationTypeLoc TL
|
||||
= cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc());
|
||||
TL.setTemplateNameLoc(NameLoc);
|
||||
TL.setLAngleLoc(Args.getLAngleLoc());
|
||||
TL.setRAngleLoc(Args.getRAngleLoc());
|
||||
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
|
||||
TL.setArgLocInfo(i, Args[i].getLocInfo());
|
||||
return DI;
|
||||
}
|
||||
|
||||
QualType
|
||||
ASTContext::getTemplateSpecializationType(TemplateName Template,
|
||||
const TemplateArgumentListInfo &Args,
|
||||
|
|
|
@ -56,6 +56,12 @@ static bool ShouldAKA(ASTContext &Context, QualType QT,
|
|||
QT = cast<QualifiedNameType>(Ty)->desugar();
|
||||
continue;
|
||||
}
|
||||
|
||||
// ...or an injected class name...
|
||||
if (isa<InjectedClassNameType>(Ty)) {
|
||||
QT = cast<InjectedClassNameType>(Ty)->desugar();
|
||||
continue;
|
||||
}
|
||||
|
||||
// ...or a substituted template type parameter.
|
||||
if (isa<SubstTemplateTypeParmType>(Ty)) {
|
||||
|
|
|
@ -610,6 +610,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|||
break;
|
||||
}
|
||||
|
||||
case Type::InjectedClassName: {
|
||||
const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1);
|
||||
const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2);
|
||||
if (!IsStructurallyEquivalent(Context,
|
||||
Inj1->getUnderlyingType(),
|
||||
Inj2->getUnderlyingType()))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Typename: {
|
||||
const TypenameType *Typename1 = cast<TypenameType>(T1);
|
||||
const TypenameType *Typename2 = cast<TypenameType>(T2);
|
||||
|
|
|
@ -574,11 +574,22 @@ DeclContext *DeclContext::getPrimaryContext() {
|
|||
if (DeclKind >= Decl::TagFirst && DeclKind <= Decl::TagLast) {
|
||||
// If this is a tag type that has a definition or is currently
|
||||
// being defined, that definition is our primary context.
|
||||
if (const TagType *TagT =cast<TagDecl>(this)->TypeForDecl->getAs<TagType>())
|
||||
if (TagT->isBeingDefined() ||
|
||||
(TagT->getDecl() && TagT->getDecl()->isDefinition()))
|
||||
return TagT->getDecl();
|
||||
return this;
|
||||
TagDecl *Tag = cast<TagDecl>(this);
|
||||
assert(isa<TagType>(Tag->TypeForDecl) ||
|
||||
isa<InjectedClassNameType>(Tag->TypeForDecl));
|
||||
|
||||
if (TagDecl *Def = Tag->getDefinition())
|
||||
return Def;
|
||||
|
||||
if (!isa<InjectedClassNameType>(Tag->TypeForDecl)) {
|
||||
const TagType *TagTy = cast<TagType>(Tag->TypeForDecl);
|
||||
if (TagTy->isBeingDefined())
|
||||
// FIXME: is it necessarily being defined in the decl
|
||||
// that owns the type?
|
||||
return TagTy->getDecl();
|
||||
}
|
||||
|
||||
return Tag;
|
||||
}
|
||||
|
||||
assert(DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast &&
|
||||
|
|
|
@ -636,11 +636,16 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
|
|||
|
||||
assert(isInstance() && "No 'this' for static methods!");
|
||||
|
||||
QualType ClassTy;
|
||||
if (ClassTemplateDecl *TD = getParent()->getDescribedClassTemplate())
|
||||
ClassTy = TD->getInjectedClassNameType(C);
|
||||
else
|
||||
ClassTy = C.getTagDeclType(getParent());
|
||||
QualType ClassTy = C.getTypeDeclType(getParent());
|
||||
|
||||
// Aesthetically we prefer not to synthesize a type as the
|
||||
// InjectedClassNameType of a template pattern: injected class names
|
||||
// are printed without template arguments, which might
|
||||
// surprise/confuse/distract our poor users if they didn't
|
||||
// explicitly write one.
|
||||
if (isa<InjectedClassNameType>(ClassTy))
|
||||
ClassTy = cast<InjectedClassNameType>(ClassTy)->getUnderlyingType();
|
||||
|
||||
ClassTy = C.getQualifiedType(ClassTy,
|
||||
Qualifiers::fromCVRMask(getTypeQualifiers()));
|
||||
return C.getPointerType(ClassTy);
|
||||
|
|
|
@ -193,7 +193,8 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
|
||||
QualType
|
||||
ClassTemplateDecl::getInjectedClassNameSpecialization(ASTContext &Context) {
|
||||
if (!CommonPtr->InjectedClassNameType.isNull())
|
||||
return CommonPtr->InjectedClassNameType;
|
||||
|
||||
|
@ -393,6 +394,7 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
|
|||
SpecializedTemplate->getIdentifier(),
|
||||
PrevDecl),
|
||||
SpecializedTemplate(SpecializedTemplate),
|
||||
TypeAsWritten(0),
|
||||
TemplateArgs(Context, Builder, /*TakeArgs=*/true),
|
||||
SpecializationKind(TSK_Undeclared) {
|
||||
}
|
||||
|
@ -453,6 +455,7 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
|
|||
ClassTemplateDecl *SpecializedTemplate,
|
||||
TemplateArgumentListBuilder &Builder,
|
||||
const TemplateArgumentListInfo &ArgInfos,
|
||||
QualType CanonInjectedType,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl) {
|
||||
unsigned N = ArgInfos.size();
|
||||
TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
|
||||
|
@ -467,7 +470,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
|
|||
ClonedArgs, N,
|
||||
PrevDecl);
|
||||
Result->setSpecializationKind(TSK_ExplicitSpecialization);
|
||||
Context.getTypeDeclType(Result, PrevDecl);
|
||||
|
||||
Context.getInjectedClassNameType(Result, CanonInjectedType);
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace {
|
|||
explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { }
|
||||
|
||||
void Print(QualType T, std::string &S);
|
||||
void PrintTag(const TagType *T, std::string &S);
|
||||
void PrintTag(TagDecl *T, std::string &S);
|
||||
#define ABSTRACT_TYPE(CLASS, PARENT)
|
||||
#define TYPE(CLASS, PARENT) \
|
||||
void Print##CLASS(const CLASS##Type *T, std::string &S);
|
||||
|
@ -330,19 +330,21 @@ void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T,
|
|||
Print(T->getResultType(), S);
|
||||
}
|
||||
|
||||
void TypePrinter::PrintUnresolvedUsing(const UnresolvedUsingType *T,
|
||||
std::string &S) {
|
||||
IdentifierInfo *II = T->getDecl()->getIdentifier();
|
||||
static void PrintTypeSpec(const NamedDecl *D, std::string &S) {
|
||||
IdentifierInfo *II = D->getIdentifier();
|
||||
if (S.empty())
|
||||
S = II->getName().str();
|
||||
else
|
||||
S = II->getName().str() + ' ' + S;
|
||||
}
|
||||
|
||||
void TypePrinter::PrintUnresolvedUsing(const UnresolvedUsingType *T,
|
||||
std::string &S) {
|
||||
PrintTypeSpec(T->getDecl(), S);
|
||||
}
|
||||
|
||||
void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) {
|
||||
if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
S = ' ' + S;
|
||||
S = T->getDecl()->getIdentifier()->getName().str() + S;
|
||||
PrintTypeSpec(T->getDecl(), S);
|
||||
}
|
||||
|
||||
void TypePrinter::PrintTypeOfExpr(const TypeOfExprType *T, std::string &S) {
|
||||
|
@ -371,18 +373,18 @@ void TypePrinter::PrintDecltype(const DecltypeType *T, std::string &S) {
|
|||
S = "decltype(" + s.str() + ")" + S;
|
||||
}
|
||||
|
||||
void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) {
|
||||
void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
|
||||
if (Policy.SuppressTag)
|
||||
return;
|
||||
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
|
||||
const char *Kind = Policy.SuppressTagKind? 0 : T->getDecl()->getKindName();
|
||||
const char *Kind = Policy.SuppressTagKind? 0 : D->getKindName();
|
||||
const char *ID;
|
||||
if (const IdentifierInfo *II = T->getDecl()->getIdentifier())
|
||||
if (const IdentifierInfo *II = D->getIdentifier())
|
||||
ID = II->getNameStart();
|
||||
else if (TypedefDecl *Typedef = T->getDecl()->getTypedefForAnonDecl()) {
|
||||
else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) {
|
||||
Kind = 0;
|
||||
assert(Typedef->getIdentifier() && "Typedef without identifier?");
|
||||
ID = Typedef->getIdentifier()->getNameStart();
|
||||
|
@ -392,13 +394,22 @@ void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) {
|
|||
// If this is a class template specialization, print the template
|
||||
// arguments.
|
||||
if (ClassTemplateSpecializationDecl *Spec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) {
|
||||
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(D)) {
|
||||
const TemplateArgument *Args;
|
||||
unsigned NumArgs;
|
||||
if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) {
|
||||
const TemplateSpecializationType *TST =
|
||||
cast<TemplateSpecializationType>(TAW->getType());
|
||||
Args = TST->getArgs();
|
||||
NumArgs = TST->getNumArgs();
|
||||
} else {
|
||||
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
|
||||
Args = TemplateArgs.getFlatArgumentList();
|
||||
NumArgs = TemplateArgs.flat_size();
|
||||
}
|
||||
std::string TemplateArgsStr
|
||||
= TemplateSpecializationType::PrintTemplateArgumentList(
|
||||
TemplateArgs.getFlatArgumentList(),
|
||||
TemplateArgs.flat_size(),
|
||||
Policy);
|
||||
= TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs,
|
||||
Policy);
|
||||
InnerString = TemplateArgsStr + InnerString;
|
||||
}
|
||||
|
||||
|
@ -406,7 +417,7 @@ void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) {
|
|||
// Compute the full nested-name-specifier for this type. In C,
|
||||
// this will always be empty.
|
||||
std::string ContextStr;
|
||||
for (DeclContext *DC = T->getDecl()->getDeclContext();
|
||||
for (DeclContext *DC = D->getDeclContext();
|
||||
!DC->isTranslationUnit(); DC = DC->getParent()) {
|
||||
std::string MyPart;
|
||||
if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
|
||||
|
@ -441,11 +452,11 @@ void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) {
|
|||
}
|
||||
|
||||
void TypePrinter::PrintRecord(const RecordType *T, std::string &S) {
|
||||
PrintTag(T, S);
|
||||
PrintTag(T->getDecl(), S);
|
||||
}
|
||||
|
||||
void TypePrinter::PrintEnum(const EnumType *T, std::string &S) {
|
||||
PrintTag(T, S);
|
||||
PrintTag(T->getDecl(), S);
|
||||
}
|
||||
|
||||
void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
|
||||
|
@ -494,6 +505,12 @@ void TypePrinter::PrintTemplateSpecialization(
|
|||
S = SpecString + ' ' + S;
|
||||
}
|
||||
|
||||
void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T,
|
||||
std::string &S) {
|
||||
// TODO: this should probably be printed with template arguments
|
||||
PrintTag(T->getDecl(), S);
|
||||
}
|
||||
|
||||
void TypePrinter::PrintQualifiedName(const QualifiedNameType *T,
|
||||
std::string &S) {
|
||||
std::string MyString;
|
||||
|
|
|
@ -1246,6 +1246,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
|
|||
case Type::MemberPointer:
|
||||
return CreateType(cast<MemberPointerType>(Ty), Unit);
|
||||
|
||||
case Type::InjectedClassName:
|
||||
case Type::TemplateSpecialization:
|
||||
case Type::Elaborated:
|
||||
case Type::QualifiedName:
|
||||
|
|
|
@ -2018,6 +2018,12 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
|
|||
Context->getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm),
|
||||
Replacement);
|
||||
}
|
||||
|
||||
case pch::TYPE_INJECTED_CLASS_NAME: {
|
||||
CXXRecordDecl *D = cast<CXXRecordDecl>(GetDecl(Record[0]));
|
||||
QualType TST = GetType(Record[1]); // probably derivable
|
||||
return Context->getInjectedClassNameType(D, TST);
|
||||
}
|
||||
}
|
||||
// Suppress a GCC warning
|
||||
return QualType();
|
||||
|
@ -2172,6 +2178,9 @@ void TypeLocReader::VisitTemplateSpecializationTypeLoc(
|
|||
void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) {
|
||||
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
||||
}
|
||||
void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
|
||||
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
||||
}
|
||||
void TypeLocReader::VisitTypenameTypeLoc(TypenameTypeLoc TL) {
|
||||
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
||||
}
|
||||
|
|
|
@ -235,6 +235,12 @@ void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) {
|
|||
assert(false && "Cannot serialize qualified name types");
|
||||
}
|
||||
|
||||
void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
|
||||
Writer.AddDeclRef(T->getDecl(), Record);
|
||||
Writer.AddTypeRef(T->getUnderlyingType(), Record);
|
||||
Code = pch::TYPE_INJECTED_CLASS_NAME;
|
||||
}
|
||||
|
||||
void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
|
||||
Writer.AddDeclRef(T->getDecl(), Record);
|
||||
Record.push_back(T->getNumProtocols());
|
||||
|
@ -394,6 +400,9 @@ void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
|
|||
void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) {
|
||||
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
||||
}
|
||||
void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
|
||||
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
||||
}
|
||||
void TypeLocWriter::VisitTypenameTypeLoc(TypenameTypeLoc TL) {
|
||||
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
||||
}
|
||||
|
|
|
@ -76,14 +76,6 @@ getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext,
|
|||
// our context.
|
||||
if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T)
|
||||
return Record;
|
||||
|
||||
if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) {
|
||||
QualType InjectedClassName
|
||||
= Template->getInjectedClassNameType(Context);
|
||||
if (T == Context.getCanonicalType(InjectedClassName))
|
||||
return Template->getTemplatedDecl();
|
||||
}
|
||||
// FIXME: check for class template partial specializations
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -130,8 +122,11 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
|
|||
return Record;
|
||||
|
||||
if (EnteringContext) {
|
||||
if (const TemplateSpecializationType *SpecType
|
||||
= dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) {
|
||||
const Type *NNSType = NNS->getAsType();
|
||||
if (!NNSType) {
|
||||
// do nothing, fall out
|
||||
} else if (const TemplateSpecializationType *SpecType
|
||||
= NNSType->getAs<TemplateSpecializationType>()) {
|
||||
// We are entering the context of the nested name specifier, so try to
|
||||
// match the nested name specifier to either a primary class template
|
||||
// or a class template partial specialization.
|
||||
|
@ -144,7 +139,8 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
|
|||
// If the type of the nested name specifier is the same as the
|
||||
// injected class name of the named class template, we're entering
|
||||
// into that class template definition.
|
||||
QualType Injected = ClassTemplate->getInjectedClassNameType(Context);
|
||||
QualType Injected
|
||||
= ClassTemplate->getInjectedClassNameSpecialization(Context);
|
||||
if (Context.hasSameType(Injected, ContextType))
|
||||
return ClassTemplate->getTemplatedDecl();
|
||||
|
||||
|
@ -156,8 +152,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
|
|||
= ClassTemplate->findPartialSpecialization(ContextType))
|
||||
return PartialSpec;
|
||||
}
|
||||
} else if (const RecordType *RecordT
|
||||
= dyn_cast_or_null<RecordType>(NNS->getAsType())) {
|
||||
} else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) {
|
||||
// The nested name specifier refers to a member of a class template.
|
||||
return RecordT->getDecl();
|
||||
}
|
||||
|
@ -248,7 +243,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
|
|||
// If we're currently defining this type, then lookup into the
|
||||
// type is okay: don't complain that it isn't complete yet.
|
||||
const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>();
|
||||
if (TagT->isBeingDefined())
|
||||
if (TagT && TagT->isBeingDefined())
|
||||
return false;
|
||||
|
||||
// The type must be complete.
|
||||
|
|
|
@ -188,18 +188,6 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
|
|||
if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
|
||||
DiagnoseUseOfDecl(IIDecl, NameLoc);
|
||||
|
||||
// C++ [temp.local]p2:
|
||||
// Within the scope of a class template specialization or
|
||||
// partial specialization, when the injected-class-name is
|
||||
// not followed by a <, it is equivalent to the
|
||||
// injected-class-name followed by the template-argument s
|
||||
// of the class template specialization or partial
|
||||
// specialization enclosed in <>.
|
||||
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD))
|
||||
if (RD->isInjectedClassName())
|
||||
if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate())
|
||||
T = Template->getInjectedClassNameType(Context);
|
||||
|
||||
if (T.isNull())
|
||||
T = Context.getTypeDeclType(TD);
|
||||
|
||||
|
@ -1773,12 +1761,7 @@ DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
|
|||
return DeclarationName();
|
||||
|
||||
// Determine the type of the class being constructed.
|
||||
QualType CurClassType;
|
||||
if (ClassTemplateDecl *ClassTemplate
|
||||
= CurClass->getDescribedClassTemplate())
|
||||
CurClassType = ClassTemplate->getInjectedClassNameType(Context);
|
||||
else
|
||||
CurClassType = Context.getTypeDeclType(CurClass);
|
||||
QualType CurClassType = Context.getTypeDeclType(CurClass);
|
||||
|
||||
// FIXME: Check two things: that the template-id names the same type as
|
||||
// CurClassType, and that the template-id does not occur when the name
|
||||
|
|
|
@ -665,22 +665,29 @@ void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
|
|||
(CXXBaseSpecifier**)(Bases), NumBases);
|
||||
}
|
||||
|
||||
static CXXRecordDecl *GetClassForType(QualType T) {
|
||||
if (const RecordType *RT = T->getAs<RecordType>())
|
||||
return cast<CXXRecordDecl>(RT->getDecl());
|
||||
else if (const InjectedClassNameType *ICT = T->getAs<InjectedClassNameType>())
|
||||
return ICT->getDecl();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Determine whether the type \p Derived is a C++ class that is
|
||||
/// derived from the type \p Base.
|
||||
bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
|
||||
if (!getLangOptions().CPlusPlus)
|
||||
return false;
|
||||
|
||||
const RecordType *DerivedRT = Derived->getAs<RecordType>();
|
||||
if (!DerivedRT)
|
||||
|
||||
CXXRecordDecl *DerivedRD = GetClassForType(Derived);
|
||||
if (!DerivedRD)
|
||||
return false;
|
||||
|
||||
const RecordType *BaseRT = Base->getAs<RecordType>();
|
||||
if (!BaseRT)
|
||||
CXXRecordDecl *BaseRD = GetClassForType(Base);
|
||||
if (!BaseRD)
|
||||
return false;
|
||||
|
||||
CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl());
|
||||
CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl());
|
||||
// FIXME: instantiate DerivedRD if necessary. We need a PoI for this.
|
||||
return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD);
|
||||
}
|
||||
|
@ -691,16 +698,14 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
|
|||
if (!getLangOptions().CPlusPlus)
|
||||
return false;
|
||||
|
||||
const RecordType *DerivedRT = Derived->getAs<RecordType>();
|
||||
if (!DerivedRT)
|
||||
CXXRecordDecl *DerivedRD = GetClassForType(Derived);
|
||||
if (!DerivedRD)
|
||||
return false;
|
||||
|
||||
const RecordType *BaseRT = Base->getAs<RecordType>();
|
||||
if (!BaseRT)
|
||||
CXXRecordDecl *BaseRD = GetClassForType(Base);
|
||||
if (!BaseRD)
|
||||
return false;
|
||||
|
||||
CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl());
|
||||
CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl());
|
||||
return DerivedRD->isDerivedFrom(BaseRD, Paths);
|
||||
}
|
||||
|
||||
|
|
|
@ -172,14 +172,6 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
|
|||
|
||||
if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) {
|
||||
QualType T = Context.getTypeDeclType(Type);
|
||||
// If we found the injected-class-name of a class template, retrieve the
|
||||
// type of that template.
|
||||
// FIXME: We really shouldn't need to do this.
|
||||
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Type))
|
||||
if (Record->isInjectedClassName())
|
||||
if (Record->getDescribedClassTemplate())
|
||||
T = Record->getDescribedClassTemplate()
|
||||
->getInjectedClassNameType(Context);
|
||||
|
||||
if (SearchType.isNull() || SearchType->isDependentType() ||
|
||||
Context.hasSameUnqualifiedType(T, SearchType)) {
|
||||
|
@ -200,16 +192,8 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
|
|||
if (SS.isSet()) {
|
||||
if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) {
|
||||
// Figure out the type of the context, if it has one.
|
||||
if (ClassTemplateSpecializationDecl *Spec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(Ctx))
|
||||
MemberOfType = Context.getTypeDeclType(Spec);
|
||||
else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
|
||||
if (Record->getDescribedClassTemplate())
|
||||
MemberOfType = Record->getDescribedClassTemplate()
|
||||
->getInjectedClassNameType(Context);
|
||||
else
|
||||
MemberOfType = Context.getTypeDeclType(Record);
|
||||
}
|
||||
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx))
|
||||
MemberOfType = Context.getTypeDeclType(Record);
|
||||
}
|
||||
}
|
||||
if (MemberOfType.isNull())
|
||||
|
|
|
@ -871,10 +871,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
NewClass->setDescribedClassTemplate(NewTemplate);
|
||||
|
||||
// Build the type for the class template declaration now.
|
||||
QualType T =
|
||||
Context.getTypeDeclType(NewClass,
|
||||
PrevClassTemplate?
|
||||
PrevClassTemplate->getTemplatedDecl() : 0);
|
||||
QualType T = NewTemplate->getInjectedClassNameSpecialization(Context);
|
||||
T = Context.getInjectedClassNameType(NewClass, T);
|
||||
assert(T->isDependentType() && "Class template type is not dependent?");
|
||||
(void)T;
|
||||
|
||||
|
@ -1306,7 +1304,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
|||
TemplateParameterList *ExpectedTemplateParams = 0;
|
||||
// Is this template-id naming the primary template?
|
||||
if (Context.hasSameType(TemplateId,
|
||||
ClassTemplate->getInjectedClassNameType(Context)))
|
||||
ClassTemplate->getInjectedClassNameSpecialization(Context)))
|
||||
ExpectedTemplateParams = ClassTemplate->getTemplateParameters();
|
||||
// ... or a partial specialization?
|
||||
else if (ClassTemplatePartialSpecializationDecl *PartialSpec
|
||||
|
@ -1431,6 +1429,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
|||
}
|
||||
|
||||
CanonType = Context.getTypeDeclType(Decl);
|
||||
assert(isa<RecordType>(CanonType) &&
|
||||
"type of non-dependent specialization is not a RecordType");
|
||||
}
|
||||
|
||||
// Build the fully-sugared type for this class template
|
||||
|
@ -3488,6 +3488,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
|
|||
ClassTemplate,
|
||||
Converted,
|
||||
TemplateArgs,
|
||||
CanonType,
|
||||
PrevPartial);
|
||||
|
||||
if (PrevPartial) {
|
||||
|
@ -3609,8 +3610,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
|
|||
// actually wrote the specialization, rather than formatting the
|
||||
// name based on the "canonical" representation used to store the
|
||||
// template arguments in the specialization.
|
||||
QualType WrittenTy
|
||||
= Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
|
||||
TypeSourceInfo *WrittenTy
|
||||
= Context.getTemplateSpecializationTypeInfo(Name, TemplateNameLoc,
|
||||
TemplateArgs, CanonType);
|
||||
if (TUK != TUK_Friend)
|
||||
Specialization->setTypeAsWritten(WrittenTy);
|
||||
TemplateArgsIn.release();
|
||||
|
@ -3632,7 +3634,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
|
|||
if (TUK == TUK_Friend) {
|
||||
FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
|
||||
TemplateNameLoc,
|
||||
WrittenTy.getTypePtr(),
|
||||
WrittenTy->getType().getTypePtr(),
|
||||
/*FIXME:*/KWLoc);
|
||||
Friend->setAccess(AS_public);
|
||||
CurContext->addDecl(Friend);
|
||||
|
@ -4344,8 +4346,9 @@ Sema::ActOnExplicitInstantiation(Scope *S,
|
|||
// the explicit instantiation, rather than formatting the name based
|
||||
// on the "canonical" representation used to store the template
|
||||
// arguments in the specialization.
|
||||
QualType WrittenTy
|
||||
= Context.getTemplateSpecializationType(Name, TemplateArgs,
|
||||
TypeSourceInfo *WrittenTy
|
||||
= Context.getTemplateSpecializationTypeInfo(Name, TemplateNameLoc,
|
||||
TemplateArgs,
|
||||
Context.getTypeDeclType(Specialization));
|
||||
Specialization->setTypeAsWritten(WrittenTy);
|
||||
TemplateArgsIn.release();
|
||||
|
|
|
@ -625,6 +625,15 @@ DeduceTemplateArguments(Sema &S,
|
|||
return Sema::TDK_Success;
|
||||
}
|
||||
|
||||
case Type::InjectedClassName: {
|
||||
// Treat a template's injected-class-name as if the template
|
||||
// specialization type had been used.
|
||||
Param = cast<InjectedClassNameType>(Param)->getUnderlyingType();
|
||||
assert(isa<TemplateSpecializationType>(Param) &&
|
||||
"injected class name is not a template specialization type");
|
||||
// fall through
|
||||
}
|
||||
|
||||
// template-name<T> (where template-name refers to a class template)
|
||||
// template-name<i>
|
||||
// TT<T>
|
||||
|
|
|
@ -621,7 +621,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
|||
Inst->setInstantiatedFromMemberTemplate(D);
|
||||
|
||||
// Trigger creation of the type for the instantiation.
|
||||
SemaRef.Context.getTypeDeclType(RecordInst);
|
||||
SemaRef.Context.getInjectedClassNameType(RecordInst,
|
||||
Inst->getInjectedClassNameSpecialization(SemaRef.Context));
|
||||
|
||||
// Finish handling of friends.
|
||||
if (Inst->getFriendObjectKind()) {
|
||||
|
@ -1462,8 +1463,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
|
|||
// actually wrote the specialization, rather than formatting the
|
||||
// name based on the "canonical" representation used to store the
|
||||
// template arguments in the specialization.
|
||||
QualType WrittenTy
|
||||
= SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
|
||||
TypeSourceInfo *WrittenTy
|
||||
= SemaRef.Context.getTemplateSpecializationTypeInfo(
|
||||
TemplateName(ClassTemplate),
|
||||
PartialSpec->getLocation(),
|
||||
InstTemplateArgs,
|
||||
CanonType);
|
||||
|
||||
|
@ -1499,6 +1502,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
|
|||
ClassTemplate,
|
||||
Converted,
|
||||
InstTemplateArgs,
|
||||
CanonType,
|
||||
0);
|
||||
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
|
||||
InstPartialSpec->setTypeAsWritten(WrittenTy);
|
||||
|
@ -2236,12 +2240,18 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
|
|||
ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
|
||||
|
||||
if (ClassTemplate) {
|
||||
T = ClassTemplate->getInjectedClassNameType(Context);
|
||||
T = ClassTemplate->getInjectedClassNameSpecialization(Context);
|
||||
} else if (ClassTemplatePartialSpecializationDecl *PartialSpec
|
||||
= dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
|
||||
T = Context.getTypeDeclType(Record);
|
||||
ClassTemplate = PartialSpec->getSpecializedTemplate();
|
||||
}
|
||||
|
||||
// If we call SubstType with an InjectedClassNameType here we
|
||||
// can end up in an infinite loop.
|
||||
T = Context.getTypeDeclType(Record);
|
||||
assert(isa<InjectedClassNameType>(T) &&
|
||||
"type of partial specialization is not an InjectedClassNameType");
|
||||
T = cast<InjectedClassNameType>(T)->getUnderlyingType();
|
||||
}
|
||||
|
||||
if (!T.isNull()) {
|
||||
// Substitute into the injected-class-name to get the type
|
||||
|
@ -2308,16 +2318,16 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
|
|||
// so now we need to look into the instantiated parent context to
|
||||
// find the instantiation of the declaration D.
|
||||
|
||||
// If our context is a class template specialization, we may need
|
||||
// to instantiate it before performing lookup into that context.
|
||||
if (ClassTemplateSpecializationDecl *Spec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(ParentDC)) {
|
||||
// If our context used to be dependent, we may need to instantiate
|
||||
// it before performing lookup into that context.
|
||||
if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) {
|
||||
if (!Spec->isDependentContext()) {
|
||||
QualType T = Context.getTypeDeclType(Spec);
|
||||
if (const TagType *Tag = T->getAs<TagType>())
|
||||
if (!Tag->isBeingDefined() &&
|
||||
RequireCompleteType(Loc, T, diag::err_incomplete_type))
|
||||
return 0;
|
||||
const RecordType *Tag = T->getAs<RecordType>();
|
||||
assert(Tag && "type of non-dependent record is not a RecordType");
|
||||
if (!Tag->isBeingDefined() &&
|
||||
RequireCompleteType(Loc, T, diag::err_incomplete_type))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2823,6 +2823,20 @@ QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
|
|||
return Result;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformInjectedClassNameType(
|
||||
TypeLocBuilder &TLB,
|
||||
InjectedClassNameTypeLoc TL,
|
||||
QualType ObjectType) {
|
||||
Decl *D = getDerived().TransformDecl(TL.getNameLoc(),
|
||||
TL.getTypePtr()->getDecl());
|
||||
if (!D) return QualType();
|
||||
|
||||
QualType T = SemaRef.Context.getTypeDeclType(cast<TypeDecl>(D));
|
||||
TLB.pushTypeSpec(T).setNameLoc(TL.getNameLoc());
|
||||
return T;
|
||||
}
|
||||
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
|
||||
|
|
|
@ -52,7 +52,7 @@ void e3(union B<A>::Member);
|
|||
void e4(enum B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
|
||||
|
||||
template <class T> struct C {
|
||||
void foo(class B<T>::Member); // expected-error{{no type named 'Member' in 'B<int>'}}
|
||||
void foo(class B<T>::Member); // expected-error{{no type named 'Member' in 'struct B<int>'}}
|
||||
};
|
||||
|
||||
C<float> f1;
|
||||
|
|
|
@ -42,3 +42,9 @@ struct X1 {
|
|||
void f0(const X1<T, N>&); // expected-error{{redecl}}
|
||||
};
|
||||
|
||||
namespace pr6326 {
|
||||
template <class T> class A {
|
||||
friend class A;
|
||||
};
|
||||
template class A<int>;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ typedef int& int_ref_t;
|
|||
Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int &>' required here}}
|
||||
|
||||
|
||||
template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1<int const>'}}
|
||||
template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'struct Def1<int const>'}}
|
||||
|
||||
template<typename T, typename T2 = T&> struct Def3;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче