llvm/clang/include/clang/AST/Type.h

//===- Type.h - C Language Family Type Representation -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
/// \file
/// C Language Family Type Representation
///
/// This file defines the clang::Type interface and subclasses, used to
/// represent types for languages in the C family.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_TYPE_H
#define LLVM_CLANG_AST_TYPE_H

#include "clang/AST/DependenceFlags.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Linkage.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/PointerAuthOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/Visibility.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DXILABI.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include "llvm/Support/TrailingObjects.h"
#include "llvm/Support/type_traits.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <optional>
#include <string>
#include <type_traits>
#include <utility>

namespace clang {

class BTFTypeTagAttr;
class ExtQuals;
class QualType;
class ConceptDecl;
class ValueDecl;
class TagDecl;
class TemplateParameterList;
class Type;

enum {};

namespace serialization {
  template <class T> class AbstractTypeReader;
  template <class T> class AbstractTypeWriter;
}

} // namespace clang

namespace llvm {

  template <typename T>
  struct PointerLikeTypeTraits;
  template<>
  struct PointerLikeTypeTraits< ::clang::Type*> {};

  template<>
  struct PointerLikeTypeTraits< ::clang::ExtQuals*> {};

} // namespace llvm

namespace clang {

class ASTContext;
template <typename> class CanQual;
class CXXRecordDecl;
class DeclContext;
class EnumDecl;
class Expr;
class ExtQualsTypeCommonBase;
class FunctionDecl;
class FunctionEffectSet;
class IdentifierInfo;
class NamedDecl;
class ObjCInterfaceDecl;
class ObjCProtocolDecl;
class ObjCTypeParamDecl;
struct PrintingPolicy;
class RecordDecl;
class Stmt;
class TagDecl;
class TemplateArgument;
class TemplateArgumentListInfo;
class TemplateArgumentLoc;
class TemplateTypeParmDecl;
class TypedefNameDecl;
class UnresolvedUsingTypenameDecl;
class UsingShadowDecl;

CanQualType;

// Provide forward declarations for all of the *Type classes.
#define TYPE
#include "clang/AST/TypeNodes.inc"

/// Pointer-authentication qualifiers.
class PointerAuthQualifier {};

/// The collection of all-type qualifiers we support.
/// Clang supports five independent qualifiers:
/// * C99: const, volatile, and restrict
/// * MS: __unaligned
/// * Embedded C (TR18037): address spaces
/// * Objective C: the GC attributes (none, weak, or strong)
class Qualifiers {};

class QualifiersAndAtomic {};

/// A std::pair-like structure for storing a qualified type split
/// into its local qualifiers and its locally-unqualified type.
struct SplitQualType {};

/// The kind of type we are substituting Objective-C type arguments into.
///
/// The kind of substitution affects the replacement of type parameters when
/// no concrete type information is provided, e.g., when dealing with an
/// unspecialized type.
enum class ObjCSubstitutionContext {};

/// The kind of 'typeof' expression we're after.
enum class TypeOfKind : uint8_t {};

/// A (possibly-)qualified type.
///
/// 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 {};

raw_ostream &operator<<(raw_ostream &OS, QualType QT);

} // namespace clang

namespace llvm {

/// Implement simplify_type for QualType, so that we can dyn_cast from QualType
/// to a specific Type class.
template<> struct simplify_type< ::clang::QualType> {};

// Teach SmallPtrSet that QualType is "basically a pointer".
template<>
struct PointerLikeTypeTraits<clang::QualType> {};

} // namespace llvm

