From: Douglas Gregor Date: Thu, 26 Mar 2009 23:50:42 +0000 (+0000) Subject: Revamp our representation of C++ nested-name-specifiers. We now have a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ab452ba8323d1985e08bade2bced588cddf2cc28;p=clang 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/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 36bf12b787..3cf48b4994 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -18,6 +18,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/AST/Builtins.h" #include "clang/AST/Decl.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Type.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMap.h" @@ -74,6 +75,14 @@ class ASTContext { llvm::FoldingSet QualifiedNameTypes; llvm::FoldingSet ObjCQualifiedInterfaceTypes; llvm::FoldingSet ObjCQualifiedIdTypes; + + /// \brief The set of nested name specifiers. + /// + /// This set is managed by the NestedNameSpecifier class. + llvm::FoldingSet NestedNameSpecifiers; + NestedNameSpecifier *GlobalNestedNameSpecifier; + friend class NestedNameSpecifier; + /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts. /// This is lazily created. This is intentionally not serialized. llvm::DenseMap ASTRecordLayouts; @@ -284,8 +293,7 @@ public: unsigned NumArgs, QualType Canon = QualType()); - QualType getQualifiedNameType(const NestedNameSpecifier *Components, - unsigned NumComponents, + QualType getQualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType); /// getObjCQualifiedInterfaceType - Return a diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 1292eaf2d2..366f860c50 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -856,34 +856,22 @@ class QualifiedDeclRefExpr : public DeclRefExpr { /// nested-name-specifier. SourceRange QualifierRange; - /// The number of components in the complete nested-name-specifier. - unsigned NumComponents; - - QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, - bool VD, SourceRange R, - const NestedNameSpecifier *Components, - unsigned NumComponents); + /// \brief The nested-name-specifier that qualifies this declaration + /// name. + NestedNameSpecifier *NNS; public: - static QualifiedDeclRefExpr *Create(ASTContext &Context, NamedDecl *d, - QualType t, SourceLocation l, bool TD, - bool VD, SourceRange R, - const NestedNameSpecifier *Components, - unsigned NumComponents); + QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, + bool VD, SourceRange R, NestedNameSpecifier *NNS) + : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD), + QualifierRange(R), NNS(NNS) { } /// \brief Retrieve the source range of the nested-name-specifier. SourceRange getQualifierRange() const { return QualifierRange; } - // Iteration over of the parts of the nested-name-specifier. - typedef const NestedNameSpecifier * iterator; - - iterator begin() const { - return reinterpret_cast(this + 1); - } - - iterator end() const { return begin() + NumComponents; } - - unsigned size() const { return NumComponents; } + /// \brief Retrieve the nested-name-specifier that qualifies this + /// declaration. + NestedNameSpecifier *getQualifier() const { return NNS; } virtual SourceRange getSourceRange() const { return SourceRange(QualifierRange.getBegin(), getLocation()); @@ -908,7 +896,10 @@ public: /// the qualification (e.g., X::) refers to a dependent type. In /// this case, X::value cannot resolve to a declaration because the /// declaration will differ from on instantiation of X to the -/// next. Therefore, UnresolvedDeclRefExpr keeps track of the qualifier (X::) and the name of the entity being referenced ("value"). Such expressions will instantiate to QualifiedDeclRefExprs. +/// next. Therefore, UnresolvedDeclRefExpr keeps track of the +/// qualifier (X::) and the name of the entity being referenced +/// ("value"). Such expressions will instantiate to +/// QualifiedDeclRefExprs. class UnresolvedDeclRefExpr : public Expr { /// The name of the entity we will be referencing. DeclarationName Name; @@ -920,18 +911,15 @@ class UnresolvedDeclRefExpr : public Expr { /// nested-name-specifier. SourceRange QualifierRange; - /// The number of components in the complete nested-name-specifier. - unsigned NumComponents; - - UnresolvedDeclRefExpr(DeclarationName N, QualType T, SourceLocation L, - SourceRange R, const NestedNameSpecifier *Components, - unsigned NumComponents); + /// \brief The nested-name-specifier that qualifies this unresolved + /// declaration name. + NestedNameSpecifier *NNS; public: - static UnresolvedDeclRefExpr *Create(ASTContext &Context, DeclarationName N, - SourceLocation L, SourceRange R, - const NestedNameSpecifier *Components, - unsigned NumComponents); + UnresolvedDeclRefExpr(DeclarationName N, QualType T, SourceLocation L, + SourceRange R, NestedNameSpecifier *NNS) + : Expr(UnresolvedDeclRefExprClass, T, true, true), + Name(N), Loc(L), QualifierRange(R), NNS(NNS) { } /// \brief Retrieve the name that this expression refers to. DeclarationName getDeclName() const { return Name; } @@ -942,16 +930,9 @@ public: /// \brief Retrieve the source range of the nested-name-specifier. SourceRange getQualifierRange() const { return QualifierRange; } - // Iteration over of the parts of the nested-name-specifier. - typedef const NestedNameSpecifier * iterator; - - iterator begin() const { - return reinterpret_cast(this + 1); - } - - iterator end() const { return begin() + NumComponents; } - - unsigned size() const { return NumComponents; } + /// \brief Retrieve the nested-name-specifier that qualifies this + /// declaration. + NestedNameSpecifier *getQualifier() const { return NNS; } virtual SourceRange getSourceRange() const { return SourceRange(QualifierRange.getBegin(), getLocation()); diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index a371e89638..a740efbe09 100644 --- a/include/clang/AST/NestedNameSpecifier.h +++ b/include/clang/AST/NestedNameSpecifier.h @@ -14,8 +14,8 @@ #ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H #define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H -#include "llvm/Support/DataTypes.h" -#include +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerIntPair.h" namespace llvm { class raw_ostream; @@ -24,93 +24,151 @@ namespace llvm { namespace clang { class ASTContext; -class DeclContext; +class DeclContext; // FIXME: die die die +class NamespaceDecl; +class IdentifierInfo; class Type; -/// \brief Represents a single component in a C++ nested-name-specifier. +/// \brief Represents a C++ nested name specifier, such as +/// "::std::vector::". /// -/// C++ nested-name-specifiers are the prefixes to qualified -/// namespaces. For example, "foo::" in "foo::x" is a -/// nested-name-specifier. Multiple nested-name-specifiers can be -/// strung together to build qualified names, e.g., "foo::bar::" in -/// "foo::bar::x". Each NestedNameSpecifier class contains one of the -/// terms, e.g., "foo::" or "bar::", which may be represented either -/// as a type or as a DeclContext. -class NestedNameSpecifier { - /// \brief A DeclContext or Type pointer, depending on whether the - /// low bit is set. - uintptr_t Data; +/// C++ nested name specifiers are the prefixes to qualified +/// namespaces. For example, "foo::" in "foo::x" is a nested name +/// specifier. Nested name specifiers are made up of a sequence of +/// specifiers, each of which can be a namespace, type, identifier +/// (for dependent names), or the global specifier ('::', must be the +/// first specifier). +class NestedNameSpecifier : public llvm::FoldingSetNode { + /// \brief The nested name specifier that precedes this nested name + /// specifier. + NestedNameSpecifier *Prefix; + + /// \brief The last component in the nested name specifier, which + /// can be an identifier, a declaration, or a type. + /// + /// When the pointer is NULL, this specifier represents the global + /// specifier '::'. Otherwise, the pointer is one of + /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of + /// specifier. The integer stores one ofthe first four values of + /// type SpecifierKind. + llvm::PointerIntPair Specifier; public: - NestedNameSpecifier() : Data(0) { } - - /// \brief Construct a nested name specifier that refers to a type. - NestedNameSpecifier(const Type *T) { - Data = reinterpret_cast(T); - assert((Data & 0x01) == 0 && "cv-qualified type in nested-name-specifier"); - Data |= 0x01; + /// \brief The kind of specifier that completes this nested name + /// specifier. + enum SpecifierKind { + /// \brief An identifier, stored as an IdentifierInfo*. + Identifier = 0, + /// \brief A namespace, stored as a Namespace*. + Namespace = 1, + /// \brief A type, stored as a Type*. + TypeSpec = 2, + /// \brief A type that was preceded by the 'template' keyword, + /// stored as a Type*. + TypeSpecWithTemplate = 3, + /// \brief The global specifier '::'. There is no stored value. + Global = 4 + }; + +private: + /// \brief Builds the global specifier. + NestedNameSpecifier() : Prefix(0), Specifier(0, 0) { } + + /// \brief Copy constructor used internally to clone nested name + /// specifiers. + NestedNameSpecifier(const NestedNameSpecifier &Other) + : llvm::FoldingSetNode(Other), Prefix(Other.Prefix), + Specifier(Other.Specifier) { } - /// \brief Construct nested name specifier that refers to a - /// DeclContext. - NestedNameSpecifier(const DeclContext *DC) { - Data = reinterpret_cast(DC); - assert((Data & 0x01) == 0 && "Badly aligned DeclContext pointer"); - } + NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not implement - /// \brief Determines whether this nested-name-specifier refers to a - /// type. Otherwise, it refers to a DeclContext. - bool isType() const { return Data & 0x01; } + /// \brief Either find or insert the given nested name specifier + /// mockup in the given context. + static NestedNameSpecifier *FindOrInsert(ASTContext &Context, const NestedNameSpecifier &Mockup); - /// \brief Compute the declaration context to which this - /// nested-name-specifier refers. +public: + /// \brief Builds a specifier combining a prefix and an identifier. /// - /// This routine computes the declaration context referenced by this - /// nested-name-specifier. The nested-name-specifier may store - /// either a DeclContext (the trivial case) or a non-dependent type - /// (which will have an associated DeclContext). It is an error to - /// invoke this routine when the nested-name-specifier refers to a - /// dependent type. + /// The prefix must be dependent, since nested name specifiers + /// referencing an identifier are only permitted when the identifier + /// cannot be resolved. + static NestedNameSpecifier *Create(ASTContext &Context, + NestedNameSpecifier *Prefix, + IdentifierInfo *II); + + /// \brief Builds a nested name specifier that names a namespace. + static NestedNameSpecifier *Create(ASTContext &Context, + NestedNameSpecifier *Prefix, + NamespaceDecl *NS); + + /// \brief Builds a nested name specifier that names a type. + static NestedNameSpecifier *Create(ASTContext &Context, + NestedNameSpecifier *Prefix, + bool Template, Type *T); + + /// \brief Returns the nested name specifier representing the global + /// scope. + static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context); + + /// \brief Return the prefix of this nested name specifier. /// - /// \returns The stored DeclContext, if the nested-name-specifier - /// stores a DeclContext. If the nested-name-specifier stores a - /// non-dependent type, returns the DeclContext associated with that - /// type. - DeclContext *computeDeclContext(ASTContext &Context) const; + /// The prefix contains all of the parts of the nested name + /// specifier that preced this current specifier. For example, for a + /// nested name specifier that represents "foo::bar::", the current + /// specifier will contain "bar::" and the prefix will contain + /// "foo::". + NestedNameSpecifier *getPrefix() const { return Prefix; } + + /// \brief Determine what kind of nested name specifier is stored. + SpecifierKind getKind() const { + if (Specifier.getPointer() == 0) + return Global; + return (SpecifierKind)Specifier.getInt(); + } - /// \brief Retrieve the nested-name-specifier as a type. - /// - /// \returns The stored type. If the nested-name-specifier does not - /// store a type, returns NULL. - Type *getAsType() const { - if (Data & 0x01) - return reinterpret_cast(Data & ~0x01); + /// \brief Retrieve the identifier stored in this nested name + /// specifier. + IdentifierInfo *getAsIdentifier() const { + if (Specifier.getInt() == Identifier) + return (IdentifierInfo *)Specifier.getPointer(); return 0; } + + /// \brief Retrieve the namespace stored in this nested name + /// specifier. + NamespaceDecl *getAsNamespace() const { + if (Specifier.getInt() == Namespace) + return (NamespaceDecl *)Specifier.getPointer(); - /// \brief Retrieves the nested-name-specifier as a DeclContext. - /// - /// \returns The stored DeclContext. If the nested-name-specifier - /// does not store a DeclContext, returns NULL. - DeclContext *getAsDeclContext() const { - if (Data & 0x01) - return 0; - return reinterpret_cast(Data); + return 0; } - /// \brief Retrieve nested name specifier as an opaque pointer. - void *getAsOpaquePtr() const { return reinterpret_cast(Data); } + /// \brief Retrieve the type stored in this nested name specifier. + Type *getAsType() const { + if (Specifier.getInt() == TypeSpec || + Specifier.getInt() == TypeSpecWithTemplate) + return (Type *)Specifier.getPointer(); + + return 0; + } + + /// \brief Whether this nested name specifier refers to a dependent + /// type or not. + bool isDependent() const; + + /// \brief Print this nested name specifier to the given output + /// stream. + void Print(llvm::raw_ostream &OS) const; - /// \brief Reconstruct a nested name specifier from an opaque pointer. - static NestedNameSpecifier getFromOpaquePtr(void *Ptr) { - NestedNameSpecifier NS; - NS.Data = reinterpret_cast(Ptr); - return NS; + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(Prefix); + ID.AddPointer(Specifier.getPointer()); + ID.AddInteger(Specifier.getInt()); } - static void Print(llvm::raw_ostream &OS, const NestedNameSpecifier *First, - const NestedNameSpecifier *Last); + void Destroy(ASTContext &Context); }; } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 3453cb09df..e37b186871 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1564,32 +1564,22 @@ protected: /// This type is used to keep track of a type name as written in the /// source code, including any nested-name-specifiers. class QualifiedNameType : public Type, public llvm::FoldingSetNode { - /// \brief The number of components in the qualified name, not - /// counting the final type. - unsigned NumComponents; + /// \brief The nested name specifier containing the qualifier. + NestedNameSpecifier *NNS; /// \brief The type that this qualified name refers to. QualType NamedType; - QualifiedNameType(const NestedNameSpecifier *Components, - unsigned NumComponents, QualType NamedType, - QualType CanonType); + QualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType, + QualType CanonType) + : Type(QualifiedName, CanonType, NamedType->isDependentType()), + NNS(NNS), NamedType(NamedType) { } friend class ASTContext; // ASTContext creates these public: - typedef const NestedNameSpecifier * iterator; - - iterator begin() const { return getComponents(); } - iterator end() const { return getComponents() + getNumComponents(); } - - /// \brief Retrieve the array of nested-name-specifier components. - const NestedNameSpecifier *getComponents() const { - return reinterpret_cast(this + 1); - } - - /// \brief Retrieve the number of nested-name-specifier components. - unsigned getNumComponents() const { return NumComponents; } + /// \brief Retrieve the qualification on this type. + NestedNameSpecifier *getQualifier() const { return NNS; } /// \brief Retrieve the type named by the qualified-id. QualType getNamedType() const { return NamedType; } @@ -1597,13 +1587,14 @@ public: virtual void getAsStringInternal(std::string &InnerString) const; void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getComponents(), NumComponents, NamedType); + Profile(ID, NNS, NamedType); } - static void Profile(llvm::FoldingSetNodeID &ID, - const NestedNameSpecifier *Components, - unsigned NumComponents, - QualType NamedType); + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + QualType NamedType) { + ID.AddPointer(NNS); + NamedType.Profile(ID); + } static bool classof(const Type *T) { return T->getTypeClass() == QualifiedName; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c656d966db..84976a0294 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -33,9 +33,9 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, bool FreeMem, unsigned size_reserve) : - CFConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), - SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), - Idents(idents), Selectors(sels) + GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), + ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts), + FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels) { if (size_reserve > 0) Types.reserve(size_reserve); InitBuiltinTypes(); @@ -77,7 +77,18 @@ ASTContext::~ASTContext() { } } + // Destroy nested-name-specifiers. + for (llvm::FoldingSet::iterator + NNS = NestedNameSpecifiers.begin(), + NNSEnd = NestedNameSpecifiers.end(); + NNS != NNSEnd; ++NNS) + NNS->Destroy(*this); + + if (GlobalNestedNameSpecifier) + GlobalNestedNameSpecifier->Destroy(*this); + TUDecl->Destroy(*this); + } void ASTContext::PrintStats() const { @@ -1376,11 +1387,10 @@ ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template, } QualType -ASTContext::getQualifiedNameType(const NestedNameSpecifier *Components, - unsigned NumComponents, +ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType) { llvm::FoldingSetNodeID ID; - QualifiedNameType::Profile(ID, Components, NumComponents, NamedType); + QualifiedNameType::Profile(ID, NNS, NamedType); void *InsertPos = 0; QualifiedNameType *T @@ -1388,11 +1398,8 @@ ASTContext::getQualifiedNameType(const NestedNameSpecifier *Components, if (T) return QualType(T, 0); - void *Mem = Allocate((sizeof(QualifiedNameType) + - sizeof(NestedNameSpecifier) * NumComponents), - 8); - T = new (Mem) QualifiedNameType(Components, NumComponents, NamedType, - getCanonicalType(NamedType)); + T = new (*this) QualifiedNameType(NNS, NamedType, + getCanonicalType(NamedType)); Types.push_back(T); QualifiedNameTypes.InsertNode(T, InsertPos); return QualType(T, 0); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 5a9de19254..c2fcc5f9ee 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -24,54 +24,6 @@ void CXXConditionDeclExpr::Destroy(ASTContext& C) { C.Deallocate(this); } -QualifiedDeclRefExpr::QualifiedDeclRefExpr(NamedDecl *d, QualType t, - SourceLocation l, bool TD, - bool VD, SourceRange R, - const NestedNameSpecifier *Components, - unsigned NumComponents) - : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD), - QualifierRange(R), NumComponents(NumComponents) { - NestedNameSpecifier *Data - = reinterpret_cast(this + 1); - for (unsigned I = 0; I < NumComponents; ++I) - Data[I] = Components[I]; -} - -QualifiedDeclRefExpr * -QualifiedDeclRefExpr::Create(ASTContext &Context, NamedDecl *d, QualType t, - SourceLocation l, bool TD, - bool VD, SourceRange R, - const NestedNameSpecifier *Components, - unsigned NumComponents) { - void *Mem = Context.Allocate((sizeof(QualifiedDeclRefExpr) + - sizeof(NestedNameSpecifier) * NumComponents)); - return new (Mem) QualifiedDeclRefExpr(d, t, l, TD, VD, R, Components, - NumComponents); -} - -UnresolvedDeclRefExpr::UnresolvedDeclRefExpr(DeclarationName N, QualType T, - SourceLocation L, SourceRange R, - const NestedNameSpecifier *Components, - unsigned NumComponents) - : Expr(UnresolvedDeclRefExprClass, T, true, true), - Name(N), Loc(L), QualifierRange(R), NumComponents(NumComponents) { - NestedNameSpecifier *Data - = reinterpret_cast(this + 1); - for (unsigned I = 0; I < NumComponents; ++I) - Data[I] = Components[I]; -} - -UnresolvedDeclRefExpr * -UnresolvedDeclRefExpr::Create(ASTContext &Context, DeclarationName N, - SourceLocation L, SourceRange R, - const NestedNameSpecifier *Components, - unsigned NumComponents) { - void *Mem = Context.Allocate((sizeof(UnresolvedDeclRefExpr) + - sizeof(NestedNameSpecifier) * NumComponents)); - return new (Mem) UnresolvedDeclRefExpr(N, Context.DependentTy, L, R, - Components, NumComponents); -} - //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index ea4b506e64..62e972efd5 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -16,46 +16,137 @@ #include "clang/AST/Decl.h" #include "clang/AST/Type.h" #include "llvm/Support/raw_ostream.h" +#include using namespace clang; -DeclContext * -NestedNameSpecifier::computeDeclContext(ASTContext &Context) const { - // The simple case: we're storing a DeclContext - if ((Data & 0x01) == 0) - return reinterpret_cast(Data); - - Type *T = getAsType(); - if (!T) - return 0; - - // Retrieve the DeclContext associated with this type. - const TagType *TagT = T->getAsTagType(); - assert(TagT && "No DeclContext from a non-tag type"); - return TagT->getDecl(); -} - -void NestedNameSpecifier::Print(llvm::raw_ostream &OS, - const NestedNameSpecifier *First, - const NestedNameSpecifier *Last) { - for (; First != Last; ++First) { - if (Type *T = First->getAsType()) { - std::string TypeStr; - - // If this is a qualified name type, suppress the qualification: - // it's part of our nested-name-specifier sequence anyway. - if (const QualifiedNameType *QualT = dyn_cast(T)) - T = QualT->getNamedType().getTypePtr(); - - if (const TagType *TagT = dyn_cast(T)) - TagT->getAsStringInternal(TypeStr, true); - else - T->getAsStringInternal(TypeStr); - OS << TypeStr; - } else if (NamedDecl *NamedDC - = dyn_cast_or_null(First->getAsDeclContext())) - OS << NamedDC->getNameAsString(); +NestedNameSpecifier * +NestedNameSpecifier::FindOrInsert(ASTContext &Context, + const NestedNameSpecifier &Mockup) { + llvm::FoldingSetNodeID ID; + Mockup.Profile(ID); + + void *InsertPos = 0; + NestedNameSpecifier *NNS + = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos); + if (!NNS) { + NNS = new (Context) NestedNameSpecifier(Mockup); + Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos); + } + + return NNS; +} + +NestedNameSpecifier * +NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, + IdentifierInfo *II) { + assert(II && "Identifier cannot be NULL"); + assert(Prefix && Prefix->isDependent() && "Prefix must be dependent"); + + NestedNameSpecifier Mockup; + Mockup.Prefix = Prefix; + Mockup.Specifier.setPointer(II); + Mockup.Specifier.setInt(Identifier); + return FindOrInsert(Context, Mockup); +} + +NestedNameSpecifier * +NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, + NamespaceDecl *NS) { + assert(NS && "Namespace cannot be NULL"); + assert((!Prefix || + (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) && + "Broken nested name specifier"); + NestedNameSpecifier Mockup; + Mockup.Prefix = Prefix; + Mockup.Specifier.setPointer(NS); + Mockup.Specifier.setInt(Namespace); + return FindOrInsert(Context, Mockup); +} + +NestedNameSpecifier * +NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, + bool Template, Type *T) { + assert(T && "Type cannot be NULL"); + NestedNameSpecifier Mockup; + Mockup.Prefix = Prefix; + Mockup.Specifier.setPointer(T); + Mockup.Specifier.setInt(Template? TypeSpecWithTemplate : TypeSpec); + return FindOrInsert(Context, Mockup); +} - OS << "::"; +NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) { + if (!Context.GlobalNestedNameSpecifier) + Context.GlobalNestedNameSpecifier = new (Context) NestedNameSpecifier(); + return Context.GlobalNestedNameSpecifier; +} + +/// \brief Whether this nested name specifier refers to a dependent +/// type or not. +bool NestedNameSpecifier::isDependent() const { + switch (getKind()) { + case Identifier: + // Identifier specifiers always represent dependent types + return true; + + case Namespace: + case Global: + return false; + + case TypeSpec: + case TypeSpecWithTemplate: + return getAsType()->isDependentType(); } + + // Necessary to suppress a GCC warning. + return false; +} + +/// \brief Print this nested name specifier to the given output +/// stream. +void NestedNameSpecifier::Print(llvm::raw_ostream &OS) const { + if (Prefix) + Prefix->Print(OS); + + switch (getKind()) { + case Identifier: + OS << getAsIdentifier()->getName(); + break; + + case Namespace: + OS << getAsNamespace()->getIdentifier()->getName(); + break; + + case Global: + break; + + case TypeSpecWithTemplate: + OS << "template "; + // Fall through to print the type. + + case TypeSpec: { + std::string TypeStr; + Type *T = getAsType(); + + // If this is a qualified name type, suppress the qualification: + // it's part of our nested-name-specifier sequence anyway. FIXME: + // We should be able to assert that this doesn't happen. + if (const QualifiedNameType *QualT = dyn_cast(T)) + T = QualT->getNamedType().getTypePtr(); + + if (const TagType *TagT = dyn_cast(T)) + TagT->getAsStringInternal(TypeStr, true); + else + T->getAsStringInternal(TypeStr); + OS << TypeStr; + break; + } + } + + OS << "::"; +} + +void NestedNameSpecifier::Destroy(ASTContext &Context) { + this->~NestedNameSpecifier(); + Context.Deallocate((void *)this); } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 60300ba04e..bd5e22491e 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -533,12 +533,12 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) { NamedDecl *D = Node->getDecl(); - NestedNameSpecifier::Print(OS, Node->begin(), Node->end()); + Node->getQualifier()->Print(OS); OS << D->getNameAsString(); } void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { - NestedNameSpecifier::Print(OS, Node->begin(), Node->end()); + Node->getQualifier()->Print(OS); OS << Node->getDeclName().getAsString(); } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 19a3f14423..103c0a9134 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1047,28 +1047,6 @@ ClassTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, Args[Idx].Profile(ID); } -QualifiedNameType::QualifiedNameType(const NestedNameSpecifier *Components, - unsigned NumComponents, - QualType NamedType, - QualType CanonType) - : Type(QualifiedName, CanonType, NamedType->isDependentType()), - NumComponents(NumComponents), NamedType(NamedType) { - NestedNameSpecifier *InitComponents - = reinterpret_cast(this + 1); - for (unsigned I = 0; I < NumComponents; ++I) - new (InitComponents + I) NestedNameSpecifier(Components[I]); -} - -void QualifiedNameType::Profile(llvm::FoldingSetNodeID &ID, - const NestedNameSpecifier *Components, - unsigned NumComponents, - QualType NamedType) { - ID.AddInteger(NumComponents); - for (unsigned I = 0; I < NumComponents; ++I) - ID.AddPointer(Components[I].getAsOpaquePtr()); - NamedType.Profile(ID); -} - //===----------------------------------------------------------------------===// // Type Printing //===----------------------------------------------------------------------===// @@ -1440,7 +1418,7 @@ void QualifiedNameType::getAsStringInternal(std::string &InnerString) const { { llvm::raw_string_ostream OS(MyString); - NestedNameSpecifier::Print(OS, begin(), end()); + NNS->Print(OS); } std::string TypeStr; diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp index 6f93a1859f..4490847a56 100644 --- a/lib/AST/TypeSerialization.cpp +++ b/lib/AST/TypeSerialization.cpp @@ -421,9 +421,7 @@ CreateImpl(ASTContext& Context, Deserializer& D) { // QualifiedNameType //===----------------------------------------------------------------------===// void QualifiedNameType::EmitImpl(llvm::Serializer& S) const { - S.EmitInt(NumComponents); // FIXME: Serialize the actual components - S.Emit(NamedType); } Type* diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 9d71cf3229..8c8cae2c8c 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1940,11 +1940,11 @@ public: 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 diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 9e1196143b..ca864a2a2e 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -24,24 +24,41 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) { if (!SS.isSet() || SS.isInvalid()) return 0; - NestedNameSpecifier NNS - = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep()); - return NNS.computeDeclContext(Context); + NestedNameSpecifier *NNS + = static_cast(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(SS.getCurrentScopeRep()); + return NNS->isDependent(); } /// \brief Require that the context specified by SS be complete. @@ -79,7 +96,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { /// 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,20 +110,38 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II) { + NestedNameSpecifier *Prefix + = static_cast(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(SD)) { - if (TD->getUnderlyingType()->isRecordType()) - return NestedNameSpecifier(Context.getTypeDeclType(TD).getTypePtr()) - .getAsOpaquePtr(); - } else if (isa(SD) || isa(SD)) { - return NestedNameSpecifier(cast(SD)).getAsOpaquePtr(); + if (NamespaceDecl *Namespace = dyn_cast(SD)) + return NestedNameSpecifier::Create(Context, Prefix, Namespace); + + if (TypeDecl *Type = dyn_cast(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(SD)) { + if (TD->getUnderlyingType()->isRecordType() || + (getLangOptions().CPlusPlus0x && + TD->getUnderlyingType()->isEnumeralType())) + T = Context.getTypeDeclType(TD); + } else if (isa(Type) || + (getLangOptions().CPlusPlus0x && isa(Type))) + T = Context.getTypeDeclType(Type); + + if (!T.isNull()) + return NestedNameSpecifier::Create(Context, Prefix, false, + T.getTypePtr()); } - // FIXME: Template parameters and dependent types. - // FIXME: C++0x scoped enums - // Fall through to produce an error: we found something that isn't // a class or a namespace. } @@ -137,8 +172,10 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, TypeTy *Ty, SourceRange TypeRange, SourceLocation CCLoc) { - return NestedNameSpecifier(QualType::getFromOpaquePtr(Ty).getTypePtr()) - .getAsOpaquePtr(); + NestedNameSpecifier *Prefix + = static_cast(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 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?"); PreDeclaratorDC = static_cast(S->getEntity()); CurContext = computeDeclContext(SS); + assert(CurContext && "No context?"); S->setEntity(CurContext); } @@ -170,4 +208,5 @@ void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { while (!S->getEntity() && S->getParent()) S = S->getParent(); CurContext = static_cast(S->getEntity()); + assert(CurContext && "No context?"); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index cb44cfc186..bb306e4a0f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1159,9 +1159,13 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { /// 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(Method->getDeclContext())); + SS.setScopeRep( + NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr())); ActOnCXXEnterDeclaratorScope(S, SS); } @@ -1192,7 +1196,10 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *ParamD) { void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *MethodD) { FunctionDecl *Method = (FunctionDecl*)MethodD; CXXScopeSpec SS; - SS.setScopeRep(Method->getDeclContext()); + QualType ClassTy + = Context.getTypeDeclType(cast(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 c46bde00ff..288b617191 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -440,13 +440,9 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, bool TypeDependent, bool ValueDependent, const CXXScopeSpec *SS) { if (SS && !SS->isEmpty()) { - llvm::SmallVector 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(SS->getCurrentScopeRep())); } else return new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent); } @@ -619,13 +615,9 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // -- a nested-name-specifier that contains a class-name that // names a dependent type. if (SS && isDependentScopeSpecifier(*SS)) { - llvm::SmallVector 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(SS->getCurrentScopeRep()))); } LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName, @@ -2302,12 +2294,11 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, Expr *NewFn = 0; if (QualifiedDeclRefExpr *QDRExpr = dyn_cast_or_null(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 f6e36bf779..52f87b93f7 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -768,33 +768,52 @@ Sema::InstantiateClassTemplateSpecialization( 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; + } + + 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()); + } } - SS.setRange(Range); - return SS; + // Required to silence GCC warning. + return 0; } diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index 780afd4468..5476ad3502 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -321,13 +321,17 @@ TemplateExprInstantiator::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { 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 4b2565795a..0780ad8f4a 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1101,9 +1101,7 @@ QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) { if (!SS.isSet() || SS.isInvalid() || T.isNull()) return T; - llvm::SmallVector 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(SS.getCurrentScopeRep()); + return Context.getQualifiedNameType(NNS, T); }