diff options
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 106 | ||||
-rw-r--r-- | test/SemaTemplate/class-template-decl.cpp | 20 |
2 files changed, 60 insertions, 66 deletions
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index bb6f2d347f..4cde69f087 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3148,75 +3148,49 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (!Record->isDependentContext()) return D; - // If the RecordDecl is actually the injected-class-name or a - // "templated" declaration for a class template, class template - // partial specialization, or a member class of a class template, - // substitute into the injected-class-name of the class template - // or partial specialization to find the new DeclContext. - QualType T; + // Determine whether this record is the "templated" declaration describing + // a class template or class template partial specialization. ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate(); - - if (ClassTemplate) { - T = ClassTemplate->getInjectedClassNameSpecialization(); - } else if (ClassTemplatePartialSpecializationDecl *PartialSpec - = dyn_cast<ClassTemplatePartialSpecializationDecl>(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)->getInjectedSpecializationType(); - } - - if (!T.isNull()) { - // Substitute into the injected-class-name to get the type - // corresponding to the instantiation we want, which may also be - // the current instantiation (if we're in a template - // definition). This substitution should never fail, since we - // know we can instantiate the injected-class-name or we - // wouldn't have gotten to the injected-class-name! - - // FIXME: Can we use the CurrentInstantiationScope to avoid this - // extra instantiation in the common case? - T = SubstType(T, TemplateArgs, Loc, DeclarationName()); - assert(!T.isNull() && "Instantiation of injected-class-name cannot fail."); - - if (!T->isDependentType()) { - assert(T->isRecordType() && "Instantiation must produce a record type"); - return T->getAs<RecordType>()->getDecl(); + if (ClassTemplate) + ClassTemplate = ClassTemplate->getCanonicalDecl(); + else if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) + ClassTemplate = PartialSpec->getSpecializedTemplate()->getCanonicalDecl(); + + // Walk the current context to find either the record or an instantiation of + // it. + DeclContext *DC = CurContext; + while (!DC->isFileContext()) { + // If we're performing substitution while we're inside the template + // definition, we'll find our own context. We're done. + if (DC->Equals(Record)) + return Record; + + if (CXXRecordDecl *InstRecord = dyn_cast<CXXRecordDecl>(DC)) { + // Check whether we're in the process of instantiating a class template + // specialization of the template we're mapping. + if (ClassTemplateSpecializationDecl *InstSpec + = dyn_cast<ClassTemplateSpecializationDecl>(InstRecord)){ + ClassTemplateDecl *SpecTemplate = InstSpec->getSpecializedTemplate(); + if (ClassTemplate && isInstantiationOf(ClassTemplate, SpecTemplate)) + return InstRecord; + } + + // Check whether we're in the process of instantiating a member class. + if (isInstantiationOf(Record, InstRecord)) + return InstRecord; } - - // We are performing "partial" template instantiation to create - // the member declarations for the members of a class template - // specialization. Therefore, D is actually referring to something - // in the current instantiation. Look through the current - // context, which contains actual instantiations, to find the - // instantiation of the "current instantiation" that D refers - // to. - bool SawNonDependentContext = false; - for (DeclContext *DC = CurContext; !DC->isFileContext(); - DC = DC->getParent()) { - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(DC)) - if (isInstantiationOf(ClassTemplate, - Spec->getSpecializedTemplate())) - return Spec; - - if (!DC->isDependentContext()) - SawNonDependentContext = true; + + + // Move to the outer template scope. + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) { + if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){ + DC = FD->getLexicalDeclContext(); + continue; + } } - - // We're performing "instantiation" of a member of the current - // instantiation while we are type-checking the - // definition. Compute the declaration context and return that. - assert(!SawNonDependentContext && - "No dependent context while instantiating record"); - DeclContext *DC = computeDeclContext(T); - assert(DC && - "Unable to find declaration for the current instantiation"); - return cast<CXXRecordDecl>(DC); + + DC = DC->getParent(); } // Fall through to deal with other dependent record types (e.g., diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp index 38b1778abf..ec4e016385 100644 --- a/test/SemaTemplate/class-template-decl.cpp +++ b/test/SemaTemplate/class-template-decl.cpp @@ -75,3 +75,23 @@ namespace PR8001 { } } +namespace rdar9676205 { + template <unsigned, class _Tp> class tuple_element; + + template <class _T1, class _T2> class pair; + + template <class _T1, class _T2> + class tuple_element<0, pair<_T1, _T2> > + { + template <class _Tp> + struct X + { + template <class _Up, bool = X<_Up>::value> + struct Y + : public X<_Up>, + public Y<_Up> + { }; + }; + }; +} + |