namespace clang {

/// Base class that is common to both the \c ExtQuals and \c Type
/// classes, which allows \c QualType to access the common fields between the
/// two.
class ExtQualsTypeCommonBase {};

/// We can encode up to four 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', 'restrict', and 'volatile' qualifiers
/// in three low bits on the QualType pointer; a fourth bit records whether
/// the pointer is an ExtQuals node. The extended qualifiers (address spaces,
/// Objective-C GC attributes) are much more rare.
class alignas(TypeAlignment) ExtQuals : public ExtQualsTypeCommonBase,
                                        public llvm::FoldingSetNode {};

/// The kind of C++11 ref-qualifier associated with a function type.
/// This determines whether a member function's "this" object can be an
/// lvalue, rvalue, or neither.
enum RefQualifierKind {};

/// Which keyword(s) were used to create an AutoType.
enum class AutoTypeKeyword {};

enum class ArraySizeModifier;
enum class ElaboratedTypeKeyword;
enum class VectorKind;

/// The base class of the type hierarchy.
///
/// A central concept with types is that each type always has a canonical
/// type.  A canonical type is the type with any typedef names stripped out
/// of it or the types it references.  For example, consider:
///
///  typedef int  foo;
///  typedef foo* bar;
///    'int *'    'foo *'    'bar'
///
/// There will be a Type object created for 'int'.  Since int is canonical, its
/// CanonicalType pointer points to itself.  There is also a Type for 'foo' (a
/// TypedefType).  Its CanonicalType pointer points to the 'int' Type.  Next
/// there is a PointerType that represents 'int*', which, like 'int', is
/// canonical.  Finally, there is a PointerType type for 'foo*' whose canonical
/// type is 'int*', and there is a TypedefType for 'bar', whose canonical type
/// is also 'int*'.
///
/// Non-canonical types are useful for emitting diagnostics, without losing
/// information about typedefs being used.  Canonical types are useful for type
/// comparisons (they allow by-pointer equality tests) and useful for reasoning
/// about whether something has a particular form (e.g. is a function type),
/// because they implicitly, recursively, strip all typedefs out of a type.
///
/// Types, once created, are immutable.
///
class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {};

/// This will check for a TypedefType by removing any existing sugar
/// until it reaches a TypedefType or a non-sugared type.
template <> const TypedefType *Type::getAs() const;
template <> const UsingType *Type::getAs() const;

/// This will check for a TemplateSpecializationType by removing any
/// existing sugar until it reaches a TemplateSpecializationType or a
/// non-sugared type.
template <> const TemplateSpecializationType *Type::getAs() const;

/// This will check for an AttributedType by removing any existing sugar
/// until it reaches an AttributedType or a non-sugared type.
template <> const AttributedType *Type::getAs() const;

/// This will check for a BoundsAttributedType by removing any existing
/// sugar until it reaches an BoundsAttributedType or a non-sugared type.
template <> const BoundsAttributedType *Type::getAs() const;

/// This will check for a CountAttributedType by removing any existing
/// sugar until it reaches an CountAttributedType or a non-sugared type.
template <> const CountAttributedType *Type::getAs() const;

// We can do canonical leaf types faster, because we don't have to
// worry about preserving child type decoration.
#define TYPE
#define LEAF_TYPE
#include "clang/AST/TypeNodes.inc"

/// This class is used for builtin types like 'int'.  Builtin
/// types are always canonical and have a literal name field.
class BuiltinType : public Type {};

/// Complex values, per C99 6.2.5p11.  This supports the C99 complex
/// types (_Complex float etc) as well as the GCC integer complex extensions.
class ComplexType : public Type, public llvm::FoldingSetNode {};

/// Sugar for parentheses used when specifying types.
class ParenType : public Type, public llvm::FoldingSetNode {};

/// PointerType - C99 6.7.5.1 - Pointer Declarators.
class PointerType : public Type, public llvm::FoldingSetNode {};

/// [BoundsSafety] Represents information of declarations referenced by the
/// arguments of the `counted_by` attribute and the likes.
class TypeCoupledDeclRefInfo {};

/// [BoundsSafety] Represents a parent type class for CountAttributedType and
/// similar sugar types that will be introduced to represent a type with a
/// bounds attribute.
///
/// Provides a common interface to navigate declarations referred to by the
/// bounds expression.

class BoundsAttributedType : public Type, public llvm::FoldingSetNode {};

/// Represents a sugar type with `__counted_by` or `__sized_by` annotations,
/// including their `_or_null` variants.
class CountAttributedType final
    : public BoundsAttributedType,
      public llvm::TrailingObjects<CountAttributedType,
                                   TypeCoupledDeclRefInfo> {};

/// Represents a type which was implicitly adjusted by the semantic
/// engine for arbitrary reasons.  For example, array and function types can
/// decay, and function types can have their calling conventions adjusted.
class AdjustedType : public Type, public llvm::FoldingSetNode {};

/// Represents a pointer type decayed from an array or function type.
class DecayedType : public AdjustedType {};

/// Pointer to a block type.
/// This type is to represent types syntactically represented as
/// "void (^)(int)", etc. Pointee is required to always be a function type.
class BlockPointerType : public Type, public llvm::FoldingSetNode {};

/// Base for LValueReferenceType and RValueReferenceType
class ReferenceType : public Type, public llvm::FoldingSetNode {};

/// An lvalue reference type, per C++11 [dcl.ref].
class LValueReferenceType : public ReferenceType {};

/// An rvalue reference type, per C++11 [dcl.ref].
class RValueReferenceType : public ReferenceType {};

/// A pointer to member type per C++ 8.3.3 - Pointers to members.
///
/// This includes both pointers to data members and pointer to member functions.
class MemberPointerType : public Type, public llvm::FoldingSetNode {};

/// Capture whether this is a normal array (e.g. int X[4])
/// an array with a static size (e.g. int X[static 4]), or an array
/// with a star size (e.g. int X[*]).
/// 'static' is only allowed on function parameters.
enum class ArraySizeModifier {};

/// Represents an array type, per C99 6.7.5.2 - Array Declarators.
class ArrayType : public Type, public llvm::FoldingSetNode {};

/// Represents the canonical version of C arrays with a specified constant size.
/// For example, the canonical type for 'int A[4 + 4*100]' is a
/// ConstantArrayType where the element type is 'int' and the size is 404.
class ConstantArrayType : public ArrayType {};

/// Represents a constant array type that does not decay to a pointer when used
/// as a function parameter.
class ArrayParameterType : public ConstantArrayType {};

/// Represents a C array with an unspecified size.  For example 'int A[]' has
/// an IncompleteArrayType where the element type is 'int' and the size is
/// unspecified.
class IncompleteArrayType : public ArrayType {};

/// Represents a C array with a specified size that is not an
/// integer-constant-expression.  For example, 'int s[x+foo()]'.
/// Since the size expression is an arbitrary expression, we store it as such.
///
/// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and
/// should not be: two lexically equivalent variable array types could mean
/// different things, for example, these variables do not have the same type
/// dynamically:
///
/// void foo(int x) {
///   int Y[x];
///   ++x;
///   int Z[x];
/// }
class VariableArrayType : public ArrayType {};

/// Represents an array type in C++ whose size is a value-dependent expression.
///
/// For example:
/// \code
/// template<typename T, int Size>
/// class array {
///   T data[Size];
/// };
/// \endcode
///
/// For these types, we won't actually know what the array bound is
/// until template instantiation occurs, at which point this will
/// become either a ConstantArrayType or a VariableArrayType.
class DependentSizedArrayType : public ArrayType {};

/// Represents an extended address space qualifier where the input address space
/// value is dependent. Non-dependent address spaces are not represented with a
/// special Type subclass; they are stored on an ExtQuals node as part of a QualType.
///
/// For example:
/// \code
/// template<typename T, int AddrSpace>
/// class AddressSpace {
///   typedef T __attribute__((address_space(AddrSpace))) type;
/// }
/// \endcode
class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode {};

/// Represents an extended vector type where either the type or size is
/// dependent.
///
/// For example:
/// \code
/// template<typename T, int Size>
/// class vector {
///   typedef T __attribute__((ext_vector_type(Size))) type;
/// }
/// \endcode
class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode {};

enum class VectorKind {};

/// Represents a GCC generic vector type. This type is created using
/// __attribute__((vector_size(n)), where "n" specifies the vector size in
/// bytes; or from an Altivec __vector or vector declaration.
/// Since the constructor takes the number of vector elements, the
/// client is responsible for converting the size into the number of elements.
class VectorType : public Type, public llvm::FoldingSetNode {};

/// Represents a vector type where either the type or size is dependent.
////
/// For example:
/// \code
/// template<typename T, int Size>
/// class vector {
///   typedef T __attribute__((vector_size(Size))) type;
/// }
/// \endcode
class DependentVectorType : public Type, public llvm::FoldingSetNode {};

/// ExtVectorType - Extended vector type. This type is created using
/// __attribute__((ext_vector_type(n)), where "n" is the number of elements.
/// Unlike vector_size, ext_vector_type is only allowed on typedef's. This
/// class enables syntactic extensions, like Vector Components for accessing
/// points (as .xyzw), colors (as .rgba), and textures (modeled after OpenGL
/// Shading Language).
class ExtVectorType : public VectorType {};

/// Represents a matrix type, as defined in the Matrix Types clang extensions.
/// __attribute__((matrix_type(rows, columns))), where "rows" specifies
/// number of rows and "columns" specifies the number of columns.
class MatrixType : public Type, public llvm::FoldingSetNode {};

/// Represents a concrete matrix type with constant number of rows and columns
class ConstantMatrixType final : public MatrixType {};

/// Represents a matrix type where the type and the number of rows and columns
/// is dependent on a template.
class DependentSizedMatrixType final : public MatrixType {};

/// FunctionType - C99 6.7.5.3 - Function Declarators.  This is the common base
/// class of FunctionNoProtoType and FunctionProtoType.
class FunctionType : public Type {};

/// Represents a K&R-style 'int foo()' function, which has
/// no information available about its arguments.
class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {};

// ------------------------------------------------------------------------------

/// Represents an abstract function effect, using just an enumeration describing
/// its kind.
class FunctionEffect {};

/// Wrap a function effect's condition expression in another struct so
/// that FunctionProtoType's TrailingObjects can treat it separately.
class EffectConditionExpr {};

/// A FunctionEffect plus a potential boolean expression determining whether
/// the effect is declared (e.g. nonblocking(expr)). Generally the condition
/// expression when present, is dependent.
struct FunctionEffectWithCondition {};

/// Support iteration in parallel through a pair of FunctionEffect and
/// EffectConditionExpr containers.
template <typename Container> class FunctionEffectIterator {};

/// An immutable set of FunctionEffects and possibly conditions attached to
/// them. The effects and conditions reside in memory not managed by this object
/// (typically, trailing objects in FunctionProtoType, or borrowed references
/// from a FunctionEffectSet).
///
/// Invariants:
/// - there is never more than one instance of any given effect.
/// - the array of conditions is either empty or has the same size as the
///   array of effects.
/// - some conditions may be null expressions; each condition pertains to
///   the effect at the same array index.
///
/// Also, if there are any conditions, at least one of those expressions will be
/// dependent, but this is only asserted in the constructor of
/// FunctionProtoType.
///
/// See also FunctionEffectSet, in Sema, which provides a mutable set.
class FunctionEffectsRef {};

/// A mutable set of FunctionEffects and possibly conditions attached to them.
/// Used to compare and merge effects on declarations.
///
/// Has the same invariants as FunctionEffectsRef.
class FunctionEffectSet {};

/// Represents a prototype with parameter type info, e.g.
/// 'int foo(int)' or 'int foo(void)'.  'void' is represented as having no
/// parameters, not as having a single void parameter. Such a type can have
/// an exception specification, but this specification is not part of the
/// canonical type. FunctionProtoType has several trailing objects, some of
/// which optional. For more information about the trailing objects see
/// the first comment inside FunctionProtoType.
class FunctionProtoType final
    : public FunctionType,
      public llvm::FoldingSetNode,
      private llvm::TrailingObjects<
          FunctionProtoType, QualType, SourceLocation,
          FunctionType::FunctionTypeExtraBitfields,
          FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType,
          Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers,
          FunctionEffect, EffectConditionExpr> {};

/// Represents the dependent type named by a dependently-scoped
/// typename using declaration, e.g.
///   using typename Base<T>::foo;
///
/// Template instantiation turns these into the underlying type.
class UnresolvedUsingType : public Type {};

class UsingType final : public Type,
                        public llvm::FoldingSetNode,
                        private llvm::TrailingObjects<UsingType, QualType> {};

class TypedefType final : public Type,
                          public llvm::FoldingSetNode,
                          private llvm::TrailingObjects<TypedefType, QualType> {};

/// Sugar type that represents a type that was qualified by a qualifier written
/// as a macro invocation.
class MacroQualifiedType : public Type {};

/// Represents a `typeof` (or __typeof__) expression (a C23 feature and GCC
/// extension) or a `typeof_unqual` expression (a C23 feature).
class TypeOfExprType : public Type {};

/// Internal representation of canonical, dependent
/// `typeof(expr)` types.
///
/// This class is used internally by the ASTContext to manage
/// canonical, dependent types, only. Clients will only see instances
/// of this class via TypeOfExprType nodes.
class DependentTypeOfExprType : public TypeOfExprType,
                                public llvm::FoldingSetNode {};

/// Represents `typeof(type)`, a C23 feature and GCC extension, or
/// `typeof_unqual(type), a C23 feature.
class TypeOfType : public Type {};

/// Represents the type `decltype(expr)` (C++11).
class DecltypeType : public Type {};

/// Internal representation of canonical, dependent
/// decltype(expr) types.
///
/// This class is used internally by the ASTContext to manage
/// canonical, dependent types, only. Clients will only see instances
/// of this class via DecltypeType nodes.
class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {};

class PackIndexingType final
    : public Type,
      public llvm::FoldingSetNode,
      private llvm::TrailingObjects<PackIndexingType, QualType> {};

/// A unary type transform, which is a type constructed from another.
class UnaryTransformType : public Type {};

/// Internal representation of canonical, dependent
/// __underlying_type(type) types.
///
/// This class is used internally by the ASTContext to manage
/// canonical, dependent types, only. Clients will only see instances
/// of this class via UnaryTransformType nodes.
class DependentUnaryTransformType : public UnaryTransformType,
                                    public llvm::FoldingSetNode {};

class TagType : public Type {};

/// A helper class that allows the use of isa/cast/dyncast
/// to detect TagType objects of structs/unions/classes.
class RecordType : public TagType {};

/// A helper class that allows the use of isa/cast/dyncast
/// to detect TagType objects of enums.
class EnumType : public TagType {};

/// An attributed type is a type to which a type attribute has been applied.
///
/// The "modified type" is the fully-sugared type to which the attributed
/// type was applied; generally it is not canonically equivalent to the
/// attributed type. The "equivalent type" is the minimally-desugared type
/// which the type is canonically equivalent to.
///
/// For example, in the following attributed type:
///     int32_t __attribute__((vector_size(16)))
///   - the modified type is the TypedefType for int32_t
///   - the equivalent type is VectorType(16, int32_t)
///   - the canonical type is VectorType(16, int)
class AttributedType : public Type, public llvm::FoldingSetNode {};

class BTFTagAttributedType : public Type, public llvm::FoldingSetNode {};

class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {};

class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {};

/// Represents the result of substituting a type for a template
/// type parameter.
///
/// Within an instantiated template, all template type parameters have
/// been replaced with these.  They are used solely to record that a
/// type was originally written as a template type parameter;
/// therefore they are never canonical.
class SubstTemplateTypeParmType final
    : public Type,
      public llvm::FoldingSetNode,
      private llvm::TrailingObjects<SubstTemplateTypeParmType, QualType> {};

/// Represents the result of substituting a set of types for a template
/// type parameter pack.
///
/// When a pack expansion in the source code contains multiple parameter packs
/// and those parameter packs correspond to different levels of template
/// parameter lists, this type node is used to represent a template type
/// parameter pack from an outer level, which has already had its argument pack
/// substituted but that still lives within a pack expansion that itself
/// could not be instantiated. When actually performing a substitution into
/// that pack expansion (e.g., when all template parameters have corresponding
/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType
/// at the current pack substitution index.
class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {};

/// Common base class for placeholders for types that get replaced by
/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced
/// class template types, and constrained type names.
///
/// These types are usually a placeholder for a deduced type. However, before
/// the initializer is attached, or (usually) if the initializer is
/// type-dependent, there is no deduced type and the type is canonical. In
/// the latter case, it is also a dependent type.
class DeducedType : public Type {};

/// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained
/// by a type-constraint.
class AutoType : public DeducedType, public llvm::FoldingSetNode {};

/// Represents a C++17 deduced template specialization type.
class DeducedTemplateSpecializationType : public DeducedType,
                                          public llvm::FoldingSetNode {};

/// Represents a type template specialization; the template
/// must be a class template, a type alias template, or a template
/// template parameter.  A template which cannot be resolved to one of
/// these, e.g. because it is written with a dependent scope
/// specifier, is instead represented as a
/// @c DependentTemplateSpecializationType.
///
/// A non-dependent template specialization type is always "sugar",
/// typically for a \c RecordType.  For example, a class template
/// specialization type of \c vector<int> will refer to a tag type for
/// the instantiation \c std::vector<int, std::allocator<int>>
///
/// Template specializations are dependent if either the template or
/// any of the template arguments are dependent, in which case the
/// type may also be canonical.
///
/// Instances of this type are allocated with a trailing array of
/// TemplateArguments, followed by a QualType representing the
/// non-canonical aliased type when the template is a type alias
/// template.
class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {};

/// Print a template argument list, including the '<' and '>'
/// enclosing the template arguments.
void printTemplateArgumentList(raw_ostream &OS,
                               ArrayRef<TemplateArgument> Args,
                               const PrintingPolicy &Policy,
                               const TemplateParameterList *TPL = nullptr);

void printTemplateArgumentList(raw_ostream &OS,
                               ArrayRef<TemplateArgumentLoc> Args,
                               const PrintingPolicy &Policy,
                               const TemplateParameterList *TPL = nullptr);

void printTemplateArgumentList(raw_ostream &OS,
                               const TemplateArgumentListInfo &Args,
                               const PrintingPolicy &Policy,
                               const TemplateParameterList *TPL = nullptr);

/// Make a best-effort determination of whether the type T can be produced by
/// substituting Args into the default argument of Param.
bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
                                  const NamedDecl *Param,
                                  ArrayRef<TemplateArgument> Args,
                                  unsigned Depth);

