diff options
author | John McCall <rjmccall@apple.com> | 2010-03-10 03:28:59 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-03-10 03:28:59 +0000 |
commit | 3cb0ebd5f76abcb776f7cb4062bd79e3268c0dc4 (patch) | |
tree | 84f7dae6f0d5da51df0529ca91ff0c7fdf3f152e /lib/Sema | |
parent | d7fdae5ea0158f91f0683044bb3a7dee0426bfe0 (diff) |
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
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 19 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 31 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 38 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 14 |
8 files changed, 90 insertions, 87 deletions
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( |