From 0b1beb7a295b20f7e05479d599dde027f9f692fe Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 2 Nov 2011 17:38:53 +0000 Subject: [PATCH] Drastically simplify the mapping from the declaration corresponding to the injected-class-name of a class (or class template) to the declaration that results from substituting the given template arguments. Previously, we would actually perform a substitution into the injected-class-name type and then retrieve the resulting declaration. However, in certain, rare circumstances involving deeply-nested member templates, we would get the wrong substitution arguments. This new approach just matches up the declaration with a declaration that's part of the current context (or one of its parents), which will either be an instantiation (during template instantiation) or the declaration itself (during the definition of the template). This is both more efficient (we're avoiding a substitution) and more correct (we can't get the template arguments wrong in the member-template case). Fixes . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143551 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplateInstantiateDecl.cpp | 106 ++++++++-------------- 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(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(T) && - "type of partial specialization is not an InjectedClassNameType"); - T = cast(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()->getDecl(); + if (ClassTemplate) + ClassTemplate = ClassTemplate->getCanonicalDecl(); + else if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast(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(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(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(DC)) - if (isInstantiationOf(ClassTemplate, - Spec->getSpecializedTemplate())) - return Spec; - - if (!DC->isDependentContext()) - SawNonDependentContext = true; + + + // Move to the outer template scope. + if (FunctionDecl *FD = dyn_cast(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(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 class tuple_element; + + template class pair; + + template + class tuple_element<0, pair<_T1, _T2> > + { + template + struct X + { + template ::value> + struct Y + : public X<_Up>, + public Y<_Up> + { }; + }; + }; +} + -- 2.40.0