aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp106
-rw-r--r--test/SemaTemplate/class-template-decl.cpp20
2 files changed, 66 insertions, 60 deletions
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 4cde69f087..bb6f2d347f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3148,49 +3148,75 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (!Record->isDependentContext())
return D;
- // Determine whether this record is the "templated" declaration describing
- // a class template or class template partial specialization.
+ // 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();
- 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;
+
+ 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();
}
-
-
- // Move to the outer template scope.
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) {
- if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){
- DC = FD->getLexicalDeclContext();
- continue;
- }
+
+ // 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;
}
-
- DC = DC->getParent();
+
+ // 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);
}
// 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 ec4e016385..38b1778abf 100644
--- a/test/SemaTemplate/class-template-decl.cpp
+++ b/test/SemaTemplate/class-template-decl.cpp
@@ -75,23 +75,3 @@ 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>
- { };
- };
- };
-}
-