summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTContext.h7
-rw-r--r--include/clang/AST/Decl.h1
-rw-r--r--include/clang/AST/DeclTemplate.h22
-rw-r--r--include/clang/AST/Type.h41
-rw-r--r--include/clang/AST/TypeLoc.h8
-rw-r--r--include/clang/AST/TypeNodes.def1
-rw-r--r--include/clang/Frontend/PCHBitCodes.h4
-rw-r--r--lib/AST/ASTContext.cpp59
-rw-r--r--lib/AST/ASTDiagnostic.cpp6
-rw-r--r--lib/AST/ASTImporter.cpp10
-rw-r--r--lib/AST/DeclBase.cpp21
-rw-r--r--lib/AST/DeclCXX.cpp15
-rw-r--r--lib/AST/DeclTemplate.cpp8
-rw-r--r--lib/AST/TypePrinter.cpp57
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp1
-rw-r--r--lib/Frontend/PCHReader.cpp9
-rw-r--r--lib/Frontend/PCHWriter.cpp9
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp23
-rw-r--r--lib/Sema/SemaDecl.cpp19
-rw-r--r--lib/Sema/SemaDeclCXX.cpp31
-rw-r--r--lib/Sema/SemaExprCXX.cpp20
-rw-r--r--lib/Sema/SemaTemplate.cpp23
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp9
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp38
-rw-r--r--lib/Sema/TreeTransform.h14
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp2
-rw-r--r--test/SemaTemplate/injected-class-name.cpp6
-rw-r--r--test/SemaTemplate/instantiation-default-1.cpp2
28 files changed, 337 insertions, 129 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 0838a3d0eb..fab63f556b 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -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,
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 91aeff3439..bd9f01b0b5 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1429,7 +1429,6 @@ class TypeDecl : public NamedDecl {
friend class DeclContext;
friend class TagDecl;
friend class TemplateTypeParmDecl;
- friend class ClassTemplateSpecializationDecl;
friend class TagType;
protected:
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index ced174716c..560ce46ede 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -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.
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index bd8a6bc846..111be55621 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -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.
///
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 6fb51edb76..27659bd02f 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -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,
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 8187caddc6..e75202e50a 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -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)
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index d4014b3075..e234e9838a 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -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
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index e2c80a6da5..f134bfdf1f 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -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,
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 7402b7dda4..866b7f799f 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -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)) {
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index bf1551a099..d9c0d7b6be 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -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);
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 9db6ae1329..a9495343e8 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -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 &&
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 9b693af5bc..7f4ad34fb7 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -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);
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index d80db45f45..b449398624 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -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;
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 5b621cf728..6e88ca32ca 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -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;
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 705d7f3c52..c3302e661d 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -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:
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 9a5cae6e81..267f4c1585 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -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++]));
}
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 93af754683..eed3cc1a5b 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -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);
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 971b78c489..95b79abd8f 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -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.
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 82dcd60aa0..94fcfc6c29 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -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
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 79cab15e69..e694cb470c 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -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);
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 309da292e1..b9c8afa195 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -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())
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 445b68b167..7c4cab1183 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -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();
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 7f16400aea..326519d3a3 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -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>
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 3a6b4cb3cc..cf8d38c095 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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;
}
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 24ea62cde1..17f94193fe 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -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(
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
index 392888e71b..dd3df63912 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
@@ -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;
diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp
index 482eae14ba..586be189b0 100644
--- a/test/SemaTemplate/injected-class-name.cpp
+++ b/test/SemaTemplate/injected-class-name.cpp
@@ -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>;
+}
diff --git a/test/SemaTemplate/instantiation-default-1.cpp b/test/SemaTemplate/instantiation-default-1.cpp
index 6f5a660d99..391589e250 100644
--- a/test/SemaTemplate/instantiation-default-1.cpp
+++ b/test/SemaTemplate/instantiation-default-1.cpp
@@ -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;