/// The injected class name of a C++ class template or class
/// template partial specialization.  Used to record that a type was
/// spelled with a bare identifier rather than as a template-id; the
/// equivalent for non-templated classes is just RecordType.
///
/// Injected class name types are always dependent.  Template
/// instantiation turns these into RecordTypes.
///
/// Injected class name types are always canonical.  This works
/// because it is impossible to compare an injected class name type
/// with the corresponding non-injected template type, for the same
/// reason that it is impossible to directly compare template
/// parameters from different dependent contexts: injected class name
/// types can only occur within the scope of a particular templated
/// declaration, and within that scope every template specialization
/// will canonicalize to the injected class name (when appropriate
/// according to the rules of the language).
class InjectedClassNameType : public Type {};

/// The elaboration keyword that precedes a qualified type name or
/// introduces an elaborated-type-specifier.
enum class ElaboratedTypeKeyword {};

/// The kind of a tag type.
enum class TagTypeKind {};

/// A helper class for Type nodes having an ElaboratedTypeKeyword.
/// The keyword in stored in the free bits of the base class.
/// Also provides a few static helpers for converting and printing
/// elaborated type keyword and tag type kind enumerations.
class TypeWithKeyword : public Type {};

/// Represents a type that was referred to using an elaborated type
/// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type,
/// or both.
///
/// This type is used to keep track of a type name as written in the
/// source code, including tag keywords and any nested-name-specifiers.
/// The type itself is always "sugar", used to express what was written
/// in the source code but containing no additional semantic information.
class ElaboratedType final
    : public TypeWithKeyword,
      public llvm::FoldingSetNode,
      private llvm::TrailingObjects<ElaboratedType, TagDecl *> {};

