aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-03-19 00:18:19 +0000
committerDouglas Gregor <dgregor@apple.com>2009-03-19 00:18:19 +0000
commite4e5b054b4917f0ee493bb2fda5b1ec749bfb9a1 (patch)
treede98baadcf679cb6d084a3efd3ffd6b8e30f2009
parent72374594c5d9ade02451bc85cf9dfa5b0ea106e7 (diff)
Introduce a representation for types that we referred to via a
qualified name, e.g., foo::x so that we retain the nested-name-specifier as written in the source code and can reproduce that qualified name when printing the types back (e.g., in diagnostics). This is PR3493, which won't be complete until finished the other tasks mentioned near the end of this commit. The parser's representation of nested-name-specifiers, CXXScopeSpec, is now a bit fatter, because it needs to contain the scopes that precede each '::' and keep track of whether the global scoping operator '::' was at the beginning. For example, we need to keep track of the leading '::', 'foo', and 'bar' in ::foo::bar::x The Action's CXXScopeTy * is no longer a DeclContext *. It's now the opaque version of the new NestedNameSpecifier, which contains a single component of a nested-name-specifier (either a DeclContext * or a Type *, bitmangled). The new sugar type QualifiedNameType composes a sequence of NestedNameSpecifiers with a representation of the type we're actually referring to. At present, we only build QualifiedNameType nodes within Sema::getTypeName. This will be extended to other type-constructing actions (e.g., ActOnClassTemplateId). Also on the way: QualifiedDeclRefExprs will also store a sequence of NestedNameSpecifiers, so that we can print out the property nested-name-specifier. I expect to also use this for handling dependent names like Fibonacci<I - 1>::value. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67265 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h5
-rw-r--r--include/clang/AST/NestedNameSpecifier.h111
-rw-r--r--include/clang/AST/Type.h64
-rw-r--r--include/clang/AST/TypeNodes.def1
-rw-r--r--include/clang/Parse/DeclSpec.h101
-rw-r--r--lib/AST/ASTContext.cpp23
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/NestedNameSpecifier.cpp34
-rw-r--r--lib/AST/Type.cpp63
-rw-r--r--lib/AST/TypeSerialization.cpp15
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp1
-rw-r--r--lib/Parse/DeclSpec.cpp61
-rw-r--r--lib/Parse/ParseDecl.cpp5
-rw-r--r--lib/Parse/ParseExprCXX.cpp11
-rw-r--r--lib/Parse/Parser.cpp4
-rw-r--r--lib/Sema/Sema.h17
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp64
-rw-r--r--lib/Sema/SemaDecl.cpp26
-rw-r--r--lib/Sema/SemaDeclCXX.cpp4
-rw-r--r--lib/Sema/SemaExpr.cpp4
-rw-r--r--lib/Sema/SemaLookup.cpp5
-rw-r--r--lib/Sema/SemaTemplate.cpp2
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp8
-rw-r--r--lib/Sema/SemaType.cpp5
-rw-r--r--test/SemaCXX/qualified-names-diag.cpp28
-rw-r--r--test/SemaTemplate/instantiate-typedef.cpp2
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.