Introduce the canonical type smart pointers, and use them in a few places to

tighten up the static type system.

llvm-svn: 78164
This commit is contained in:
Douglas Gregor
2009-08-05 05:36:45 +00:00
parent 8c79569853
commit 2211d345d2
12 changed files with 801 additions and 47 deletions

View File

@@ -22,6 +22,7 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/OwningPtr.h"
@@ -700,7 +701,7 @@ public:
/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
/// to be free of any of these, allowing two canonical types to be compared
/// for exact equality with a simple pointer comparison.
QualType getCanonicalType(QualType T);
CanQualType getCanonicalType(QualType T);
const Type *getCanonicalType(const Type *T) {
return T->getCanonicalTypeInternal().getTypePtr();
}

View File

@@ -0,0 +1,746 @@
//===-- CanonicalType.h - C Language Family Type Representation -*- 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 CanQual class template, which provides access to
// canonical types.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_CANONICAL_TYPE_H
#define LLVM_CLANG_AST_CANONICAL_TYPE_H
#include "clang/AST/Type.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/type_traits.h"
#include <iterator>
namespace clang {
template<typename T> class CanProxy;
template<typename T> struct CanProxyAdaptor;
//----------------------------------------------------------------------------//
// Canonical, qualified type template
//----------------------------------------------------------------------------//
/// \brief Represents a canonical, potentially-qualified type.
///
/// The CanQual template is a lightweight smart pointer that provides access
/// to the canonical representation of a type, where all typedefs and other
/// syntactic sugar has been eliminated. A CanQualType may also have various
/// qualifiers (const, volatile, restrict) attached to it.
///
/// The template type parameter @p T is one of the Type classes (PointerType,
/// BuiltinType, etc.). The type stored within @c CanQual<T> will be of that
/// type (or some subclass of that type). The typedef @c CanQualType is just
/// a shorthand for @c CanQual<Type>.
///
/// An instance of @c CanQual<T> can be implicitly converted to a
/// @c CanQual<U> when T is derived from U, which essentially provides an
/// implicit upcast. For example, @c CanQual<LValueReferenceType> can be
/// converted to @c CanQual<ReferenceType>. Note that any @c CanQual type can
/// be implicitly converted to a QualType, but the reverse operation requires
/// a call to ASTContext::getCanonicalType().
///
///
template<typename T = Type>
class CanQual {
/// \brief The actual, canonical type.
QualType Stored;
public:
/// \brief Constructs a NULL canonical type.
CanQual() : Stored() { }
/// \brief Converting constructor that permits implicit upcasting of
/// canonical type pointers.
template<typename U>
CanQual(const CanQual<U>& Other,
typename llvm::enable_if<llvm::is_base_of<T, U>, int>::type = 0);
/// \brief Implicit conversion to the underlying pointer.
///
/// Also provides the ability to use canonical types in a boolean context,
/// e.g.,
/// @code
/// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... }
/// @endcode
operator const T*() const { return getTypePtr(); }
/// \brief Retrieve the underlying type pointer, which refers to a
/// canonical type.
T *getTypePtr() const { return cast_or_null<T>(Stored.getTypePtr()); }
/// \brief Implicit conversion to a qualified type.
operator QualType() const { return Stored; }
/// \brief Retrieve a canonical type pointer with a different static type,
/// upcasting or downcasting as needed.
///
/// The getAs() function is typically used to try to downcast to a
/// more specific (canonical) type in the type system. For example:
///
/// @code
/// void f(CanQual<Type> T) {
/// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) {
/// // look at Ptr's pointee type
/// }
/// }
/// @endcode
///
/// \returns A proxy pointer to the same type, but with the specified
/// static type (@p U). If the dynamic type is not the specified static type
/// or a derived class thereof, a NULL canonical type.
template<typename U> CanProxy<U> getAs() const;
/// \brief Overloaded arrow operator that produces a canonical type
/// proxy.
CanProxy<T> operator->() const;
/// \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); }
bool isConstQualified() const {
return (getCVRQualifiers() & QualType::Const) ? true : false;
}
bool isVolatileQualified() const {
return (getCVRQualifiers() & QualType::Volatile) ? true : false;
}
bool isRestrictQualified() const {
return (getCVRQualifiers() & QualType::Restrict) ? true : false;
}
/// \brief Retrieve the unqualified form of this type.
CanQual<T> getUnqualifiedType() const;
CanQual<T> getQualifiedType(unsigned TQs) const {
return CanQual<T>::CreateUnsafe(QualType(getTypePtr(), TQs));
}
/// \brief Determines whether this canonical type is more qualified than
/// the @p Other canonical type.
bool isMoreQualifiedThan(CanQual<T> Other) const {
return Stored.isMoreQualifiedThan(Other.Stored);
}
/// \brief Determines whether this canonical type is at least as qualified as
/// the @p Other canonical type.
bool isAtLeastAsQualifiedAs(CanQual<T> Other) const {
return Stored.isAtLeastAsQualifiedAs(Other.Stored);
}
/// \brief If the canonical type is a reference type, returns the type that
/// it refers to; otherwise,
CanQual<Type> getNonReferenceType() const;
/// \brief Retrieve the internal representation of this canonical type.
void *getAsOpaquePtr() const { return Stored.getAsOpaquePtr(); }
/// \brief Construct a canonical type from its internal representation.
static CanQual<T> getFromOpaquePtr(void *Ptr);
/// \brief Builds a canonical type from a QualType.
///
/// This routine is inherently unsafe, because it requires the user to
/// ensure that the given type is a canonical type with the correct
// (dynamic) type.
static CanQual<T> CreateUnsafe(QualType Other);
};
template<typename T, typename U>
inline bool operator==(CanQual<T> x, CanQual<U> y) {
return x.getAsOpaquePtr() == y.getAsOpaquePtr();
}
template<typename T, typename U>
inline bool operator!=(CanQual<T> x, CanQual<U> y) {
return x.getAsOpaquePtr() != y.getAsOpaquePtr();
}
/// \brief Represents a canonical, potentially-qualified type.
typedef CanQual<Type> CanQualType;
//----------------------------------------------------------------------------//
// Internal proxy classes used by canonical types
//----------------------------------------------------------------------------//
#define LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(Accessor) \
CanQualType Accessor() const { \
return CanQualType::CreateUnsafe(this->getTypePtr()->Accessor()); \
}
#define LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type, Accessor) \
Type Accessor() const { return this->getTypePtr()->Accessor(); }
/// \brief Base class of all canonical proxy types, which is responsible for
/// storing the underlying canonical type and providing basic conversions.
template<typename T>
class CanProxyBase {
protected:
CanQual<T> Stored;
public:
/// \brief Retrieve the pointer to the underlying Type
T* getTypePtr() const { return Stored.getTypePtr(); }
/// \brief Implicit conversion to the underlying pointer.
///
/// Also provides the ability to use canonical type proxies in a Boolean
// context,e.g.,
/// @code
/// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... }
/// @endcode
operator const T*() const { return this->Stored.getTypePtr(); }
/// \brief Try to convert the given canonical type to a specific structural
/// type.
template<typename U> CanProxy<U> getAs() const {
return this->Stored.template getAs<U>();
}
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type::TypeClass, getTypeClass)
// Type predicates
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPODType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariablyModifiedType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isEnumeralType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBooleanType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isCharType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isWideCharType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegralType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealFloatingType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyComplexType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFloatingType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArithmeticType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDerivedType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isScalarType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAggregateType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyPointerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidPointerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFunctionPointerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isNullPtrType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDependentType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isOverloadableType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasPointerRepresentation)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasObjCPointerRepresentation)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPromotableIntegerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType)
/// \brief Retrieve the proxy-adaptor type.
///
/// This arrow operator is used when CanProxyAdaptor has been specialized
/// for the given type T. In that case, we reference members of the
/// CanProxyAdaptor specialization. Otherwise, this operator will be hidden
/// by the arrow operator in the primary CanProxyAdaptor template.
const CanProxyAdaptor<T> *operator->() const {
return static_cast<const CanProxyAdaptor<T> *>(this);
}
};
/// \brief Replacable canonical proxy adaptor class that provides the link
/// between a canonical type and the accessors of the type.
///
/// The CanProxyAdaptor is a replaceable class template that is instantiated
/// as part of each canonical proxy type. The primary template merely provides
/// redirection to the underlying type (T), e.g., @c PointerType. One can
/// provide specializations of this class template for each underlying type
/// that provide accessors returning canonical types (@c CanQualType) rather
/// than the more typical @c QualType, to propagate the notion of "canonical"
/// through the system.
template<typename T>
struct CanProxyAdaptor : CanProxyBase<T> { };
/// \brief Canonical proxy type returned when retrieving the members of a
/// canonical type or as the result of the @c CanQual<T>::getAs member
/// function.
///
/// The CanProxy type mainly exists as a proxy through which operator-> will
/// look to either map down to a raw T* (e.g., PointerType*) or to a proxy
/// type that provides canonical-type access to the fields of the type.
template<typename T>
class CanProxy : public CanProxyAdaptor<T> {
public:
/// \brief Build a NULL proxy.
CanProxy() { }
/// \brief Build a proxy to the given canonical type.
CanProxy(CanQual<T> Stored) { this->Stored = Stored; }
/// \brief Implicit conversion to the stored canonical type.
operator CanQual<T>() const { return this->Stored; }
};
} // end namespace clang
namespace llvm {
/// Implement simplify_type for CanQual<T>, so that we can dyn_cast from
/// CanQual<T> to a specific Type class. We're prefer isa/dyn_cast/cast/etc.
/// to return smart pointer (proxies?).
template<typename T>
struct simplify_type<const ::clang::CanQual<T> > {
typedef T* SimpleType;
static SimpleType getSimplifiedValue(const ::clang::CanQual<T> &Val) {
return Val.getTypePtr();
}
};
template<typename T>
struct simplify_type< ::clang::CanQual<T> >
: public simplify_type<const ::clang::CanQual<T> > {};
// Teach SmallPtrSet that CanQual<T> is "basically a pointer".
template<typename T>
class PointerLikeTypeTraits<clang::CanQual<T> > {
public:
static inline void *getAsVoidPointer(clang::CanQual<T> P) {
return P.getAsOpaquePtr();
}
static inline clang::CanQual<T> getFromVoidPointer(void *P) {
return clang::CanQual<T>::getFromOpaquePtr(P);
}
// CVR qualifiers go in low bits.
enum { NumLowBitsAvailable = 0 };
};
} // end namespace llvm
namespace clang {
//----------------------------------------------------------------------------//
// Canonical proxy adaptors for canonical type nodes.
//----------------------------------------------------------------------------//
/// \brief Iterator adaptor that turns an iterator over canonical QualTypes
/// into an iterator over CanQualTypes.
template<typename InputIterator>
class CanTypeIterator {
InputIterator Iter;
public:
typedef CanQualType value_type;
typedef value_type reference;
typedef CanProxy<Type> pointer;
typedef typename std::iterator_traits<InputIterator>::difference_type
difference_type;
typedef typename std::iterator_traits<InputIterator>::iterator_category
iterator_category;
CanTypeIterator() : Iter() { }
explicit CanTypeIterator(InputIterator Iter) : Iter(Iter) { }
// Input iterator
reference operator*() const {
return CanQualType::CreateUnsafe(*Iter);
}
pointer operator->() const;
CanTypeIterator &operator++() {
++Iter;
return *this;
}
CanTypeIterator operator++(int) {
CanTypeIterator Tmp(*this);
++Iter;
return Tmp;
}
friend bool operator==(const CanTypeIterator& X, const CanTypeIterator &Y) {
return X.Iter == Y.Iter;
}
friend bool operator!=(const CanTypeIterator& X, const CanTypeIterator &Y) {
return X.Iter != Y.Iter;
}
// Bidirectional iterator
CanTypeIterator &operator--() {
--Iter;
return *this;
}
CanTypeIterator operator--(int) {
CanTypeIterator Tmp(*this);
--Iter;
return Tmp;
}
// Random access iterator
reference operator[](difference_type n) const {
return CanQualType::CreateUnsafe(Iter[n]);
}
CanTypeIterator &operator+=(difference_type n) {
Iter += n;
return *this;
}
CanTypeIterator &operator-=(difference_type n) {
Iter -= n;
return *this;
}
friend CanTypeIterator operator+(CanTypeIterator X, difference_type n) {
X += n;
return X;
}
friend CanTypeIterator operator+(difference_type n, CanTypeIterator X) {
X += n;
return X;
}
friend CanTypeIterator operator-(CanTypeIterator X, difference_type n) {
X -= n;
return X;
}
friend difference_type operator-(const CanTypeIterator &X,
const CanTypeIterator &Y) {
return X - Y;
}
};
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)
};
template<>
struct CanProxyAdaptor<PointerType> : public CanProxyBase<PointerType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
};
template<>
struct CanProxyAdaptor<BlockPointerType>
: public CanProxyBase<BlockPointerType>
{
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
};
template<>
struct CanProxyAdaptor<ReferenceType> : public CanProxyBase<ReferenceType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
};
template<>
struct CanProxyAdaptor<LValueReferenceType>
: public CanProxyBase<LValueReferenceType>
{
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
};
template<>
struct CanProxyAdaptor<RValueReferenceType>
: public CanProxyBase<RValueReferenceType>
{
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
};
template<>
struct CanProxyAdaptor<MemberPointerType>
: public CanProxyBase<MemberPointerType>
{
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Type *, getClass)
};
template<>
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)
};
template<>
struct CanProxyAdaptor<ConstantArrayType>
: public CanProxyBase<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(const llvm::APInt &, getSize)
};
template<>
struct CanProxyAdaptor<ConstantArrayWithExprType>
: public CanProxyBase<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(const llvm::APInt &, getSize)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
};
template<>
struct CanProxyAdaptor<ConstantArrayWithoutExprType>
: public CanProxyBase<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(const llvm::APInt &, getSize)
};
template<>
struct CanProxyAdaptor<IncompleteArrayType>
: public CanProxyBase<IncompleteArrayType>
{
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
getSizeModifier)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndexTypeQualifier)
};
template<>
struct CanProxyAdaptor<VariableArrayType>
: public CanProxyBase<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(Expr *, getSizeExpr)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
};
template<>
struct CanProxyAdaptor<DependentSizedArrayType>
: public CanProxyBase<DependentSizedArrayType>
{
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
};
template<>
struct CanProxyAdaptor<DependentSizedExtVectorType>
: public CanProxyBase<DependentSizedExtVectorType>
{
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Expr *, getSizeExpr)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getAttributeLoc)
};
template<>
struct CanProxyAdaptor<VectorType> : public CanProxyBase<VectorType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements)
};
template<>
struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements)
};
template<>
struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
};
template<>
struct CanProxyAdaptor<FunctionNoProtoType>
: public CanProxyBase<FunctionNoProtoType>
{
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
};
template<>
struct CanProxyAdaptor<FunctionProtoType>
: public CanProxyBase<FunctionProtoType>
{
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs);
CanQualType getArgType(unsigned i) const {
return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i));
}
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariadic)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getTypeQuals)
typedef CanTypeIterator<FunctionProtoType::arg_type_iterator>
arg_type_iterator;
arg_type_iterator arg_type_begin() const {
return arg_type_iterator(this->getTypePtr()->arg_type_begin());
}
arg_type_iterator arg_type_end() const {
return arg_type_iterator(this->getTypePtr()->arg_type_end());
}
// Note: canonical function types never have exception specifications
};
template<>
struct CanProxyAdaptor<TypeOfType> : public CanProxyBase<TypeOfType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
};
template<>
struct CanProxyAdaptor<DecltypeType> : public CanProxyBase<DecltypeType> {
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getUnderlyingExpr)
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
};
template<>
struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> {
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
};
template<>
struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> {
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getAddressSpace)
};
template<>
struct CanProxyAdaptor<EnumType> : public CanProxyBase<EnumType> {
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
};
template<>
struct CanProxyAdaptor<TemplateTypeParmType>
: public CanProxyBase<TemplateTypeParmType>
{
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getDepth)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndex)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isParameterPack)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(IdentifierInfo *, getName)
};
template<>
struct CanProxyAdaptor<ObjCObjectPointerType>
: public CanProxyBase<ObjCObjectPointerType>
{
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceType *,
getInterfaceType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCIdType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCClassType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedIdType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClassType)
typedef ObjCObjectPointerType::qual_iterator qual_iterator;
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols)
};
//----------------------------------------------------------------------------//
// Method and function definitions
//----------------------------------------------------------------------------//
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));
}
template<typename T>
inline CanQual<Type> CanQual<T>::getNonReferenceType() const {
if (CanQual<ReferenceType> RefType = getAs<ReferenceType>())
return RefType->getPointeeType();
else
return *this;
}
template<typename T>
CanQual<T> CanQual<T>::getFromOpaquePtr(void *Ptr) {
CanQual<T> Result;
Result.Stored.setFromOpaqueValue(Ptr);
assert((!Result || Result.Stored.isCanonical())
&& "Type is not canonical!");
return Result;
}
template<typename T>
CanQual<T> CanQual<T>::CreateUnsafe(QualType Other) {
assert((Other.isNull() || Other->isCanonical()) && "Type is not canonical!");
assert((Other.isNull() || isa<T>(Other.getTypePtr())) &&
"Dynamic type does not meet the static type's requires");
CanQual<T> Result;
Result.Stored = Other;
return Result;
}
template<typename T>
template<typename U>
CanProxy<U> CanQual<T>::getAs() const {
if (Stored.isNull())
return CanProxy<U>();
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>();
}
template<typename T>
CanProxy<T> CanQual<T>::operator->() const {
return CanProxy<T>(*this);
}
template<typename InputIterator>
typename CanTypeIterator<InputIterator>::pointer
CanTypeIterator<InputIterator>::operator->() const {
return CanProxy<Type>(*this);
}
}
#endif // LLVM_CLANG_AST_CANONICAL_TYPE_H