/// Represents a qualified type name for which the type name is
/// dependent.
///
/// DependentNameType represents a class of dependent types that involve a
/// possibly dependent nested-name-specifier (e.g., "T::") followed by a
/// name of a type. The DependentNameType may start with a "typename" (for a
/// typename-specifier), "class", "struct", "union", or "enum" (for a
/// dependent elaborated-type-specifier), or nothing (in contexts where we
/// know that we must be referring to a type, e.g., in a base class specifier).
/// Typically the nested-name-specifier is dependent, but in MSVC compatibility
/// mode, this type is used with non-dependent names to delay name lookup until
/// instantiation.
class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {};

/// Represents a template specialization type whose template cannot be
/// resolved, e.g.
///   A<T>::template B<T>
class DependentTemplateSpecializationType : public TypeWithKeyword,
                                            public llvm::FoldingSetNode {};

/// Represents a pack expansion of types.
///
/// Pack expansions are part of C++11 variadic templates. A pack
/// expansion contains a pattern, which itself contains one or more
/// "unexpanded" parameter packs. When instantiated, a pack expansion
/// produces a series of types, each instantiated from the pattern of
/// the expansion, where the Ith instantiation of the pattern uses the
/// Ith arguments bound to each of the unexpanded parameter packs. The
/// pack expansion is considered to "expand" these unexpanded
/// parameter packs.
///
/// \code
/// template<typename ...Types> struct tuple;
///
/// template<typename ...Types>
/// struct tuple_of_references {
///   typedef tuple<Types&...> type;
/// };
/// \endcode
///
/// Here, the pack expansion \c Types&... is represented via a
/// PackExpansionType whose pattern is Types&.
class PackExpansionType : public Type, public llvm::FoldingSetNode {};

