aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-02-05 22:40:03 +0000
committerDouglas Gregor <dgregor@apple.com>2010-02-05 22:40:03 +0000
commit8b013bdbf6474ed25d4017635cac851e51163c25 (patch)
tree287d5b61ba93c5cd09f42c93d8e6be6d3888e823
parent04a67a6aa3dfdc92d57f7f8d93ba397348c868a4 (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.cpp57
-rw-r--r--test/SemaTemplate/instantiate-member-template.cpp25
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);
+ };
+
+}