View File

@@ -15,6 +15,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
namespace llvm {
template <typename T> struct DenseMapInfo;
@@ -290,19 +291,19 @@ public:
/// getCXXConstructorName - Returns the name of a C++ constructor
/// for the given Type.
DeclarationName getCXXConstructorName(QualType Ty) {
DeclarationName getCXXConstructorName(CanQualType Ty) {
return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty);
}
/// getCXXDestructorName - Returns the name of a C++ destructor
/// for the given Type.
DeclarationName getCXXDestructorName(QualType Ty) {
DeclarationName getCXXDestructorName(CanQualType Ty) {
return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty);
}
/// getCXXConversionFunctionName - Returns the name of a C++
/// conversion function for the given Type.
DeclarationName getCXXConversionFunctionName(QualType Ty) {
DeclarationName getCXXConversionFunctionName(CanQualType Ty) {
return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
}
@@ -310,7 +311,7 @@ public:
/// of C++ name, e.g., for a constructor, destructor, or conversion
/// function.
DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind,
QualType Ty);
CanQualType Ty);
/// getCXXOperatorName - Get the name of the overloadable C++
/// operator corresponding to Op.

View File

@@ -19,6 +19,7 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/type_traits.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -178,11 +179,11 @@ public:
/// operator==/!= - Indicate whether the specified types and qualifiers are
/// identical.
bool operator==(const QualType &RHS) const {
return Value == RHS.Value;
friend bool operator==(const QualType &LHS, const QualType &RHS) {
return LHS.Value == RHS.Value;
}
bool operator!=(const QualType &RHS) const {
return Value != RHS.Value;
friend bool operator!=(const QualType &LHS, const QualType &RHS) {
return LHS.Value != RHS.Value;
}
std::string getAsString() const;
@@ -251,6 +252,7 @@ public:
// CVR qualifiers go in low bits.
enum { NumLowBitsAvailable = 0 };
};
} // end namespace llvm
namespace clang {

View File

@@ -2070,18 +2070,19 @@ QualType ASTContext::getPointerDiffType() const {
/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
/// to be free of any of these, allowing two canonical types to be compared
/// for exact equality with a simple pointer comparison.
QualType ASTContext::getCanonicalType(QualType T) {
CanQualType ASTContext::getCanonicalType(QualType T) {
QualType CanType = T.getTypePtr()->getCanonicalTypeInternal();
// If the result has type qualifiers, make sure to canonicalize them as well.
unsigned TypeQuals = T.getCVRQualifiers() | CanType.getCVRQualifiers();
if (TypeQuals == 0) return CanType;
if (TypeQuals == 0)
return CanQualType::CreateUnsafe(CanType);
// If the type qualifiers are on an array type, get the canonical type of the
// array with the qualifiers applied to the element type.
ArrayType *AT = dyn_cast<ArrayType>(CanType);
if (!AT)
return CanType.getQualifiedType(TypeQuals);
return CanQualType::CreateUnsafe(CanType.getQualifiedType(TypeQuals));
// Get the canonical version of the element with the extra qualifiers on it.
// This can recursively sink qualifiers through multiple levels of arrays.
@@ -2089,25 +2090,29 @@ QualType ASTContext::getCanonicalType(QualType T) {
NewEltTy = getCanonicalType(NewEltTy);
if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
return getConstantArrayType(NewEltTy, CAT->getSize(),CAT->getSizeModifier(),
CAT->getIndexTypeQualifier());
return CanQualType::CreateUnsafe(
getConstantArrayType(NewEltTy, CAT->getSize(),
CAT->getSizeModifier(),
CAT->getIndexTypeQualifier()));
if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT))
return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),
IAT->getIndexTypeQualifier());
return CanQualType::CreateUnsafe(
getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),
IAT->getIndexTypeQualifier()));
if (DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT))
return getDependentSizedArrayType(NewEltTy,
DSAT->getSizeExpr(),
DSAT->getSizeModifier(),
DSAT->getIndexTypeQualifier(),
DSAT->getBracketsRange());
return CanQualType::CreateUnsafe(
getDependentSizedArrayType(NewEltTy,
DSAT->getSizeExpr(),
DSAT->getSizeModifier(),
DSAT->getIndexTypeQualifier(),
DSAT->getBracketsRange()));
VariableArrayType *VAT = cast<VariableArrayType>(AT);
return getVariableArrayType(NewEltTy,
VAT->getSizeExpr(),
VAT->getSizeModifier(),
VAT->getIndexTypeQualifier(),
VAT->getBracketsRange());
return CanQualType::CreateUnsafe(getVariableArrayType(NewEltTy,
VAT->getSizeExpr(),
VAT->getSizeModifier(),
VAT->getIndexTypeQualifier(),
VAT->getBracketsRange()));
}
TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
@@ -2250,7 +2255,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) {
// If we get here, we either have type qualifiers on the type, or we have
// sugar such as a typedef in the way. If we have type qualifiers on the type
// we must propagate them down into the elemeng type.
// we must propagate them down into the element type.
unsigned CVRQuals = T.getCVRQualifiers();
unsigned AddrSpace = 0;
Type *Ty = T.getTypePtr();

View File

@@ -304,7 +304,8 @@ CXXRecordDecl::getDestructor(ASTContext &Context) {
QualType ClassType = Context.getTypeDeclType(this);
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
= Context.DeclarationNames.getCXXDestructorName(
Context.getCanonicalType(ClassType));
DeclContext::lookup_iterator I, E;
llvm::tie(I, E) = lookup(Name);

View File

@@ -298,12 +298,10 @@ DeclarationNameTable::~DeclarationNameTable() {
DeclarationName
DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
QualType Ty) {
CanQualType Ty) {
assert(Kind >= DeclarationName::CXXConstructorName &&
Kind <= DeclarationName::CXXConversionFunctionName &&
"Kind must be a C++ special name kind");
assert(Ty->isCanonical() &&
"Can only build C++ special names from canonical types");
llvm::FoldingSet<CXXSpecialName> *SpecialNames
= static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);

View File

@@ -2380,15 +2380,15 @@ PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
case DeclarationName::CXXConstructorName:
return Context->DeclarationNames.getCXXConstructorName(
GetType(Record[Idx++]));
Context->getCanonicalType(GetType(Record[Idx++])));
case DeclarationName::CXXDestructorName:
return Context->DeclarationNames.getCXXDestructorName(
GetType(Record[Idx++]));
Context->getCanonicalType(GetType(Record[Idx++])));
case DeclarationName::CXXConversionFunctionName:
return Context->DeclarationNames.getCXXConversionFunctionName(
GetType(Record[Idx++]));
Context->getCanonicalType(GetType(Record[Idx++])));
case DeclarationName::CXXOperatorName:
return Context->DeclarationNames.getCXXOperatorName(

View File

@@ -1553,21 +1553,21 @@ DeclarationName Sema::GetNameForDeclarator(Declarator &D) {
case Declarator::DK_Constructor: {
QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
Ty = Context.getCanonicalType(Ty);
return Context.DeclarationNames.getCXXConstructorName(Ty);
return Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(Ty));
}
case Declarator::DK_Destructor: {
QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
Ty = Context.getCanonicalType(Ty);
return Context.DeclarationNames.getCXXDestructorName(Ty);
return Context.DeclarationNames.getCXXDestructorName(
Context.getCanonicalType(Ty));
}
case Declarator::DK_Conversion: {
// FIXME: We'd like to keep the non-canonical type for diagnostics!
QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
Ty = Context.getCanonicalType(Ty);
return Context.DeclarationNames.getCXXConversionFunctionName(Ty);
return Context.DeclarationNames.getCXXConversionFunctionName(
Context.getCanonicalType(Ty));
}
case Declarator::DK_Operator:
@@ -2736,9 +2736,9 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
QualType ClassType = Context.getTypeDeclType(Record);
if (!ClassType->isDependentType()) {
ClassType = Context.getCanonicalType(ClassType);
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
= Context.DeclarationNames.getCXXDestructorName(
Context.getCanonicalType(ClassType));
if (NewFD->getDeclName() != Name) {
Diag(NewFD->getLocation(), diag::err_destructor_name);
return NewFD->setInvalidDecl();

View File

@@ -1259,8 +1259,8 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
/// [special]p1). This routine can only be executed just before the
/// definition of the class is complete.
void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
QualType ClassType = Context.getTypeDeclType(ClassDecl);
ClassType = Context.getCanonicalType(ClassType);
CanQualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
// FIXME: Implicit declarations have exception specifications, which are
// the union of the specifications of the implicitly called functions.

View File

@@ -32,7 +32,7 @@ Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc,
const CXXScopeSpec &SS,
bool isAddressOfOperand) {
QualType ConvType = QualType::getFromOpaquePtr(Ty);
QualType ConvTypeCanon = Context.getCanonicalType(ConvType);
CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType);
DeclarationName ConvName
= Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen,

View File

@@ -484,7 +484,7 @@ Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
// Build the instantiated destructor declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
QualType ClassTy =
CanQualType ClassTy =
SemaRef.Context.getCanonicalType(SemaRef.Context.getTypeDeclType(Record));
CXXDestructorDecl *Destructor
= CXXDestructorDecl::Create(SemaRef.Context, Record,
@@ -517,7 +517,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
// Build the instantiated conversion declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
QualType ConvTy
CanQualType ConvTy
= SemaRef.Context.getCanonicalType(T->getAsFunctionType()->getResultType());
CXXConversionDecl *Conversion
= CXXConversionDecl::Create(SemaRef.Context, Record,