From 50d62d1b4a98adbc83de8f8cd1379ea1c25656f7 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 5 Aug 2009 05:36:45 +0000 Subject: [PATCH] Introduce the canonical type smart pointers, and use them in a few places to tighten up the static type system. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78164 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 3 +- include/clang/AST/CanonicalType.h | 746 +++++++++++++++++++++++ include/clang/AST/DeclarationName.h | 9 +- include/clang/AST/Type.h | 10 +- lib/AST/ASTContext.cpp | 41 +- lib/AST/DeclCXX.cpp | 3 +- lib/AST/DeclarationName.cpp | 4 +- lib/Frontend/PCHReader.cpp | 6 +- lib/Sema/SemaDecl.cpp | 16 +- lib/Sema/SemaDeclCXX.cpp | 4 +- lib/Sema/SemaExprCXX.cpp | 2 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 +- 12 files changed, 801 insertions(+), 47 deletions(-) create mode 100644 include/clang/AST/CanonicalType.h diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index abbcb44377..0822d2ae30 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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(); } diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h new file mode 100644 index 0000000000..f94f8446ba --- /dev/null +++ b/include/clang/AST/CanonicalType.h @@ -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 + +namespace clang { + +template class CanProxy; +template 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 will be of that +/// type (or some subclass of that type). The typedef @c CanQualType is just +/// a shorthand for @c CanQual. +/// +/// An instance of @c CanQual can be implicitly converted to a +/// @c CanQual when T is derived from U, which essentially provides an +/// implicit upcast. For example, @c CanQual can be +/// converted to @c CanQual. Note that any @c CanQual type can +/// be implicitly converted to a QualType, but the reverse operation requires +/// a call to ASTContext::getCanonicalType(). +/// +/// +template +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 + CanQual(const CanQual& Other, + typename llvm::enable_if, 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 Ptr = T->getAs()) { ... } + /// @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(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 T) { + /// if (CanQual Ptr = T->getAs()) { + /// // 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 CanProxy getAs() const; + + /// \brief Overloaded arrow operator that produces a canonical type + /// proxy. + CanProxy 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 getUnqualifiedType() const; + + CanQual getQualifiedType(unsigned TQs) const { + return CanQual::CreateUnsafe(QualType(getTypePtr(), TQs)); + } + + /// \brief Determines whether this canonical type is more qualified than + /// the @p Other canonical type. + bool isMoreQualifiedThan(CanQual 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 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 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 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 CreateUnsafe(QualType Other); +}; + +template +inline bool operator==(CanQual x, CanQual y) { + return x.getAsOpaquePtr() == y.getAsOpaquePtr(); +} + +template +inline bool operator!=(CanQual x, CanQual y) { + return x.getAsOpaquePtr() != y.getAsOpaquePtr(); +} + +/// \brief Represents a canonical, potentially-qualified type. +typedef CanQual 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 +class CanProxyBase { +protected: + CanQual 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 Ptr = T->getAs()) { ... } + /// @endcode + operator const T*() const { return this->Stored.getTypePtr(); } + + /// \brief Try to convert the given canonical type to a specific structural + /// type. + template CanProxy getAs() const { + return this->Stored.template getAs(); + } + + 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 *operator->() const { + return static_cast *>(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 +struct CanProxyAdaptor : CanProxyBase { }; + +/// \brief Canonical proxy type returned when retrieving the members of a +/// canonical type or as the result of the @c CanQual::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 +class CanProxy : public CanProxyAdaptor { +public: + /// \brief Build a NULL proxy. + CanProxy() { } + + /// \brief Build a proxy to the given canonical type. + CanProxy(CanQual Stored) { this->Stored = Stored; } + + /// \brief Implicit conversion to the stored canonical type. + operator CanQual() const { return this->Stored; } +}; + +} // end namespace clang + +namespace llvm { + +/// Implement simplify_type for CanQual, so that we can dyn_cast from +/// CanQual to a specific Type class. We're prefer isa/dyn_cast/cast/etc. +/// to return smart pointer (proxies?). +template +struct simplify_type > { + typedef T* SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CanQual &Val) { + return Val.getTypePtr(); + } +}; +template +struct simplify_type< ::clang::CanQual > +: public simplify_type > {}; + +// Teach SmallPtrSet that CanQual is "basically a pointer". +template +class PointerLikeTypeTraits > { +public: + static inline void *getAsVoidPointer(clang::CanQual P) { + return P.getAsOpaquePtr(); + } + static inline clang::CanQual getFromVoidPointer(void *P) { + return clang::CanQual::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 +class CanTypeIterator { + InputIterator Iter; + +public: + typedef CanQualType value_type; + typedef value_type reference; + typedef CanProxy pointer; + typedef typename std::iterator_traits::difference_type + difference_type; + typedef typename std::iterator_traits::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 : public CanProxyBase { + 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 : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase +{ + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase +{ + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase +{ + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase +{ + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Type *, getClass) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndexTypeQualifier) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase +{ + 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 + : public CanProxyBase +{ + 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 + : public CanProxyBase +{ + 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 + : public CanProxyBase +{ + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndexTypeQualifier) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase +{ + 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 + : public CanProxyBase +{ + 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 + : public CanProxyBase +{ + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Expr *, getSizeExpr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getAttributeLoc) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase +{ + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase +{ + 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 + 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 : public CanProxyBase { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getUnderlyingExpr) + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) +}; + +template<> +struct CanProxyAdaptor : public CanProxyBase { + 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 : public CanProxyBase { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) +}; + +template<> +struct CanProxyAdaptor + : public CanProxyBase +{ + 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 + : public CanProxyBase +{ + 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 +inline CanQual CanQual::getUnqualifiedType() const { + if (CanQual EQ = getAs()) + return CanQual::CreateUnsafe(QualType(EQ->getBaseType(), 0)); + return CanQual::CreateUnsafe(QualType(Stored.getTypePtr(), 0)); +} + +template +inline CanQual CanQual::getNonReferenceType() const { + if (CanQual RefType = getAs()) + return RefType->getPointeeType(); + else + return *this; +} + +template +CanQual CanQual::getFromOpaquePtr(void *Ptr) { + CanQual Result; + Result.Stored.setFromOpaqueValue(Ptr); + assert((!Result || Result.Stored.isCanonical()) + && "Type is not canonical!"); + return Result; +} + +template +CanQual CanQual::CreateUnsafe(QualType Other) { + assert((Other.isNull() || Other->isCanonical()) && "Type is not canonical!"); + assert((Other.isNull() || isa(Other.getTypePtr())) && + "Dynamic type does not meet the static type's requires"); + CanQual Result; + Result.Stored = Other; + return Result; +} + +template +template +CanProxy CanQual::getAs() const { + if (Stored.isNull()) + return CanProxy(); + + if (isa(Stored.getTypePtr())) + return CanQual::CreateUnsafe(Stored); + + if (const ExtQualType *EQ = Stored->getAs()) + return CanQual::CreateUnsafe(QualType(EQ->getBaseType(), 0)) + .template getAs(); + + return CanProxy(); +} + +template +CanProxy CanQual::operator->() const { + return CanProxy(*this); +} + +template +typename CanTypeIterator::pointer +CanTypeIterator::operator->() const { + return CanProxy(*this); +} + +} + + +#endif // LLVM_CLANG_AST_CANONICAL_TYPE_H diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index db140999b0..3d571b1ac0 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -15,6 +15,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" namespace llvm { template 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. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 7bf877ed1a..b5317edb03 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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 { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c4740843e5..ad46bcdca7 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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(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(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(AT)) - return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeQualifier()); + return CanQualType::CreateUnsafe( + getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), + IAT->getIndexTypeQualifier())); if (DependentSizedArrayType *DSAT = dyn_cast(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(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(); diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index ad015d12de..52619e9920 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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); diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index a55b363a0d..da9f01a9aa 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -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 *SpecialNames = static_cast*>(CXXSpecialNamesImpl); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 61be4da5b7..aab5dd8783 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -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( diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a21502961a..44ee2ebbf0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(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(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 76bd71cdce..0e42a71c59 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index e31f9edb61..2ebd7b184d 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index abe1fffe88..021a6ad2ab 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -484,7 +484,7 @@ Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) { // Build the instantiated destructor declaration. CXXRecordDecl *Record = cast(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(Owner); QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); - QualType ConvTy + CanQualType ConvTy = SemaRef.Context.getCanonicalType(T->getAsFunctionType()->getResultType()); CXXConversionDecl *Conversion = CXXConversionDecl::Create(SemaRef.Context, Record, -- 2.40.0