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
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 971b78c..95b79ab 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -76,14 +76,6 @@
// 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 @@
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 @@
// 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 @@
= 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 @@
// 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 82dcd60..94fcfc6 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -188,18 +188,6 @@
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 @@
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 79cab15..e694cb4 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -665,22 +665,29 @@
(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 @@
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 309da29..b9c8afa 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -172,14 +172,6 @@
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 @@
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 445b68b..7c4cab1 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -871,10 +871,8 @@
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 @@
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 @@
}
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 @@
ClassTemplate,
Converted,
TemplateArgs,
+ CanonType,
PrevPartial);
if (PrevPartial) {
@@ -3609,8 +3610,9 @@
// 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 @@
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 @@
// 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 7f16400..326519d 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -625,6 +625,15 @@
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 3a6b4cb..cf8d38c 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -621,7 +621,8 @@
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 @@
// 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 @@
ClassTemplate,
Converted,
InstTemplateArgs,
+ CanonType,
0);
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
InstPartialSpec->setTypeAsWritten(WrittenTy);
@@ -2236,12 +2240,18 @@
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 @@
// 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 24ea62c..17f9419 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -2823,6 +2823,20 @@
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(