/// This class wraps the list of protocol qualifiers. For types that can
/// take ObjC protocol qualifers, they can subclass this class.
template <class T>
class ObjCProtocolQualifiers {};

/// Represents a type parameter type in Objective C. It can take
/// a list of protocols.
class ObjCTypeParamType : public Type,
                          public ObjCProtocolQualifiers<ObjCTypeParamType>,
                          public llvm::FoldingSetNode {};

/// Represents a class type in Objective C.
///
/// Every Objective C type is a combination of a base type, a set of
/// type arguments (optional, for parameterized classes) and a list of
/// protocols.
///
/// Given the following declarations:
/// \code
///   \@class C<T>;
///   \@protocol P;
/// \endcode
///
/// 'C' is an ObjCInterfaceType C.  It is sugar for an ObjCObjectType
/// with base C and no protocols.
///
/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list [P].
/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no
/// protocol list.
/// 'C<C*><P>' is a specialized ObjCObjectType with base C, type arguments 'C*',
/// and protocol list [P].
///
/// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose
/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType
/// and no protocols.
///
/// 'id<P>' is an ObjCObjectPointerType whose pointee is an ObjCObjectType
/// with base BuiltinType::ObjCIdType and protocol list [P].  Eventually
/// this should get its own sugar class to better represent the source.
class ObjCObjectType : public Type,
                       public ObjCProtocolQualifiers<ObjCObjectType> {};

