aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTContext.h53
-rw-r--r--include/clang/AST/CanonicalType.h42
-rw-r--r--include/clang/AST/Type.h731
-rw-r--r--include/clang/AST/TypeNodes.def1
-rw-r--r--include/clang/Frontend/DocumentXML.h1
-rw-r--r--include/clang/Frontend/PCHReader.h2
-rw-r--r--include/clang/Frontend/PCHWriter.h30
-rw-r--r--include/clang/Frontend/TypeXML.def15
-rw-r--r--include/clang/Parse/DeclSpec.h2
-rw-r--r--lib/AST/ASTContext.cpp404
-rw-r--r--lib/AST/DeclCXX.cpp11
-rw-r--r--lib/AST/DeclarationName.cpp4
-rw-r--r--lib/AST/Expr.cpp8
-rw-r--r--lib/AST/ExprConstant.cpp2
-rw-r--r--lib/AST/StmtDumper.cpp9
-rw-r--r--lib/AST/Type.cpp229
-rw-r--r--lib/CodeGen/CGCXX.cpp4
-rw-r--r--lib/CodeGen/CGCall.cpp2
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp1
-rw-r--r--lib/CodeGen/CGExpr.cpp158
-rw-r--r--lib/CodeGen/CGExprAgg.cpp11
-rw-r--r--lib/CodeGen/CGExprScalar.cpp3
-rw-r--r--lib/CodeGen/CGObjCMac.cpp30
-rw-r--r--lib/CodeGen/CGValue.h77
-rw-r--r--lib/CodeGen/CodeGenFunction.h6
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp8
-rw-r--r--lib/CodeGen/Mangle.cpp31
-rw-r--r--lib/Frontend/DocumentXML.cpp4
-rw-r--r--lib/Frontend/PCHReader.cpp27
-rw-r--r--lib/Frontend/PCHWriter.cpp68
-rw-r--r--lib/Frontend/RewriteObjC.cpp9
-rw-r--r--lib/Sema/Sema.cpp4
-rw-r--r--lib/Sema/SemaCXXCast.cpp19
-rw-r--r--lib/Sema/SemaDecl.cpp10
-rw-r--r--lib/Sema/SemaDeclCXX.cpp20
-rw-r--r--lib/Sema/SemaExpr.cpp83
-rw-r--r--lib/Sema/SemaExprCXX.cpp59
-rw-r--r--lib/Sema/SemaInherit.cpp2
-rw-r--r--lib/Sema/SemaOverload.cpp95
-rw-r--r--lib/Sema/SemaStmt.cpp13
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp43
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp2
-rw-r--r--lib/Sema/SemaType.cpp132
-rw-r--r--lib/Sema/TreeTransform.h47
-rw-r--r--test/Sema/address_spaces.c2
45 files changed, 1359 insertions, 1155 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 9c5e31cd74..d9b0e79dbc 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -63,7 +63,7 @@ namespace clang {
/// decls) that can be referred to throughout the semantic analysis of a file.
class ASTContext {
std::vector<Type*> Types;
- llvm::FoldingSet<ExtQualType> ExtQualTypes;
+ llvm::FoldingSet<ExtQuals> ExtQualNodes;
llvm::FoldingSet<ComplexType> ComplexTypes;
llvm::FoldingSet<PointerType> PointerTypes;
llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
@@ -332,6 +332,11 @@ public:
// Type Constructors
//===--------------------------------------------------------------------===//
+private:
+ /// getExtQualType - Return a type with extended qualifiers.
+ QualType getExtQualType(const Type *Base, Qualifiers Quals);
+
+public:
/// getAddSpaceQualType - Return the uniqued reference to the type for an
/// address space qualified type with the specified type and address space.
/// The resulting type has a union of the qualifiers from T and the address
@@ -342,7 +347,27 @@ public:
/// getObjCGCQualType - Returns the uniqued reference to the type for an
/// objc gc qualified type. The retulting type has a union of the qualifiers
/// from T and the gc attribute.
- QualType getObjCGCQualType(QualType T, QualType::GCAttrTypes gcAttr);
+ QualType getObjCGCQualType(QualType T, Qualifiers::GC gcAttr);
+
+ /// getRestrictType - Returns the uniqued reference to the type for a
+ /// 'restrict' qualified type. The resulting type has a union of the
+ /// qualifiers from T and 'restrict'.
+ QualType getRestrictType(QualType T) {
+ return T.withFastQualifiers(Qualifiers::Restrict);
+ }
+
+ /// getVolatileType - Returns the uniqued reference to the type for a
+ /// 'volatile' qualified type. The resulting type has a union of the
+ /// qualifiers from T and 'volatile'.
+ QualType getVolatileType(QualType T);
+
+ /// getConstType - Returns the uniqued reference to the type for a
+ /// 'const' qualified type. The resulting type has a union of the
+ /// qualifiers from T and 'const'.
+ ///
+ /// It can be reasonably expected that this will always be
+ /// equivalent to calling T.withConst().
+ QualType getConstType(QualType T) { return T.withConst(); }
/// getNoReturnType - Add the noreturn attribute to the given type which must
/// be a FunctionType or a pointer to an allowable type or a BlockPointer.
@@ -636,6 +661,28 @@ public:
QualType getFixedWidthIntType(unsigned Width, bool Signed);
+ /// getCVRQualifiedType - Returns a type with additional const,
+ /// volatile, or restrict qualifiers.
+ QualType getCVRQualifiedType(QualType T, unsigned CVR) {
+ return getQualifiedType(T, Qualifiers::fromCVRMask(CVR));
+ }
+
+ /// getQualifiedType - Returns a type with additional qualifiers.
+ QualType getQualifiedType(QualType T, Qualifiers Qs) {
+ if (!Qs.hasNonFastQualifiers())
+ return T.withFastQualifiers(Qs.getFastQualifiers());
+ QualifierCollector Qc(Qs);
+ const Type *Ptr = Qc.strip(T);
+ return getExtQualType(Ptr, Qc);
+ }
+
+ /// getQualifiedType - Returns a type with additional qualifiers.
+ QualType getQualifiedType(const Type *T, Qualifiers Qs) {
+ if (!Qs.hasNonFastQualifiers())
+ return QualType(T, Qs.getFastQualifiers());
+ return getExtQualType(T, Qs);
+ }
+
TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,
bool TemplateKeyword,
TemplateDecl *Template);
@@ -666,7 +713,7 @@ public:
/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
/// garbage collection attribute.
///
- QualType::GCAttrTypes getObjCGCAttrKind(const QualType &Ty) const;
+ Qualifiers::GC getObjCGCAttrKind(const QualType &Ty) const;
/// isObjCNSObjectType - Return true if this is an NSObject object with
/// its NSObject attribute set.
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index be163eb5a8..d7ac76dd32 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -103,20 +103,23 @@ public:
/// proxy.
CanProxy<T> operator->() const;
+ /// \brief Retrieve all qualifiers.
+ Qualifiers getQualifiers() const { return Stored.getQualifiers(); }
+
/// \brief Retrieve the const/volatile/restrict qualifiers.
unsigned getCVRQualifiers() const { return Stored.getCVRQualifiers(); }
- /// \brief Set the const/volatile/restrict qualifiers
- void setCVRQualifiers(unsigned Quals) { Stored.setCVRQualifiers(Quals); }
+ /// \brief Determines whether this type has any qualifiers
+ bool hasQualifiers() const { return Stored.hasQualifiers(); }
bool isConstQualified() const {
- return (getCVRQualifiers() & QualType::Const) ? true : false;
+ return Stored.isConstQualified();
}
bool isVolatileQualified() const {
- return (getCVRQualifiers() & QualType::Volatile) ? true : false;
+ return Stored.isVolatileQualified();
}
bool isRestrictQualified() const {
- return (getCVRQualifiers() & QualType::Restrict) ? true : false;
+ return Stored.isRestrictQualified();
}
/// \brief Retrieve the unqualified form of this type.
@@ -322,7 +325,7 @@ public:
static inline clang::CanQual<T> getFromVoidPointer(void *P) {
return clang::CanQual<T>::getFromOpaquePtr(P);
}
- // CVR qualifiers go in low bits.
+ // qualifier information is encoded in the low bits.
enum { NumLowBitsAvailable = 0 };
};
@@ -426,13 +429,6 @@ public:
};
template<>
-struct CanProxyAdaptor<ExtQualType> : public CanProxyBase<ExtQualType> {
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type*, getBaseType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(QualType::GCAttrTypes, getObjCGCAttr)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getAddressSpace)
-};
-
-template<>
struct CanProxyAdaptor<ComplexType> : public CanProxyBase<ComplexType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
};
@@ -477,7 +473,7 @@ struct CanProxyAdaptor<ArrayType> : public CanProxyBase<ArrayType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
getSizeModifier)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndexTypeQualifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
};
template<>
@@ -486,7 +482,7 @@ struct CanProxyAdaptor<ConstantArrayType>
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
getSizeModifier)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndexTypeQualifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize)
};
@@ -496,7 +492,7 @@ struct CanProxyAdaptor<ConstantArrayWithExprType>
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
getSizeModifier)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndexTypeQualifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
@@ -510,7 +506,7 @@ struct CanProxyAdaptor<ConstantArrayWithoutExprType>
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
getSizeModifier)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndexTypeQualifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize)
};
@@ -520,7 +516,7 @@ struct CanProxyAdaptor<IncompleteArrayType>
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
getSizeModifier)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndexTypeQualifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
};
template<>
@@ -529,7 +525,7 @@ struct CanProxyAdaptor<VariableArrayType>
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
getSizeModifier)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndexTypeQualifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
@@ -666,9 +662,7 @@ struct CanProxyAdaptor<ObjCObjectPointerType>
//----------------------------------------------------------------------------//
template<typename T>
inline CanQual<T> CanQual<T>::getUnqualifiedType() const {
- if (CanQual<ExtQualType> EQ = getAs<ExtQualType>())
- return CanQual<T>::CreateUnsafe(QualType(EQ->getBaseType(), 0));
- return CanQual<T>::CreateUnsafe(QualType(Stored.getTypePtr(), 0));
+ return CanQual<T>::CreateUnsafe(Stored.getUnqualifiedType());
}
template<typename T>
@@ -707,10 +701,6 @@ CanProxy<U> CanQual<T>::getAs() const {
if (isa<U>(Stored.getTypePtr()))
return CanQual<U>::CreateUnsafe(Stored);
- if (const ExtQualType *EQ = Stored->getAs<ExtQualType>())
- return CanQual<T>::CreateUnsafe(QualType(EQ->getBaseType(), 0))
- .template getAs<U>();
-
return CanProxy<U>();
}
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 7871830314..345e51c740 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -30,7 +30,7 @@ using llvm::cast;
using llvm::cast_or_null;
using llvm::dyn_cast;
using llvm::dyn_cast_or_null;
-namespace clang { class Type; }
+namespace clang { class Type; class ExtQuals; }
namespace llvm {
template <typename T>
@@ -44,6 +44,15 @@ namespace llvm {
}
enum { NumLowBitsAvailable = 3 };
};
+ template<>
+ class PointerLikeTypeTraits< ::clang::ExtQuals*> {
+ public:
+ static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; }
+ static inline ::clang::ExtQuals *getFromVoidPointer(void *P) {
+ return static_cast< ::clang::ExtQuals*>(P);
+ }
+ enum { NumLowBitsAvailable = 3 };
+ };
}
namespace clang {
@@ -73,43 +82,345 @@ namespace clang {
#define TYPE(Class, Base) class Class##Type;
#include "clang/AST/TypeNodes.def"
-/// QualType - For efficiency, we don't store CVR-qualified types as nodes on
-/// their own: instead each reference to a type stores the qualifiers. This
-/// greatly reduces the number of nodes we need to allocate for types (for
-/// example we only need one for 'int', 'const int', 'volatile int',
-/// 'const volatile int', etc).
-///
-/// As an added efficiency bonus, instead of making this a pair, we just store
-/// the three bits we care about in the low bits of the pointer. To handle the
-/// packing/unpacking, we make QualType be a simple wrapper class that acts like
-/// a smart pointer.
-class QualType {
- llvm::PointerIntPair<Type*, 3> Value;
+/// Qualifiers - The collection of all-type qualifiers we support.
+/// Clang supports five independent qualifiers:
+/// * C99: const, volatile, and restrict
+/// * Embedded C (TR18037): address spaces
+/// * Objective C: the GC attributes (none, weak, or strong)
+class Qualifiers {
public:
- enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ.
+ enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ.
Const = 0x1,
Restrict = 0x2,
Volatile = 0x4,
- CVRFlags = Const|Restrict|Volatile
+ CVRMask = Const | Volatile | Restrict
};
- enum GCAttrTypes {
+ enum GC {
GCNone = 0,
Weak,
Strong
};
- // 24 bits should be enough for anyone.
- static const unsigned MaxAddressSpace = 0xffffffu;
+ enum {
+ /// The maximum supported address space number.
+ /// 24 bits should be enough for anyone.
+ MaxAddressSpace = 0xffffffu,
+
+ /// The width of the "fast" qualifier mask.
+ FastWidth = 2,
+
+ /// The fast qualifier mask.
+ FastMask = (1 << FastWidth) - 1
+ };
+
+ Qualifiers() : Mask(0) {}
+
+ static Qualifiers fromFastMask(unsigned Mask) {
+ Qualifiers Qs;
+ Qs.addFastQualifiers(Mask);
+ return Qs;
+ }
+
+ static Qualifiers fromCVRMask(unsigned CVR) {
+ Qualifiers Qs;
+ Qs.addCVRQualifiers(CVR);
+ return Qs;
+ }
+
+ // Deserialize qualifiers from an opaque representation.
+ static Qualifiers fromOpaqueValue(unsigned opaque) {
+ Qualifiers Qs;
+ Qs.Mask = opaque;
+ return Qs;
+ }
+
+ // Serialize these qualifiers into an opaque representation.
+ unsigned getAsOpaqueValue() const {
+ return Mask;
+ }
+
+ bool hasConst() const { return Mask & Const; }
+ void setConst(bool flag) {
+ Mask = (Mask & ~Const) | (flag ? Const : 0);
+ }
+ void removeConst() { Mask &= ~Const; }
+ void addConst() { Mask |= Const; }
+
+ bool hasVolatile() const { return Mask & Volatile; }
+ void setVolatile(bool flag) {
+ Mask = (Mask & ~Volatile) | (flag ? Volatile : 0);
+ }
+ void removeVolatile() { Mask &= ~Volatile; }
+ void addVolatile() { Mask |= Volatile; }
+
+ bool hasRestrict() const { return Mask & Restrict; }
+ void setRestrict(bool flag) {
+ Mask = (Mask & ~Restrict) | (flag ? Restrict : 0);
+ }
+ void removeRestrict() { Mask &= ~Restrict; }
+ void addRestrict() { Mask |= Restrict; }
+
+ bool hasCVRQualifiers() const { return getCVRQualifiers(); }
+ unsigned getCVRQualifiers() const { return Mask & CVRMask; }
+ void setCVRQualifiers(unsigned mask) {
+ assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
+ Mask = (Mask & ~CVRMask) | mask;
+ }
+ void removeCVRQualifiers(unsigned mask) {
+ assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
+ Mask &= ~mask;
+ }
+ void removeCVRQualifiers() {
+ removeCVRQualifiers(CVRMask);
+ }
+ void addCVRQualifiers(unsigned mask) {
+ assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
+ Mask |= mask;
+ }
+
+ bool hasObjCGCAttr() const { return Mask & GCAttrMask; }
+ GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); }
+ void setObjCGCAttr(GC type) {
+ Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift);
+ }
+ void removeObjCGCAttr() { setObjCGCAttr(GCNone); }
+ void addObjCGCAttr(GC type) {
+ assert(type);
+ setObjCGCAttr(type);
+ }
+
+ bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
+ unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
+ void setAddressSpace(unsigned space) {
+ assert(space <= MaxAddressSpace);
+ Mask = (Mask & ~AddressSpaceMask)
+ | (((uint32_t) space) << AddressSpaceShift);
+ }
+ void removeAddressSpace() { setAddressSpace(0); }
+ void addAddressSpace(unsigned space) {
+ assert(space);
+ setAddressSpace(space);
+ }
+
+ // Fast qualifiers are those that can be allocated directly
+ // on a QualType object.
+ bool hasFastQualifiers() const { return getFastQualifiers(); }
+ unsigned getFastQualifiers() const { return Mask & FastMask; }
+ void setFastQualifiers(unsigned mask) {
+ assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
+ Mask = (Mask & ~FastMask) | mask;
+ }
+ void removeFastQualifiers(unsigned mask) {
+ assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
+ Mask &= ~mask;
+ }
+ void removeFastQualifiers() {
+ removeFastQualifiers(FastMask);
+ }
+ void addFastQualifiers(unsigned mask) {
+ assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
+ Mask |= mask;
+ }
+
+ /// hasNonFastQualifiers - Return true if the set contains any
+ /// qualifiers which require an ExtQuals node to be allocated.
+ bool hasNonFastQualifiers() const { return Mask & ~FastMask; }
+ Qualifiers getNonFastQualifiers() const {
+ Qualifiers Quals = *this;
+ Quals.setFastQualifiers(0);
+ return Quals;
+ }
+
+ /// hasQualifiers - Return true if the set contains any qualifiers.
+ bool hasQualifiers() const { return Mask; }
+ bool empty() const { return !Mask; }
+
+ /// \brief Add the qualifiers from the given set to this set.
+ void addQualifiers(Qualifiers Q) {
+ // If the other set doesn't have any non-boolean qualifiers, just
+ // bit-or it in.
+ if (!(Q.Mask & ~CVRMask))
+ Mask |= Q.Mask;
+ else {
+ Mask |= (Q.Mask & CVRMask);
+ if (Q.hasAddressSpace())
+ addAddressSpace(Q.getAddressSpace());
+ if (Q.hasObjCGCAttr())
+ addObjCGCAttr(Q.getObjCGCAttr());
+ }
+ }
+
+ bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
+ bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
+
+ operator bool() const { return hasQualifiers(); }
+
+ Qualifiers &operator+=(Qualifiers R) {
+ addQualifiers(R);
+ return *this;
+ }
+
+ // Union two qualifier sets. If an enumerated qualifier appears
+ // in both sets, use the one from the right.
+ friend Qualifiers operator+(Qualifiers L, Qualifiers R) {
+ L += R;
+ return L;
+ }
+
+ std::string getAsString() const;
+ std::string getAsString(const PrintingPolicy &Policy) const {
+ std::string Buffer;
+ getAsStringInternal(Buffer, Policy);
+ return Buffer;
+ }
+ void getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(Mask);
+ }
+
+private:
+
+ // bits: |0 1 2|3 .. 4|5 .. 31|
+ // |C R V|GCAttr|AddrSpace|
+ uint32_t Mask;
+
+ static const uint32_t GCAttrMask = 0x18;
+ static const uint32_t GCAttrShift = 3;
+ static const uint32_t AddressSpaceMask = ~(CVRMask | GCAttrMask);
+ static const uint32_t AddressSpaceShift = 5;
+};
+
+
+/// ExtQuals - We can encode up to three bits in the low bits of a
+/// type pointer, but there are many more type qualifiers that we want
+/// to be able to apply to an arbitrary type. Therefore we have this
+/// struct, intended to be heap-allocated and used by QualType to
+/// store qualifiers.
+///
+/// The current design tags the 'const' and 'restrict' qualifiers in
+/// two low bits on the QualType pointer; a third bit records whether
+/// the pointer is an ExtQuals node. 'const' was chosen because it is
+/// orders of magnitude more common than the other two qualifiers, in
+/// both library and user code. It's relatively rare to see
+/// 'restrict' in user code, but many standard C headers are saturated
+/// with 'restrict' declarations, so that representing them efficiently
+/// is a critical goal of this representation.
+class ExtQuals : public llvm::FoldingSetNode {
+ // NOTE: changing the fast qualifiers should be straightforward as
+ // long as you don't make 'const' non-fast.
+ // 1. Qualifiers:
+ // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ).
+ // Fast qualifiers must occupy the low-order bits.
+ // b) Update Qualifiers::FastWidth and FastMask.
+ // 2. QualType:
+ // a) Update is{Volatile,Restrict}Qualified(), defined inline.
+ // b) Update remove{Volatile,Restrict}, defined near the end of
+ // this header.
+ // 3. ASTContext:
+ // a) Update get{Volatile,Restrict}Type.
+
+ /// Context - the context to which this set belongs. We save this
+ /// here so that QualifierCollector can use it to reapply extended
+ /// qualifiers to an arbitrary type without requiring a context to
+ /// be pushed through every single API dealing with qualifiers.
+ ASTContext& Context;
+
+ /// BaseType - the underlying type that this qualifies
+ const Type *BaseType;
+
+ /// Quals - the immutable set of qualifiers applied by this
+ /// node; always contains extended qualifiers.
+ Qualifiers Quals;
+
+public:
+ ExtQuals(ASTContext& Context, const Type *Base, Qualifiers Quals)
+ : Context(Context), BaseType(Base), Quals(Quals)
+ {
+ assert(Quals.hasNonFastQualifiers()
+ && "ExtQuals created with no fast qualifiers");
+ assert(!Quals.hasFastQualifiers()
+ && "ExtQuals created with fast qualifiers");
+ }
+
+ Qualifiers getQualifiers() const { return Quals; }
+
+ bool hasVolatile() const { return Quals.hasVolatile(); }
+
+ bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); }
+ Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); }
+
+ bool hasAddressSpace() const { return Quals.hasAddressSpace(); }
+ unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
+
+ const Type *getBaseType() const { return BaseType; }
+ ASTContext &getContext() const { return Context; }
+
+public:
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, getBaseType(), Quals);
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const Type *BaseType,
+ Qualifiers Quals) {
+ assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!");
+ ID.AddPointer(BaseType);
+ Quals.Profile(ID);
+ }
+};
+
+
+/// QualType - For efficiency, we don't store CV-qualified types as nodes on
+/// their own: instead each reference to a type stores the qualifiers. This
+/// greatly reduces the number of nodes we need to allocate for types (for
+/// example we only need one for 'int', 'const int', 'volatile int',
+/// 'const volatile int', etc).
+///
+/// As an added efficiency bonus, instead of making this a pair, we
+/// just store the two bits we care about in the low bits of the
+/// pointer. To handle the packing/unpacking, we make QualType be a
+/// simple wrapper class that acts like a smart pointer. A third bit
+/// indicates whether there are extended qualifiers present, in which
+/// case the pointer points to a special structure.
+class QualType {
+ // Thankfully, these are efficiently composable.
+ llvm::PointerIntPair<llvm::PointerUnion<const Type*,const ExtQuals*>,
+ Qualifiers::FastWidth> Value;
+
+ bool hasExtQuals() const {
+ return Value.getPointer().is<const ExtQuals*>();
+ }
+
+ const ExtQuals *getExtQualsUnsafe() const {
+ return Value.getPointer().get<const ExtQuals*>();
+ }
+
+ const Type *getTypePtrUnsafe() const {
+ return Value.getPointer().get<const Type*>();
+ }
+
+ friend class QualifierCollector;
+public:
QualType() {}
QualType(const Type *Ptr, unsigned Quals)
- : Value(const_cast<Type*>(Ptr), Quals) {}
+ : Value(Ptr, Quals) {}
+ QualType(const ExtQuals *Ptr, unsigned Quals)
+ : Value(Ptr, Quals) {}
+
+ unsigned getFastQualifiers() const { return Value.getInt(); }
+ void setFastQualifiers(unsigned Quals) { Value.setInt(Quals); }
- unsigned getCVRQualifiers() const { return Value.getInt(); }
- void setCVRQualifiers(unsigned Quals) { Value.setInt(Quals); }
- Type *getTypePtr() const { return Value.getPointer(); }
+ /// Retrieves a pointer to the underlying (unqualified) type.
+ /// This should really return a const Type, but it's not worth
+ /// changing all the users right now.
+ Type *getTypePtr() const {
+ if (hasNonFastQualifiers())
+ return const_cast<Type*>(getExtQualsUnsafe()->getBaseType());
+ return const_cast<Type*>(getTypePtrUnsafe());
+ }
void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
static QualType getFromOpaquePtr(void *Ptr) {
@@ -128,43 +439,97 @@ public:
/// isNull - Return true if this QualType doesn't point to a type yet.
bool isNull() const {
- return getTypePtr() == 0;
+ return Value.getPointer().isNull();
}
bool isConstQualified() const {
- return (getCVRQualifiers() & Const) ? true : false;
+ return (getFastQualifiers() & Qualifiers::Const);
+ }
+ bool isRestrictQualified() const {
+ return (getFastQualifiers() & Qualifiers::Restrict);
}
bool isVolatileQualified() const {
- return (getCVRQualifiers() & Volatile) ? true : false;
+ return (hasNonFastQualifiers() && getExtQualsUnsafe()->hasVolatile());
}
- bool isRestrictQualified() const {
- return (getCVRQualifiers() & Restrict) ? true : false;
+
+ // Determines whether this type has any direct qualifiers.
+ bool hasQualifiers() const {
+ return getFastQualifiers() || hasNonFastQualifiers();
+ }
+
+ bool hasNonFastQualifiers() const {
+ return hasExtQuals();
+ }
+
+ // Retrieves the set of qualifiers belonging to this type.
+ Qualifiers getQualifiers() const {
+ Qualifiers Quals;
+ if (hasNonFastQualifiers())
+ Quals = getExtQualsUnsafe()->getQualifiers();
+ Quals.addFastQualifiers(getFastQualifiers());
+ return Quals;
+ }
+
+ // Retrieves the CVR qualifiers of this type.
+ unsigned getCVRQualifiers() const {
+ unsigned CVR = getFastQualifiers();
+ if (isVolatileQualified()) CVR |= Qualifiers::Volatile;
+ return CVR;
}
bool isConstant(ASTContext& Ctx) const;
- /// addConst/addVolatile/addRestrict - add the specified type qual to this
- /// QualType.
- void addConst() { Value.setInt(Value.getInt() | Const); }
- void addVolatile() { Value.setInt(Value.getInt() | Volatile); }
- void addRestrict() { Value.setInt(Value.getInt() | Restrict); }
+ // Don't promise in the API that anything besides 'const' can be
+ // easily added.
+
+ /// addConst - add the specified type qualifier to this QualType.
+ void addConst() {
+ addFastQu