Revamp our representation of C++ nested-name-specifiers. We now have a
uniqued representation that should both save some memory and make it
far easier to properly build canonical types for types involving
dependent nested-name-specifiers, e.g., "typename T::Nested::type".
This approach will greatly simplify the representation of
CXXScopeSpec. That'll be next.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67799 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 9d71cf3..8c8cae2 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1940,11 +1940,11 @@
ClassTemplateSpecializationDecl *ClassTemplateSpec,
bool ExplicitInstantiation);
- CXXScopeSpec InstantiateScopeSpecifier(const NestedNameSpecifier *Components,
- unsigned NumComponents,
- SourceRange Range,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
+ NestedNameSpecifier *
+ InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
// Simple function for cloning expressions.
template<typename T>
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 9e11961..ca864a2 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -24,24 +24,41 @@
if (!SS.isSet() || SS.isInvalid())
return 0;
- NestedNameSpecifier NNS
- = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep());
- return NNS.computeDeclContext(Context);
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+ if (NNS->isDependent())
+ return 0;
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ assert(false && "Dependent nested-name-specifier has no DeclContext");
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ return NNS->getAsNamespace();
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ const TagType *Tag = NNS->getAsType()->getAsTagType();
+ assert(Tag && "Non-tag type in nested-name-specifier");
+ return Tag->getDecl();
+ } break;
+
+ case NestedNameSpecifier::Global:
+ return Context.getTranslationUnitDecl();
+ }
+
+ // Required to silence a GCC warning.
+ return 0;
}
bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return false;
- NestedNameSpecifier NNS
- = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep());
-
- if (Type *T = NNS.getAsType())
- return T->isDependentType();
-
- // FIXME: What about the injected-class-name of a class template? It
- // is dependent, but we represent it as a declaration.
- return false;
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+ return NNS->isDependent();
}
/// \brief Require that the context specified by SS be complete.
@@ -79,7 +96,7 @@
/// global scope ('::').
Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
SourceLocation CCLoc) {
- return NestedNameSpecifier(Context.getTranslationUnitDecl()).getAsOpaquePtr();
+ return NestedNameSpecifier::GlobalSpecifier(Context);
}
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
@@ -93,19 +110,37 @@
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II) {
+ NestedNameSpecifier *Prefix
+ = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+
+ // If the prefix is already dependent, there is no name lookup to
+ // perform. Just build the resulting nested-name-specifier.
+ if (Prefix && Prefix->isDependent())
+ return NestedNameSpecifier::Create(Context, Prefix, &II);
+
NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName);
if (SD) {
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
- if (TD->getUnderlyingType()->isRecordType())
- return NestedNameSpecifier(Context.getTypeDeclType(TD).getTypePtr())
- .getAsOpaquePtr();
- } else if (isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) {
- return NestedNameSpecifier(cast<DeclContext>(SD)).getAsOpaquePtr();
- }
+ if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD))
+ return NestedNameSpecifier::Create(Context, Prefix, Namespace);
- // FIXME: Template parameters and dependent types.
- // FIXME: C++0x scoped enums
+ if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) {
+ // Determine whether we have a class (or, in C++0x, an enum) or
+ // a typedef thereof. If so, build the nested-name-specifier.
+ QualType T;
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (TD->getUnderlyingType()->isRecordType() ||
+ (getLangOptions().CPlusPlus0x &&
+ TD->getUnderlyingType()->isEnumeralType()))
+ T = Context.getTypeDeclType(TD);
+ } else if (isa<RecordDecl>(Type) ||
+ (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type)))
+ T = Context.getTypeDeclType(Type);
+
+ if (!T.isNull())
+ return NestedNameSpecifier::Create(Context, Prefix, false,
+ T.getTypePtr());
+ }
// Fall through to produce an error: we found something that isn't
// a class or a namespace.
@@ -137,8 +172,10 @@
TypeTy *Ty,
SourceRange TypeRange,
SourceLocation CCLoc) {
- return NestedNameSpecifier(QualType::getFromOpaquePtr(Ty).getTypePtr())
- .getAsOpaquePtr();
+ NestedNameSpecifier *Prefix
+ = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+ return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false,
+ QualType::getFromOpaquePtr(Ty).getTypePtr());
}
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
@@ -152,6 +189,7 @@
assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());
CurContext = computeDeclContext(SS);
+ assert(CurContext && "No context?");
S->setEntity(CurContext);
}
@@ -170,4 +208,5 @@
while (!S->getEntity() && S->getParent())
S = S->getParent();
CurContext = static_cast<DeclContext*>(S->getEntity());
+ assert(CurContext && "No context?");
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index cb44cfc..bb306e4 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1159,9 +1159,13 @@
/// Method declaration as if we had just parsed the qualified method
/// name. However, it should not bring the parameters into scope;
/// that will be performed by ActOnDelayedCXXMethodParameter.
-void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) {
+void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *MethodD) {
CXXScopeSpec SS;
- SS.setScopeRep(((FunctionDecl*)Method)->getDeclContext());
+ FunctionDecl *Method = (FunctionDecl*)MethodD;
+ QualType ClassTy
+ = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
+ SS.setScopeRep(
+ NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
ActOnCXXEnterDeclaratorScope(S, SS);
}
@@ -1192,7 +1196,10 @@
void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *MethodD) {
FunctionDecl *Method = (FunctionDecl*)MethodD;
CXXScopeSpec SS;
- SS.setScopeRep(Method->getDeclContext());
+ QualType ClassTy
+ = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
+ SS.setScopeRep(
+ NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
ActOnCXXExitDeclaratorScope(S, SS);
// Now that we have our default arguments, check the constructor
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c46bde0..288b617 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -440,13 +440,9 @@
bool TypeDependent, bool ValueDependent,
const CXXScopeSpec *SS) {
if (SS && !SS->isEmpty()) {
- llvm::SmallVector<NestedNameSpecifier, 16> Specs;
- for (CXXScopeSpec::iterator Spec = SS->begin(), SpecEnd = SS->end();
- Spec != SpecEnd; ++Spec)
- Specs.push_back(NestedNameSpecifier::getFromOpaquePtr(*Spec));
- return QualifiedDeclRefExpr::Create(Context, D, Ty, Loc, TypeDependent,
- ValueDependent, SS->getRange(),
- &Specs[0], Specs.size());
+ return new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
+ ValueDependent, SS->getRange(),
+ static_cast<NestedNameSpecifier *>(SS->getCurrentScopeRep()));
} else
return new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
}
@@ -619,13 +615,9 @@
// -- a nested-name-specifier that contains a class-name that
// names a dependent type.
if (SS && isDependentScopeSpecifier(*SS)) {
- llvm::SmallVector<NestedNameSpecifier, 16> Specs;
- for (CXXScopeSpec::iterator Spec = SS->begin(), SpecEnd = SS->end();
- Spec != SpecEnd; ++Spec)
- Specs.push_back(NestedNameSpecifier::getFromOpaquePtr(*Spec));
- return Owned(UnresolvedDeclRefExpr::Create(Context, Name, Loc,
- SS->getRange(), &Specs[0],
- Specs.size()));
+ return Owned(new (Context) UnresolvedDeclRefExpr(Name, Context.DependentTy,
+ Loc, SS->getRange(),
+ static_cast<NestedNameSpecifier *>(SS->getCurrentScopeRep())));
}
LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName,
@@ -2302,12 +2294,11 @@
Expr *NewFn = 0;
if (QualifiedDeclRefExpr *QDRExpr
= dyn_cast_or_null<QualifiedDeclRefExpr>(DRExpr))
- NewFn = QualifiedDeclRefExpr::Create(Context, FDecl, FDecl->getType(),
- QDRExpr->getLocation(),
- false, false,
- QDRExpr->getQualifierRange(),
- QDRExpr->begin(),
- QDRExpr->size());
+ NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
+ QDRExpr->getLocation(),
+ false, false,
+ QDRExpr->getQualifierRange(),
+ QDRExpr->getQualifier());
else
NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(),
Fn->getSourceRange().getBegin());
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index f6e36bf..52f87b9 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -768,33 +768,52 @@
ClassTemplateSpec->getNumTemplateArgs());
}
-/// \brief Instantiate a sequence of nested-name-specifiers into a
-/// scope specifier.
-CXXScopeSpec
-Sema::InstantiateScopeSpecifier(const NestedNameSpecifier *Components,
- unsigned NumComponents,
- SourceRange Range,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
- CXXScopeSpec SS;
- for (unsigned Comp = 0; Comp < NumComponents; ++Comp) {
- if (Type *T = Components[Comp].getAsType()) {
- QualType NewT = InstantiateType(QualType(T, 0), TemplateArgs,
- NumTemplateArgs, Range.getBegin(),
- DeclarationName());
- if (NewT.isNull())
- return SS;
- NestedNameSpecifier NNS(NewT.getTypePtr());
- SS.addScopeRep(NNS.getAsOpaquePtr());
- } else {
- DeclContext *DC = Components[Comp].getAsDeclContext();
- // FIXME: injected-class-name might be dependent, and therefore
- // would need instantiation.
- NestedNameSpecifier NNS(DC);
- SS.addScopeRep(NNS.getAsOpaquePtr());
- }
+/// \brief Instantiate a nested-name-specifier.
+NestedNameSpecifier *
+Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ // Instantiate the prefix of this nested name specifier.
+ NestedNameSpecifier *Prefix = NNS->getPrefix();
+ if (Prefix) {
+ Prefix = InstantiateNestedNameSpecifier(Prefix, Range, TemplateArgs,
+ NumTemplateArgs);
+ if (!Prefix)
+ return 0;
}
- SS.setRange(Range);
- return SS;
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ // FIXME: Implement this lookup!
+ assert(false && "Cannot instantiate this nested-name-specifier");
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::Global:
+ return NNS;
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::TypeSpec: {
+ QualType T = QualType(NNS->getAsType(), 0);
+ if (!T->isDependentType())
+ return NNS;
+
+ T = InstantiateType(T, TemplateArgs, NumTemplateArgs, Range.getBegin(),
+ DeclarationName());
+ if (T.isNull())
+ return 0;
+
+ // Note that T.getTypePtr(), below, strips cv-qualifiers. This is
+ // perfectly reasonable, since cv-qualified types in
+ // nested-name-specifiers don't matter.
+ // FIXME: we need to perform more checking on this type.
+ return NestedNameSpecifier::Create(Context, Prefix,
+ NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
+ T.getTypePtr());
+ }
+ }
+
+ // Required to silence GCC warning.
+ return 0;
}
diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp
index 780afd4..5476ad3 100644
--- a/lib/Sema/SemaTemplateInstantiateExpr.cpp
+++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp
@@ -321,13 +321,17 @@
Sema::OwningExprResult
TemplateExprInstantiator::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *E) {
- CXXScopeSpec SS = SemaRef.InstantiateScopeSpecifier(E->begin(), E->size(),
- E->getQualifierRange(),
- TemplateArgs,
- NumTemplateArgs);
- if (SS.isInvalid() || SS.isEmpty())
+ NestedNameSpecifier *NNS
+ = SemaRef.InstantiateNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange(),
+ TemplateArgs, NumTemplateArgs);
+ if (!NNS)
return SemaRef.ExprError();
+ CXXScopeSpec SS;
+ SS.setRange(E->getQualifierRange());
+ SS.setScopeRep(NNS);
+
// FIXME: We're passing in a NULL scope, because
// ActOnDeclarationNameExpr doesn't actually use the scope when we
// give it a non-empty scope specifier. Investigate whether it would
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 4b25657..0780ad8 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1101,9 +1101,7 @@
if (!SS.isSet() || SS.isInvalid() || T.isNull())
return T;
- llvm::SmallVector<NestedNameSpecifier, 4> Specs;
- for (CXXScopeSpec::iterator Spec = SS.begin(), SpecEnd = SS.end();
- Spec != SpecEnd; ++Spec)
- Specs.push_back(NestedNameSpecifier::getFromOpaquePtr(*Spec));
- return Context.getQualifiedNameType(&Specs[0], Specs.size(), T);
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+ return Context.getQualifiedNameType(NNS, T);
}