/// A class providing a concrete implementation
/// of ObjCObjectType, so as to not increase the footprint of
/// ObjCInterfaceType.  Code outside of ASTContext and the core type
/// system should not reference this type.
class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode {};

inline QualType *ObjCObjectType::getTypeArgStorage() {}

inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() {}

inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() {}

/// Interfaces are the core concept in Objective-C for object oriented design.
/// They basically correspond to C++ classes.  There are two kinds of interface
/// types: normal interfaces like `NSString`, and qualified interfaces, which
/// are qualified with a protocol list like `NSString<NSCopyable, NSAmazing>`.
///
/// ObjCInterfaceType guarantees the following properties when considered
/// as a subtype of its superclass, ObjCObjectType:
///   - There are no protocol qualifiers.  To reinforce this, code which
///     tries to invoke the protocol methods via an ObjCInterfaceType will
///     fail to compile.
///   - It is its own base type.  That is, if T is an ObjCInterfaceType*,
///     T->getBaseType() == QualType(T, 0).
class ObjCInterfaceType : public ObjCObjectType {};

inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const {}

/// Represents a pointer to an Objective C object.
///
/// These are constructed from pointer declarators when the pointee type is
/// an ObjCObjectType (or sugar for one).  In addition, the 'id' and 'Class'
/// types are typedefs for these, and the protocol-qualified types 'id<P>'
/// and 'Class<P>' are translated into these.
///
/// Pointers to pointers to Objective C objects are still PointerTypes;
/// only the first level of pointer gets it own type implementation.
class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {};

class AtomicType : public Type, public llvm::FoldingSetNode {};

/// PipeType - OpenCL20.
class PipeType : public Type, public llvm::FoldingSetNode {};

/// A fixed int type of a specified bitwidth.
class BitIntType final : public Type, public llvm::FoldingSetNode {};

class DependentBitIntType final : public Type, public llvm::FoldingSetNode {};

/// A qualifier set is used to build a set of qualifiers.
class QualifierCollector : public Qualifiers {};

/// A container of type source information.
///
/// A client can read the relevant info using TypeLoc wrappers, e.g:
/// @code
/// TypeLoc TL = TypeSourceInfo->getTypeLoc();
/// TL.getBeginLoc().print(OS, SrcMgr);
/// @endcode
class alignas(8) TypeSourceInfo {};

// Inline function definitions.

inline SplitQualType SplitQualType::getSingleStepDesugaredType() const {}

inline const Type *QualType::getTypePtr() const {}

inline const Type *QualType::getTypePtrOrNull() const {}

inline bool QualType::isReferenceable() const {}

inline SplitQualType QualType::split() const {}

inline Qualifiers QualType::getLocalQualifiers() const {}

inline Qualifiers QualType::getQualifiers() const {}

inline unsigned QualType::getCVRQualifiers() const {}

inline QualType QualType::getCanonicalType() const {}

inline bool QualType::isCanonical() const {}

inline bool QualType::isCanonicalAsParam() const {}

inline bool QualType::isConstQualified() const {}

inline bool QualType::isRestrictQualified() const {}


inline bool QualType::isVolatileQualified() const {}

inline bool QualType::hasQualifiers() const {}

inline QualType QualType::getUnqualifiedType() const {}

inline SplitQualType QualType::getSplitUnqualifiedType() const {}

inline void QualType::removeLocalConst() {}

inline void QualType::removeLocalRestrict() {}

inline void QualType::removeLocalVolatile() {}

/// Check if this type has any address space qualifier.
inline bool QualType::hasAddressSpace() const {}

/// Return the address space of this type.
inline LangAS QualType::getAddressSpace() const {}

/// Return the gc attribute of this type.
inline Qualifiers::GC QualType::getObjCGCAttr() const {}

inline bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion() const {}

inline bool QualType::hasNonTrivialToPrimitiveDestructCUnion() const {}

inline bool QualType::hasNonTrivialToPrimitiveCopyCUnion() const {}

inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) {}

inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) {}

/// Determine whether this type is more
/// qualified than the Other type. For example, "const volatile int"
/// is more qualified than "const int", "volatile int", and
/// "int". However, it is not more qualified than "const volatile
/// int".
inline bool QualType::isMoreQualifiedThan(QualType other) const {}

/// Determine whether this type is at last
/// as qualified as the Other type. For example, "const volatile
/// int" is at least as qualified as "const int", "volatile int",
/// "int", and "const volatile int".
inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const {}

/// If Type is a reference type (e.g., const
/// int&), returns the type that the reference refers to ("const
/// int"). Otherwise, returns the type itself. This routine is used
/// throughout Sema to implement C++ 5p6:
///
///   If an expression initially has the type "reference to T" (8.3.2,
///   8.5.3), the type is adjusted to "T" prior to any further
///   analysis, the expression designates the object or function
///   denoted by the reference, and the expression is an lvalue.
inline QualType QualType::getNonReferenceType() const {}

inline bool QualType::isCForbiddenLValueType() const {}

/// Tests whether the type is categorized as a fundamental type.
///
/// \returns True for types specified in C++0x [basic.fundamental].
inline bool Type::isFundamentalType() const {}

/// Tests whether the type is categorized as a compound type.
///
/// \returns True for types specified in C++0x [basic.compound].
inline bool Type::isCompoundType() const {}

inline bool Type::isFunctionType() const {}

inline bool Type::isPointerType() const {}

inline bool Type::isPointerOrReferenceType() const {}

inline bool Type::isAnyPointerType() const {}

inline bool Type::isSignableType() const {}

inline bool Type::isBlockPointerType() const {}

inline bool Type::isReferenceType() const {}

inline bool Type::isLValueReferenceType() const {}

inline bool Type::isRValueReferenceType() const {}

inline bool Type::isObjectPointerType() const {}

inline bool Type::isFunctionPointerType() const {}

inline bool Type::isFunctionReferenceType() const {}

inline bool Type::isMemberPointerType() const {}

inline bool Type::isMemberFunctionPointerType() const {}

inline bool Type::isMemberDataPointerType() const {}

inline bool Type::isArrayType() const {}

inline bool Type::isConstantArrayType() const {}

inline bool Type::isIncompleteArrayType() const {}

inline bool Type::isVariableArrayType() const {}

inline bool Type::isArrayParameterType() const {}

inline bool Type::isDependentSizedArrayType() const {}

inline bool Type::isBuiltinType() const {}

inline bool Type::isRecordType() const {}

inline bool Type::isEnumeralType() const {}

inline bool Type::isAnyComplexType() const {}

inline bool Type::isVectorType() const {}

inline bool Type::isExtVectorType() const {}

inline bool Type::isExtVectorBoolType() const {}

inline bool Type::isSubscriptableVectorType() const {}

inline bool Type::isMatrixType() const {}

inline bool Type::isConstantMatrixType() const {}

inline bool Type::isDependentAddressSpaceType() const {}

inline bool Type::isObjCObjectPointerType() const {}

inline bool Type::isObjCObjectType() const {}

inline bool Type::isObjCObjectOrInterfaceType() const {}

inline bool Type::isAtomicType() const {}

inline bool Type::isUndeducedAutoType() const {}

inline bool Type::isObjCQualifiedIdType() const {}

inline bool Type::isObjCQualifiedClassType() const {}

inline bool Type::isObjCIdType() const {}

inline bool Type::isObjCClassType() const {}

inline bool Type::isObjCSelType() const {}

inline bool Type::isObjCBuiltinType() const {}

inline bool Type::isDecltypeType() const {}

#define IMAGE_TYPE
#include "clang/Basic/OpenCLImageTypes.def"

inline bool Type::isSamplerT() const {}

inline bool Type::isEventT() const {}

inline bool Type::isClkEventT() const {}

inline bool Type::isQueueT() const {}

inline bool Type::isReserveIDT() const {}

inline bool Type::isImageType() const {}

inline bool Type::isPipeType() const {}

inline bool Type::isBitIntType() const {}

#define EXT_OPAQUE_TYPE
#include "clang/Basic/OpenCLExtensionTypes.def"

inline bool Type::isOCLIntelSubgroupAVCType() const {}

inline bool Type::isOCLExtOpaqueType() const {}

inline bool Type::isOpenCLSpecificType() const {}

#define HLSL_INTANGIBLE_TYPE
#include "clang/Basic/HLSLIntangibleTypes.def"

inline bool Type::isHLSLSpecificType() const {}

inline bool Type::isHLSLIntangibleType() const {}

inline bool Type::isTemplateTypeParmType() const {}

inline bool Type::isSpecificBuiltinType(unsigned K) const {}

inline bool Type::isPlaceholderType() const {}

inline const BuiltinType *Type::getAsPlaceholderType() const {}

inline bool Type::isSpecificPlaceholderType(unsigned K) const {}

inline bool Type::isNonOverloadPlaceholderType() const {}

inline bool Type::isVoidType() const {}

inline bool Type::isHalfType() const {}

inline bool Type::isFloat16Type() const {}

inline bool Type::isFloat32Type() const {}

inline bool Type::isDoubleType() const {}

inline bool Type::isBFloat16Type() const {}

inline bool Type::isFloat128Type() const {}

inline bool Type::isIbm128Type() const {}

inline bool Type::isNullPtrType() const {}

bool IsEnumDeclComplete(EnumDecl *);
bool IsEnumDeclScoped(EnumDecl *);

inline bool Type::isIntegerType() const {}

inline bool Type::isFixedPointType() const {}

inline bool Type::isFixedPointOrIntegerType() const {}

inline bool Type::isConvertibleToFixedPointType() const {}

inline bool Type::isSaturatedFixedPointType() const {}

inline bool Type::isUnsaturatedFixedPointType() const {}

inline bool Type::isSignedFixedPointType() const {}

inline bool Type::isUnsignedFixedPointType() const {}

inline bool Type::isScalarType() const {}

inline bool Type::isIntegralOrEnumerationType() const {}

inline bool Type::isBooleanType() const {}

inline bool Type::isUndeducedType() const {}

/// Determines whether this is a type for which one can define
/// an overloaded operator.
inline bool Type::isOverloadableType() const {}

/// Determines whether this type is written as a typedef-name.
inline bool Type::isTypedefNameType() const {}

/// Determines whether this type can decay to a pointer type.
inline bool Type::canDecayToPointerType() const {}

inline bool Type::hasPointerRepresentation() const {}

inline bool Type::hasObjCPointerRepresentation() const {}

inline const Type *Type::getBaseElementTypeUnsafe() const {}

inline const Type *Type::getPointeeOrArrayElementType() const {}
/// Insertion operator for partial diagnostics. This allows sending adress
/// spaces into a diagnostic with <<.
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
                                             LangAS AS) {}

/// Insertion operator for partial diagnostics. This allows sending Qualifiers
/// into a diagnostic with <<.
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
                                             Qualifiers Q) {}

/// Insertion operator for partial diagnostics.  This allows sending QualType's
/// into a diagnostic with <<.
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
                                             QualType T) {}

// Helper class template that is used by Type::getAs to ensure that one does
// not try to look through a qualified type to get to an array type.
TypeIsArrayType;

// Member-template getAs<specific type>'.
template <typename T> const T *Type::getAs() const {}

template <typename T> const T *Type::getAsAdjusted() const {}

inline const ArrayType *Type::getAsArrayTypeUnsafe() const {}

template <typename T> const T *Type::castAs() const {}

inline const ArrayType *Type::castAsArrayTypeUnsafe() const {}

DecayedType::DecayedType(QualType OriginalType, QualType DecayedPtr,
                         QualType CanonicalPtr)
    :{}

QualType DecayedType::getPointeeType() const {}

// Get the decimal string representation of a fixed point type, represented
// as a scaled integer.
// TODO: At some point, we should change the arguments to instead just accept an
// APFixedPoint instead of APSInt and scale.
void FixedPointValueToString(SmallVectorImpl<char> &Str, llvm::APSInt Val,
                             unsigned Scale);

inline FunctionEffectsRef FunctionEffectsRef::get(QualType QT) {}

} // namespace clang

#endif // LLVM_CLANG_AST_TYPE_H