diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-02-05 22:40:03 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-02-05 22:40:03 +0000 |
commit | 8b013bdbf6474ed25d4017635cac851e51163c25 (patch) | |
tree | 287d5b61ba93c5cd09f42c93d8e6be6d3888e823 | |
parent | 04a67a6aa3dfdc92d57f7f8d93ba397348c868a4 (diff) |
Cope with finding the "instantiated" declaration when we are
type-checking within a template definition. In this case, the
"instantiated" declaration is just the declaration itself, found
within the current instantiation. Fixes PR6239.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95442 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 57 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-member-template.cpp | 25 |
2 files changed, 61 insertions, 21 deletions
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index e4017c5630..66a8b1f1e6 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2170,10 +2170,11 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, if (!Record->isDependentContext()) return D; - // If the RecordDecl is actually the injected-class-name or a "templated" - // declaration for a class template or class template partial - // specialization, substitute into the injected-class-name of the - // class template or partial specialization to find the new DeclContext. + // 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; ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate(); @@ -2183,15 +2184,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) { T = Context.getTypeDeclType(Record); ClassTemplate = PartialSpec->getSpecializedTemplate(); - } + } if (!T.isNull()) { - // Substitute into the injected-class-name to get the type corresponding - // to the instantiation we want. 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? + // 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, SourceLocation(), DeclarationName()); assert(!T.isNull() && "Instantiation of injected-class-name cannot fail."); @@ -2200,26 +2204,37 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, return T->getAs<RecordType>()->getDecl(); } - // 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. + // 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)) + = dyn_cast<ClassTemplateSpecializationDecl>(DC)) if (isInstantiationOf(ClassTemplate, Spec->getSpecializedTemplate())) return Spec; + + if (!DC->isDependentContext()) + SawNonDependentContext = true; } - assert(false && + // 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 Record; + return cast<CXXRecordDecl>(DC); } - + // Fall through to deal with other dependent record types (e.g., // anonymous unions in class templates). } diff --git a/test/SemaTemplate/instantiate-member-template.cpp b/test/SemaTemplate/instantiate-member-template.cpp index b4f0a9c650..c1260cf6a8 100644 --- a/test/SemaTemplate/instantiate-member-template.cpp +++ b/test/SemaTemplate/instantiate-member-template.cpp @@ -131,3 +131,28 @@ namespace N0 { x1.f(x0l); } } + +namespace PR6239 { + template <typename T> + struct X0 { + class type { + typedef T E; + template <E e> // subsitute T for E and bug goes away + struct sfinae { }; + + template <class U> + typename sfinae<&U::operator=>::type test(int); + }; + }; + + template <typename T> + struct X1 { + typedef T E; + template <E e> // subsitute T for E and bug goes away + struct sfinae { }; + + template <class U> + typename sfinae<&U::operator=>::type test(int); + }; + +} |