aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaCXXScopeSpec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaCXXScopeSpec.cpp')
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp102
1 files changed, 97 insertions, 5 deletions
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 5395869a02..bbc1bc52cb 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -13,6 +13,7 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/STLExtras.h"
@@ -26,8 +27,14 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) {
NestedNameSpecifier *NNS
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- if (NNS->isDependent())
- return 0;
+ if (NNS->isDependent()) {
+ // If this nested-name-specifier refers to the current
+ // instantiation, return its DeclContext.
+ if (CXXRecordDecl *Record = getCurrentInstantiationOf(NNS))
+ return Record;
+ else
+ return 0;
+ }
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
@@ -61,6 +68,90 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
return NNS->isDependent();
}
+// \brief Determine whether this C++ scope specifier refers to an
+// unknown specialization, i.e., a dependent type that is not the
+// current instantiation.
+bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
+ if (!isDependentScopeSpecifier(SS))
+ return false;
+
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ return getCurrentInstantiationOf(NNS) == 0;
+}
+
+/// \brief If the given nested name specifier refers to the current
+/// instantiation, return the declaration that corresponds to that
+/// current instantiation (C++0x [temp.dep.type]p1).
+///
+/// \param NNS a dependent nested name specifier.
+CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
+ assert(getLangOptions().CPlusPlus && "Only callable in C++");
+ assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed");
+
+ QualType T = QualType(NNS->getAsType(), 0);
+ // If the nested name specifier does not refer to a type, then it
+ // does not refer to the current instantiation.
+ if (T.isNull())
+ return 0;
+
+ T = Context.getCanonicalType(T);
+
+ for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) {
+ // If we've hit a namespace or the global scope, then the
+ // nested-name-specifier can't refer to the current instantiation.
+ if (Ctx->isFileContext())
+ return 0;
+
+ // Skip non-class contexts.
+ CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx);
+ if (!Record)
+ continue;
+
+ // If this record type is not dependent,
+ if (!Record->isDependentType())
+ return 0;
+
+ // C++ [temp.dep.type]p1:
+ //
+ // In the definition of a class template, a nested class of a
+ // class template, a member of a class template, or a member of a
+ // nested class of a class template, a name refers to the current
+ // instantiation if it is
+ // -- the injected-class-name (9) of the class template or
+ // nested class,
+ // -- in the definition of a primary class template, the name
+ // of the class template followed by the template argument
+ // list of the primary template (as described below)
+ // enclosed in <>,
+ // -- in the definition of a nested class of a class template,
+ // the name of the nested class referenced as a member of
+ // the current instantiation, or
+ // -- in the definition of a partial specialization, the name
+ // of the class template followed by the template argument
+ // list of the partial specialization enclosed in <>. If
+ // the nth template parameter is a parameter pack, the nth
+ // template argument is a pack expansion (14.6.3) whose
+ // pattern is the name of the parameter pack. (FIXME)
+ //
+ // All of these options come down to having the
+ // nested-name-specifier type that is equivalent to the
+ // injected-class-name of one of the types that is currently in
+ // our context.
+ if (Context.getTypeDeclType(Record) == T)
+ return Record;
+
+ if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) {
+ QualType InjectedClassName
+ = Template->getInjectedClassNameType(Context);
+ if (T == Context.getCanonicalType(InjectedClassName))
+ return Template->getTemplatedDecl();
+ }
+ }
+
+ return 0;
+}
+
/// \brief Require that the context specified by SS be complete.
///
/// If SS refers to a type, this routine checks whether the type is
@@ -113,9 +204,10 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
NestedNameSpecifier *Prefix
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- // If the prefix is already dependent, there is no name lookup to
- // perform. Just build the resulting nested-name-specifier.
- if (Prefix && Prefix->isDependent())
+ // If the prefix already refers to an unknown specialization, there
+ // is no name lookup to perform. Just build the resulting
+ // nested-name-specifier.
+ if (Prefix && isUnknownSpecialization(SS))
return NestedNameSpecifier::Create(Context, Prefix, &II);
NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName);