diff options
26 files changed, 566 insertions, 99 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 124f7db449..f4df88c94c 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -72,6 +72,7 @@ class ASTContext { llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; llvm::FoldingSet<ClassTemplateSpecializationType> ClassTemplateSpecializationTypes; + llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes; llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes; llvm::FoldingSet<ObjCQualifiedIdType> ObjCQualifiedIdTypes; /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts. @@ -284,6 +285,10 @@ public: unsigned NumArgs, QualType Canon = QualType()); + QualType getQualifiedNameType(const NestedNameSpecifier *Components, + unsigned NumComponents, + QualType NamedType); + /// getObjCQualifiedInterfaceType - Return a /// ObjCQualifiedInterfaceType type for the given interface decl and /// the conforming protocol list. diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h new file mode 100644 index 0000000000..cdf04b06db --- /dev/null +++ b/include/clang/AST/NestedNameSpecifier.h @@ -0,0 +1,111 @@ +//===--- NestedNameSpecifier.h - C++ nested name specifiers -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the NestedNameSpecifier class, which represents +// a C++ nested-name-specifier. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H +#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H + +#include "llvm/Support/DataTypes.h" +#include <cassert> + +namespace clang { + +class ASTContext; +class DeclContext; +class Type; + +/// \brief Represents a single component in a C++ nested-name-specifier. +/// +/// 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; + +public: + NestedNameSpecifier() : Data(0) { } + + /// \brief Construct a nested name specifier that refers to a type. + NestedNameSpecifier(const Type *T) { + Data = reinterpret_cast<uintptr_t>(T); + assert((Data & 0x01) == 0 && "cv-qualified type in nested-name-specifier"); + Data |= 0x01; + } + + /// \brief Construct nested name specifier that refers to a + /// DeclContext. + NestedNameSpecifier(const DeclContext *DC) { + Data = reinterpret_cast<uintptr_t>(DC); + assert((Data & 0x01) == 0 && "Badly aligned DeclContext pointer"); + } + + /// \brief Determines whether this nested-name-specifier refers to a + /// type. Otherwise, it refers to a DeclContext. + bool isType() const { return Data & 0x01; } + + /// \brief Compute the declaration context to which this + /// nested-name-specifier refers. + /// + /// 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. + /// + /// \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; + + /// \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<Type *>(Data & ~0x01); + + return 0; + } + + /// \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<DeclContext *>(Data); + } + + /// \brief Retrieve nested name specifier as an opaque pointer. + void *getAsOpaquePtr() const { return reinterpret_cast<void *>(Data); } + + /// \brief Reconstruct a nested name specifier from an opaque pointer. + static NestedNameSpecifier getFromOpaquePtr(void *Ptr) { + NestedNameSpecifier NS; + NS.Data = reinterpret_cast<uintptr_t>(Ptr); + return NS; + } +}; + +} + +#endif diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 94368b707d..b4e609dc3b 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_TYPE_H #include "clang/Basic/Diagnostic.h" +#include "clang/AST/NestedNameSpecifier.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/FoldingSet.h" @@ -47,6 +48,7 @@ namespace clang { class SourceLocation; class StmtIteratorBase; class TemplateArgument; + class QualifiedNameType; // Provide forward declarations for all of the *Type classes #define TYPE(Class, Base) class Class##Type; @@ -1357,7 +1359,9 @@ public: void setBeingDefined(bool Def) { decl.setInt(Def? 1 : 0); } virtual void getAsStringInternal(std::string &InnerString) const; - + void getAsStringInternal(std::string &InnerString, + bool SuppressTagKind) const; + static bool classof(const Type *T) { return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast; } @@ -1548,6 +1552,64 @@ protected: friend class Type; }; +/// \brief Represents a type that was referred to via a qualified +/// name, e.g., N::M::type. +/// +/// 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 type that this qualified name refers to. + QualType NamedType; + + QualifiedNameType(const NestedNameSpecifier *Components, + unsigned NumComponents, QualType NamedType, + QualType CanonType); + + 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<const NestedNameSpecifier *>(this + 1); + } + + /// \brief Retrieve the number of nested-name-specifier components. + unsigned getNumComponents() const { return NumComponents; } + + /// \brief Retrieve the type named by the qualified-id. + QualType getNamedType() const { return NamedType; } + + virtual void getAsStringInternal(std::string &InnerString) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getComponents(), NumComponents, NamedType); + } + + static void Profile(llvm::FoldingSetNodeID &ID, + const NestedNameSpecifier *Components, + unsigned NumComponents, + QualType NamedType); + + static bool classof(const Type *T) { + return T->getTypeClass() == QualifiedName; + } + static bool classof(const QualifiedNameType *T) { return true; } + +protected: + virtual void EmitImpl(llvm::Serializer& S) const; + static Type* CreateImpl(ASTContext& Context, llvm::Deserializer& D); + friend class Type; +}; + /// ObjCInterfaceType - Interfaces are the core concept in Objective-C for /// object oriented design. They basically correspond to C++ classes. There /// are two kinds of interface types, normal interfaces like "NSString" and diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 4c5c02d2a5..e1e79aab53 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -73,6 +73,7 @@ TYPE(Record, TagType) TYPE(Enum, TagType) DEPENDENT_TYPE(TemplateTypeParm, Type) NON_CANONICAL_TYPE(ClassTemplateSpecialization, Type) +NON_CANONICAL_TYPE(QualifiedName, Type) TYPE(ObjCInterface, Type) TYPE(ObjCQualifiedInterface, ObjCInterfaceType) TYPE(ObjCQualifiedId, Type) diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 3c6995e50b..9c19a1a2d5 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -397,10 +397,36 @@ private: /// specifier. class CXXScopeSpec { SourceRange Range; - Action::CXXScopeTy *ScopeRep; + + /// Storage containing the scope representations for up to four + /// levels of nested-name-specifier. NumScopeReps specifiers how + /// many levels there are. If there are more than four, we use + /// ManyScopeReps. + Action::CXXScopeTy *InlineScopeReps[4]; + + /// The number of scope representations we've stored. + unsigned NumScopeReps; + + /// The number of scope representations we can store without + /// allocating new memory. + unsigned Capacity; + + // If there are > 4 scope representations, a pointer to those scope + // representations. + Action::CXXScopeTy **ManyScopeReps; + + void reallocate(); public: - CXXScopeSpec() : ScopeRep(0) {} + CXXScopeSpec() : NumScopeReps(0), Capacity(4) { } + + CXXScopeSpec(const CXXScopeSpec &SS); + + CXXScopeSpec &operator=(const CXXScopeSpec &SS); + + ~CXXScopeSpec() { + clear(); + } const SourceRange &getRange() const { return Range; } void setRange(const SourceRange &R) { Range = R; } @@ -409,21 +435,82 @@ public: SourceLocation getBeginLoc() const { return Range.getBegin(); } SourceLocation getEndLoc() const { return Range.getEnd(); } - Action::CXXScopeTy *getScopeRep() const { return ScopeRep; } - void setScopeRep(Action::CXXScopeTy *S) { ScopeRep = S; } + typedef Action::CXXScopeTy * const * iterator; + + iterator begin() const { + if (NumScopeReps > 4) + return ManyScopeReps; + else + return &InlineScopeReps[0]; + } + + iterator end() const { + return begin() + NumScopeReps; + } + + Action::CXXScopeTy *getScopeRep(unsigned I) const { + assert(I < size() && "Out-of-range scope index"); + return begin()[I]; + } + unsigned size() const { return NumScopeReps; } + + void addScopeRep(Action::CXXScopeTy *S) { + if (!S) + return; + + if (NumScopeReps >= Capacity) + reallocate(); + + if (Capacity == 4) + InlineScopeReps[NumScopeReps++] = S; + else + ManyScopeReps[NumScopeReps++] = S; + } + + Action::CXXScopeTy *getCurrentScopeRep() const { + if (size() == 0) + return 0; + return begin()[size() - 1]; + } + + void setScopeRep(Action::CXXScopeTy *S) { + if (Capacity > 4) + delete [] ManyScopeReps; + Capacity = 4; + NumScopeReps = 0; + addScopeRep(S); + } bool isEmpty() const { return !Range.isValid(); } bool isNotEmpty() const { return !isEmpty(); } /// isInvalid - An error occured during parsing of the scope specifier. - bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; } + bool isInvalid() const { return isNotEmpty() && NumScopeReps == 0; } /// isSet - A scope specifier was resolved to a valid C++ scope. - bool isSet() const { return getScopeRep() != 0; } + bool isSet() const { return getCurrentScopeRep() != 0; } void clear() { Range = SourceRange(); - ScopeRep = 0; + if (NumScopeReps > 4) + delete [] ManyScopeReps; + NumScopeReps = 0; + Capacity = 4; + } + + /// \brief Allocate and build the information that will be attached + /// to a scope-annotation token. + void *buildAnnotationData() const; + + /// \brief Reconstruct a scope specifier from the annotation data. + /// + /// This routine does not free the annotation data; call + /// freeAnnotationData for that. + void setFromAnnotationData(void *Data); + + /// Frees the annotation data. + static void freeAnnotationData(void *Data) { + delete [] (uintptr_t *) Data; } }; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c318107dab..c5441dd304 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1375,6 +1375,29 @@ ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template, return QualType(Spec, 0); } +QualType +ASTContext::getQualifiedNameType(const NestedNameSpecifier *Components, + unsigned NumComponents, + QualType NamedType) { + llvm::FoldingSetNodeID ID; + QualifiedNameType::Profile(ID, Components, NumComponents, NamedType); + + void *InsertPos = 0; + QualifiedNameType *T + = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + void *Mem = Allocate((sizeof(QualifiedNameType) + + sizeof(NestedNameSpecifier) * NumComponents), + 8); + T = new (Mem) QualifiedNameType(Components, NumComponents, NamedType, + getCanonicalType(NamedType)); + Types.push_back(T); + QualifiedNameTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + /// CmpProtocolNames - Comparison predicate for sorting protocols /// alphabetically. static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 48b1971112..5ea7a47fd6 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -18,6 +18,7 @@ add_clang_library(clangAST Expr.cpp ExprCXX.cpp InheritViz.cpp + NestedNameSpecifier.cpp ParentMap.cpp Stmt.cpp StmtDumper.cpp diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp new file mode 100644 index 0000000000..318c05fe7c --- /dev/null +++ b/lib/AST/NestedNameSpecifier.cpp @@ -0,0 +1,34 @@ +//===--- NestedNameSpecifier.cpp - C++ nested name specifiers -----*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the NestedNameSpecifier class, which represents +// a C++ nested-name-specifier. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +using namespace clang; + +DeclContext * +NestedNameSpecifier::computeDeclContext(ASTContext &Context) const { + // The simple case: we're storing a DeclContext + if ((Data & 0x01) == 0) + return reinterpret_cast<DeclContext *>(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(); +} diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index bb3df0882f..b066802c67 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -96,6 +96,8 @@ QualType Type::getDesugaredType() const { if (const ClassTemplateSpecializationType *Spec = dyn_cast<ClassTemplateSpecializationType>(this)) return Spec->getCanonicalTypeInternal().getDesugaredType(); + if (const QualifiedNameType *QualName = dyn_cast<QualifiedNameType>(this)) + return QualName->getNamedType().getDesugaredType(); // FIXME: remove this cast. return QualType(const_cast<Type*>(this), 0); @@ -1045,6 +1047,28 @@ 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<NestedNameSpecifier *>(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 //===----------------------------------------------------------------------===// @@ -1411,6 +1435,38 @@ getAsStringInternal(std::string &InnerString) const { InnerString = SpecString + ' ' + InnerString; } +void QualifiedNameType::getAsStringInternal(std::string &InnerString) const { + std::string MyString; + + for (iterator Comp = begin(), CompEnd = end(); Comp != CompEnd; ++Comp) { + if (Type *T = Comp->getAsType()) { + std::string TypeStr; + if (const TagType *TagT = dyn_cast<TagType>(T)) + TagT->getAsStringInternal(TypeStr, true); + else + T->getAsStringInternal(TypeStr); + + MyString += TypeStr; + } else if (NamedDecl *NamedDC + = dyn_cast_or_null<NamedDecl>(Comp->getAsDeclContext())) + MyString += NamedDC->getNameAsString(); + MyString += "::"; + } + + std::string TypeStr; + if (const TagType *TagT = dyn_cast<TagType>(NamedType.getTypePtr())) { + // Suppress printing of 'enum', 'struct', 'union', or 'class'. + TagT->getAsStringInternal(TypeStr, true); + } else + NamedType.getAsStringInternal(TypeStr); + + MyString += TypeStr; + if (InnerString.empty()) + InnerString.swap(MyString); + else + InnerString = MyString + ' ' + InnerString; +} + void ObjCInterfaceType::getAsStringInternal(std::string &InnerString) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; @@ -1451,10 +1507,15 @@ void ObjCQualifiedIdType::getAsStringInternal(std::string &InnerString) const { } void TagType::getAsStringInternal(std::string &InnerString) const { + getAsStringInternal(InnerString, false); +} + +void TagType::getAsStringInternal(std::string &InnerString, + bool SuppressTagKind) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; - const char *Kind = getDecl()->getKindName(); + const char *Kind = SuppressTagKind? 0 : getDecl()->getKindName(); const char *ID; if (const IdentifierInfo *II = getDecl()->getIdentifier()) ID = II->getName(); diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp index 8498e0123e..6f93a1859f 100644 --- a/lib/AST/TypeSerialization.cpp +++ b/lib/AST/TypeSerialization.cpp @@ -418,6 +418,21 @@ 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* +QualifiedNameType::CreateImpl(ASTContext& Context, llvm::Deserializer& D) { + // FIXME: Implement de-serialization + return 0; +} + +//===----------------------------------------------------------------------===// // VariableArrayType //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index b0cf07789b..cec39fd71a 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -525,6 +525,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, case Type::BlockPointer: case Type::MemberPointer: case Type::ClassTemplateSpecialization: + case Type::QualifiedName: case Type::ObjCQualifiedClass: // Unsupported types return llvm::DIType(); diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index a498182df7..72ac3112f9 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/STLExtras.h" +#include <cstring> using namespace clang; @@ -23,6 +24,66 @@ static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc, return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID); } +/// \brief Double the capacity of this scope specifier. +void CXXScopeSpec::reallocate() { + Action::CXXScopeTy **Data = new Action::CXXScopeTy *[Capacity * 2]; + + Action::CXXScopeTy **From + = Capacity == 4? &InlineScopeReps[0] : ManyScopeReps; + std::memcpy(Data, From, Capacity * sizeof(Action::CXXScopeTy *)); + + if (Capacity > 4) + delete [] ManyScopeReps; + ManyScopeReps = Data; + Capacity *= 2; +} + +CXXScopeSpec::CXXScopeSpec(const CXXScopeSpec &SS) + : Range(SS.Range), NumScopeReps(SS.NumScopeReps), Capacity(SS.Capacity) { + + if (Capacity > 4) { + ManyScopeReps = new Action::CXXScopeTy *[Capacity]; + memcpy(ManyScopeReps, SS.ManyScopeReps, + Capacity * sizeof(Action::CXXScopeTy *)); + } else { + memcpy(InlineScopeReps, SS.InlineScopeReps, + Capacity * sizeof(Action::CXXScopeTy *)); + } +} + +CXXScopeSpec &CXXScopeSpec::operator=(const CXXScopeSpec &SS) { + // FIXME: Does not provide the strong exception safety guarantee. + this->~CXXScopeSpec(); + new (this) CXXScopeSpec(SS); + return *this; +} + +void *CXXScopeSpec::buildAnnotationData() const { + uintptr_t *Data = (uintptr_t *)malloc(sizeof(uintptr_t) * (size() + 1)); + Data[0] = size(); + for (unsigned I = 0; I < size(); ++I) + Data[I + 1] = reinterpret_cast<uintptr_t>(getScopeRep(I)); + return Data; +} + +void CXXScopeSpec::setFromAnnotationData(void *DataIn) { + uintptr_t *Data = static_cast<uintptr_t *>(DataIn); + NumScopeReps = *Data; + + // Allocate enough space for the annotation data. + if (NumScopeReps > Capacity) { + if (Capacity > 4) + delete [] ManyScopeReps; + + Capacity = NumScopeReps; + ManyScopeReps = new Action::CXXScopeTy *[Capacity]; + } + + if (Capacity > 4) + std::memcpy(ManyScopeReps, Data + 1, sizeof(uintptr_t) * NumScopeReps); + else + std::memcpy(InlineScopeReps, Data + 1, sizeof(uintptr_t) * NumScopeReps); +} /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 25565e6576..0dddfdff79 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -491,7 +491,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, goto DoneWithDeclSpec; CXXScopeSpec SS; - SS.setScopeRep(Tok.getAnnotationValue()); + SS.setFromAnnotationData(Tok.getAnnotationValue()); SS.setRange(Tok.getAnnotationRange()); // If the next token is the name of the class type that the C++ scope @@ -508,7 +508,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (TypeRep == 0) goto DoneWithDeclSpec; - + + CXXScopeSpec::freeAnnotationData(Tok.getAnnotationValue()); ConsumeToken(); // The C++ scope. isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index e1b5db9c44..731f4c7957 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -36,7 +36,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { - SS.setScopeRep(Tok.getAnnotationValue()); + SS.setFromAnnotationData(Tok.getAnnotationValue()); + CXXScopeSpec::freeAnnotationData(Tok.getAnnotationValue()); SS.setRange(Tok.getAnnotationRange()); ConsumeToken(); return true; @@ -53,7 +54,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { // '::' - Global scope qualifier. SourceLocation CCLoc = ConsumeToken(); SS.setBeginLoc(CCLoc); - SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc)); + SS.addScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc)); SS.setEndLoc(CCLoc); HasScopeSpecifier = true; } @@ -79,7 +80,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { if (SS.isInvalid()) continue; - SS.setScopeRep( + SS.addScopeRep( Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II)); SS.setEndLoc(CCLoc); continue; @@ -149,7 +150,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { if (TemplateId->Kind == TNK_Class_template) { if (AnnotateTemplateIdTokenAsType(&SS)) - SS.setScopeRep(0); + SS.clear(); assert(Tok.is(tok::annot_typename) && "AnnotateTemplateIdTokenAsType isn't working"); @@ -164,7 +165,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { HasScopeSpecifier = true; } - SS.setScopeRep( + SS.addScopeRep( Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, TypeToken.getAnnotationValue(), TypeToken.getAnnotationRange(), diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 5666051fe5..8c3ff443f1 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -856,7 +856,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { else PP.EnterToken(Tok); Tok.setKind(tok::annot_cxxscope); - Tok.setAnnotationValue(SS.getScopeRep()); + Tok.setAnnotationValue(SS.buildAnnotationData()); Tok.setAnnotationRange(SS.getRange()); // In case the tokens were cached, have Preprocessor replace them with the @@ -888,7 +888,7 @@ bool Parser::TryAnnotateCXXScopeToken() { else PP.EnterToken(Tok); Tok.setKind(tok::annot_cxxscope); - Tok.setAnnotationValue(SS.getScopeRep()); + Tok.setAnnotationValue(SS.buildAnnotationData()); Tok.setAnnotationRange(SS.getRange()); // In case the tokens were cached, have Preprocessor replace them with the diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index d84829a0c7..5106a54f95 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1451,21 +1451,8 @@ public: SourceLocation RParen); bool RequireCompleteDeclContext(const CXXScopeSpec &SS); - - /// \brief Build a scope representation from a declaration context. - CXXScopeTy *createScopeRep(DeclContext *DC) { - return static_cast<CXXScopeTy *>(DC); - } - - /// \brief Build a scope representation from a type. - CXXScopeTy *createScopeRep(QualType T); - - DeclContext *getScopeRepAsDeclContext(const CXXScopeSpec &SS); - QualType getScopeRepAsType(const CXXScopeSpec &SS); - - /// \brief Determines whether this scope specifier is represented as - /// a type. - bool isScopeRepType(const CXXScopeSpec &SS); + + DeclContext *computeDeclContext(const CXXScopeSpec &SS); /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index e30ec2adcf..156f3a12fb 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -13,51 +13,20 @@ #include "Sema.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/Parse/DeclSpec.h" #include "llvm/ADT/STLExtras.h" using namespace clang; -/// \brief Retrieve the scope represented by this scope specifier as a -/// DeclContext. -DeclContext *Sema::getScopeRepAsDeclContext(const CXXScopeSpec &SS) { - if (SS.isInvalid() || !SS.getScopeRep()) - return 0; - uintptr_t Rep = reinterpret_cast<uintptr_t>(SS.getScopeRep()); - if ((Rep & 0x01) == 0) - return reinterpret_cast<DeclContext *>(Rep); - - // Retrieve the DeclContext associated with this type. - QualType T = QualType(reinterpret_cast<Type *>(Rep & ~0x01), 0); - const TagType *TagT = T->getAsTagType(); - assert(TagT && "No DeclContext from a non-tag type"); - return TagT->getDecl(); -} - -/// \brief Retrieve the scope represented by this scope specifier as a -/// type. -QualType Sema::getScopeRepAsType(const CXXScopeSpec &SS) { - if (SS.isInvalid() || !SS.getScopeRep()) - return QualType(); - - uintptr_t Rep = reinterpret_cast<uintptr_t>(SS.getScopeRep()); - if ((Rep & 0x01) == 0) - return QualType(); - return QualType(reinterpret_cast<Type *>(Rep & ~0x01), 0); -} - -Action::CXXScopeTy *Sema::createScopeRep(QualType T) { - assert(((reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()) & 0x01) == 0) && - "Scope type with cv-qualifiers"); - if (T.isNull()) +/// \brief Compute the DeclContext that is associated with the given +/// scope specifier. +DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) { + if (!SS.isSet() || SS.isInvalid()) return 0; - - return reinterpret_cast<CXXScopeTy *>( - reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()) | 0x01); -} -bool Sema::isScopeRepType(const CXXScopeSpec &SS) { - uintptr_t Rep = reinterpret_cast<uintptr_t>(SS.getScopeRep()); - return Rep & 0x01; + NestedNameSpecifier NNS + = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep()); + return NNS.computeDeclContext(Context); } /// \brief Require that the context specified by SS be complete. @@ -73,7 +42,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { if (!SS.isSet() || SS.isInvalid()) return false; - DeclContext *DC = getScopeRepAsDeclContext(SS); + DeclContext *DC = computeDeclContext(SS); if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { // If we're currently defining this type, then lookup into the // type is okay: don't complain that it isn't complete yet. @@ -95,7 +64,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { /// global scope ('::'). Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc) { - return createScopeRep(Context.getTranslationUnitDecl()); + return NestedNameSpecifier(Context.getTranslationUnitDecl()).getAsOpaquePtr(); } /// ActOnCXXNestedNameSpecifier - Called during parsing of a @@ -114,9 +83,10 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, if (SD) { if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { if (TD->getUnderlyingType()->isRecordType()) - return createScopeRep(Context.getTypeDeclType(TD)); + return NestedNameSpecifier(Context.getTypeDeclType(TD).getTypePtr()) + .getAsOpaquePtr(); } else if (isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) { - return createScopeRep(cast<DeclContext>(SD)); + return NestedNameSpecifier(cast<DeclContext>(SD)).getAsOpaquePtr(); } // FIXME: Template parameters and dependent types. @@ -152,7 +122,8 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, TypeTy *Ty, SourceRange TypeRange, SourceLocation CCLoc) { - return createScopeRep(QualType::getFromOpaquePtr(Ty)); + return NestedNameSpecifier(QualType::getFromOpaquePtr(Ty).getTypePtr()) + .getAsOpaquePtr(); } /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global @@ -165,7 +136,7 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?"); PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity()); - CurContext = getScopeRepAsDeclContext(SS); + CurContext = computeDeclContext(SS); S->setEntity(CurContext); } @@ -176,8 +147,7 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { /// defining scope. void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); - assert(S->getEntity() == getScopeRepAsDeclContext(SS) && - "Context imbalance!"); + assert(S->getEntity() == computeDeclContext(SS) && "Context imbalance!"); S->setEntity(PreDeclaratorDC); PreDeclaratorDC = 0; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c3dfd19be4..63d446f70c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -72,22 +72,32 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, } if (IIDecl) { + QualType T; + if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { // Check whether we can use this type (void)DiagnoseUseOfDecl(IIDecl, NameLoc); - return Context.getTypeDeclType(TD).getAsOpaquePtr(); - } - - if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { + T = Context.getTypeDeclType(TD); + } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { // Check whether we can use this interface. (void)DiagnoseUseOfDecl(IIDecl, NameLoc); - return Context.getObjCInterfaceType(IDecl).getAsOpaquePtr(); + T = Context.getObjCInterfaceType(IDecl); + } else + return 0; + + if (SS && SS->isNotEmpty() && SS->isSet()) { + llvm::SmallVector<NestedNameSpecifier, 4> TNNs; + for (CXXScopeSpec::iterator TNN = SS->begin(), TNNEnd = SS->end(); + TNN != TNNEnd; ++TNN) + TNNs.push_back(NestedNameSpecifier::getFromOpaquePtr(*TNN)); + T = Context.getQualifiedNameType(&TNNs[0], TNNs.size(), T); } - // Otherwise, could be a variable, function etc. + return T.getAsOpaquePtr(); } + return 0; } @@ -1257,7 +1267,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl, DeclSpec::SCS_static, D.getIdentifierLoc()); } else { // Something like "int foo::x;" - DC = getScopeRepAsDeclContext(D.getCXXScopeSpec()); + DC = computeDeclContext(D.getCXXScopeSpec()); // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ? PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true); @@ -3020,7 +3030,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, } // FIXME: RequireCompleteDeclContext(SS)? - DC = getScopeRepAsDeclContext(SS); + DC = computeDeclContext(SS); SearchDC = DC; // Look-up name inside 'foo::'. PrevDecl = dyn_cast_or_null<TagDecl>( diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 3307dd0cc4..10e7bd4c97 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -299,8 +299,8 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, const CXXScopeSpec *SS) { CXXRecordDecl *CurDecl; - if (SS) { - DeclContext *DC = getScopeRepAsDeclContext(*SS); + if (SS && SS->isSet() && !SS->isInvalid()) { + DeclContext *DC = computeDeclContext(*SS); CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC); } else CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1e184d0349..cec94cfdf0 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -727,7 +727,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // implicit member ref, because we want a pointer to the member in general, // not any specific instance's member. if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) { - DeclContext *DC = getScopeRepAsDeclContext(*SS); + DeclContext *DC = computeDeclContext(*SS); if (D && isa<CXXRecordDecl>(DC)) { QualType DType; if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { @@ -942,7 +942,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // - a nested-name-specifier that contains a class-name that // names a dependent type. else if (SS && !SS->isEmpty()) { - for (DeclContext *DC = getScopeRepAsDeclContext(*SS); + for (DeclContext *DC = computeDeclContext(*SS); DC; DC = DC->getParent()) { // FIXME: could stop early at namespace scope. if (DC->isRecord()) { diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index d6c36d44a9..616ee3dd93 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1038,9 +1038,10 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS, if (SS->isInvalid() || RequireCompleteDeclContext(*SS)) return LookupResult::CreateLookupResult(Context, 0); - if (SS->isSet()) - return LookupQualifiedName(getScopeRepAsDeclContext(*SS), + if (SS->isSet()) { + return LookupQualifiedName(computeDeclContext(*SS), Name, NameKind, RedeclarationOnly); + } } return LookupName(S, Name, NameKind, RedeclarationOnly, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 6277d9e512..f5317787ba 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -399,7 +399,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, DeclContext *SemanticContext = CurContext; if (SS.isNotEmpty() && !SS.isInvalid()) { - SemanticContext = getScopeRepAsDeclContext(SS); + SemanticContext = computeDeclContext(SS); // FIXME: need to match up several levels of template parameter // lists here. diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 4341fc94f9..7df9941aa5 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -492,6 +492,14 @@ InstantiateClassTemplateSpecializationType( QualType TemplateTypeInstantiator:: +InstantiateQualifiedNameType(const QualifiedNameType *T, + unsigned Quals) const { + assert(false && "Cannot have dependent qualified name types (yet)"); + return QualType(); +} + +QualType +TemplateTypeInstantiator:: InstantiateObjCInterfaceType(const ObjCInterfaceType *T, unsigned Quals) const { assert(false && "Objective-C types cannot be dependent"); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index c52f64055b..a8be924fc8 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -742,7 +742,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { } case DeclaratorChunk::MemberPointer: // The scope spec must refer to a class, or be dependent. - DeclContext *DC = getScopeRepAsDeclContext(DeclType.Mem.Scope()); + DeclContext *DC = computeDeclContext(DeclType.Mem.Scope()); QualType ClsType; // FIXME: Extend for dependent types when it's actually supported. // See ActOnCXXNestedNameSpecifier. @@ -810,8 +810,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && ((D.getContext() != Declarator::MemberContext && (!D.getCXXScopeSpec().isSet() || - !static_cast<DeclContext*>(D.getCXXScopeSpec().getScopeRep()) - ->isRecord())) || + !computeDeclContext(D.getCXXScopeSpec())->isRecord())) || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) { if (D.isFunctionDeclarator()) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); diff --git a/test/SemaCXX/qualified-names-diag.cpp b/test/SemaCXX/qualified-names-diag.cpp new file mode 100644 index 0000000000..151b924a3a --- /dev/null +++ b/test/SemaCXX/qualified-names-diag.cpp @@ -0,0 +1,28 @@ +// RUN: clang -fsyntax-only -verify %s +namespace foo { + namespace wibble { + struct x { int y; }; + + namespace bar { + namespace wonka { + struct x { + struct y { }; + }; + } + } + } +} + +namespace bar { + typedef int y; +} +void test() { + foo::wibble::x a; + ::bar::y b; + a + b; // expected-error{{invalid operands to binary expression ('foo::wibble::x' (aka 'struct x') and '::bar::y' (aka 'int'))}} + + ::foo::wibble::bar::wonka::x::y c; + c + b; // expected-error{{invalid operands to binary expression ('::foo::wibble::bar::wonka::x::y' (aka 'struct y') and '::bar::y' (aka 'int'))}} +} + +int ::foo::wibble::bar::wonka::x::y::* ptrmem; diff --git a/test/SemaTemplate/instantiate-typedef.cpp b/test/SemaTemplate/instantiate-typedef.cpp index 8ecee50502..3e7c464d2c 100644 --- a/test/SemaTemplate/instantiate-typedef.cpp +++ b/test/SemaTemplate/instantiate-typedef.cpp @@ -8,7 +8,7 @@ struct add_pointer { add_pointer<int>::type test1(int * ptr) { return ptr; } add_pointer<float>::type test2(int * ptr) { - return ptr; // expected-error{{incompatible type returning 'int *', expected 'type' (aka 'float *')}} + return ptr; // expected-error{{incompatible type returning 'int *', expected 'add_pointer<float>::type' (aka 'float *')}} } add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}} |