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.
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.
--- /dev/null
+//===--- 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
#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"
class SourceLocation;
class StmtIteratorBase;
class TemplateArgument;
+ class QualifiedNameType;
// Provide forward declarations for all of the *Type classes
#define TYPE(Class, Base) class Class##Type;
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;
}
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
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)
/// 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; }
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;
}
};
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,
Expr.cpp
ExprCXX.cpp
InheritViz.cpp
+ NestedNameSpecifier.cpp
ParentMap.cpp
Stmt.cpp
StmtDumper.cpp
--- /dev/null
+//===--- 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();
+}
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);
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
//===----------------------------------------------------------------------===//
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;
}
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();
return 0;
}
+//===----------------------------------------------------------------------===//
+// 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
//===----------------------------------------------------------------------===//
case Type::BlockPointer:
case Type::MemberPointer:
case Type::ClassTemplateSpecialization:
+ case Type::QualifiedName:
case Type::ObjCQualifiedClass:
// Unsupported types
return llvm::DIType();
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/STLExtras.h"
+#include <cstring>
using namespace clang;
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.
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
if (TypeRep == 0)
goto DoneWithDeclSpec;
-
+
+ CXXScopeSpec::freeAnnotationData(Tok.getAnnotationValue());
ConsumeToken(); // The C++ scope.
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
"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;
// '::' - 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;
}
if (SS.isInvalid())
continue;
- SS.setScopeRep(
+ SS.addScopeRep(
Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
SS.setEndLoc(CCLoc);
continue;
if (TemplateId->Kind == TNK_Class_template) {
if (AnnotateTemplateIdTokenAsType(&SS))
- SS.setScopeRep(0);
+ SS.clear();
assert(Tok.is(tok::annot_typename) &&
"AnnotateTemplateIdTokenAsType isn't working");
HasScopeSpecifier = true;
}
- SS.setScopeRep(
+ SS.addScopeRep(
Actions.ActOnCXXNestedNameSpecifier(CurScope, SS,
TypeToken.getAnnotationValue(),
TypeToken.getAnnotationRange(),
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
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
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 ('::').
#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.
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.
/// 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
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.
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
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);
}
/// 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;
}
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;
}
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);
}
// FIXME: RequireCompleteDeclContext(SS)?
- DC = getScopeRepAsDeclContext(SS);
+ DC = computeDeclContext(SS);
SearchDC = DC;
// Look-up name inside 'foo::'.
PrevDecl = dyn_cast_or_null<TagDecl>(
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);
// 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)) {
// - 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()) {
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,
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.
SourceLocation());
}
+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,
}
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.
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);
--- /dev/null
+// 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;
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}}