text: //===- GlobalDecl.h - Global declaration holder -----------------*- 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
  //
  //===----------------------------------------------------------------------===//
  //
  // A GlobalDecl can hold either a regular variable/function or a C++ ctor/dtor
  // together with its type.
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef LLVM_CLANG_AST_GLOBALDECL_H
  #define LLVM_CLANG_AST_GLOBALDECL_H
  
  #include "clang/AST/DeclCXX.h"
  #include "clang/AST/DeclObjC.h"
  #include "clang/AST/DeclOpenMP.h"
  #include "clang/Basic/ABI.h"
  #include "clang/Basic/LLVM.h"
  #include "llvm/ADT/DenseMapInfo.h"
  #include "llvm/ADT/PointerIntPair.h"
  #include "llvm/Support/Casting.h"
  #include "llvm/Support/type_traits.h"
  #include <cassert>
  
  namespace clang {
  
  enum class DynamicInitKind : unsigned {
    NoStub = 0,
    Initializer,
    AtExit,
  };
  
  /// GlobalDecl - represents a global declaration. This can either be a
  /// CXXConstructorDecl and the constructor type (Base, Complete).
  /// a CXXDestructorDecl and the destructor type (Base, Complete) or
  /// a VarDecl, a FunctionDecl or a BlockDecl.
  class GlobalDecl {
    llvm::PointerIntPair<const Decl *, 2> Value;
    unsigned MultiVersionIndex = 0;
  
    void Init(const Decl *D) {
      assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!");
      assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!");
  
      Value.setPointer(D);
    }
  
  public:
    GlobalDecl() = default;
    GlobalDecl(const VarDecl *D) { Init(D);}
    GlobalDecl(const FunctionDecl *D, unsigned MVIndex = 0)
        : MultiVersionIndex(MVIndex) {
      Init(D);
    }
    GlobalDecl(const CXXMethodDecl *D, bool isMemberPointerThunk) : Value(D, isMemberPointerThunk){ }
    GlobalDecl(const BlockDecl *D) { Init(D); }
    GlobalDecl(const CapturedDecl *D) { Init(D); }
    GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
    GlobalDecl(const OMPDeclareReductionDecl *D) { Init(D); }
    GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) : Value(D, Type) {}
    GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) : Value(D, Type) {}
    GlobalDecl(const VarDecl *D, DynamicInitKind StubKind)
        : Value(D, unsigned(StubKind)) {}
  
    GlobalDecl getCanonicalDecl() const {
      GlobalDecl CanonGD;
      CanonGD.Value.setPointer(Value.getPointer()->getCanonicalDecl());
      CanonGD.Value.setInt(Value.getInt());
      CanonGD.MultiVersionIndex = MultiVersionIndex;
  
      return CanonGD;
    }
  
    const Decl *getDecl() const { return Value.getPointer(); }
  
    CXXCtorType getCtorType() const {
      assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!");
      return static_cast<CXXCtorType>(Value.getInt());
    }
  
    CXXDtorType getDtorType() const {
      assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!");
      return static_cast<CXXDtorType>(Value.getInt());
    }
  
    DynamicInitKind getDynamicInitKind() const {
      assert(isa<VarDecl>(getDecl()) &&
             cast<VarDecl>(getDecl())->hasGlobalStorage() &&
             "Decl is not a global variable!");
      return static_cast<DynamicInitKind>(Value.getInt());
    }
  
    unsigned getMultiVersionIndex() const {
      assert(isa<FunctionDecl>(getDecl()) &&
             !isa<CXXConstructorDecl>(getDecl()) &&
             !isa<CXXDestructorDecl>(getDecl()) &&
             "Decl is not a plain FunctionDecl!");
      return MultiVersionIndex;
    }
  
    bool isMemberPointerThunk() const {
      assert(isa<CXXMethodDecl>(getDecl()) && "Decl is not a method!");
      return static_cast<bool>(Value.getInt());
    }
    
    friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) {
      return LHS.Value == RHS.Value &&
             LHS.MultiVersionIndex == RHS.MultiVersionIndex;
    }
  
    void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
  
    static GlobalDecl getFromOpaquePtr(void *P) {
      GlobalDecl GD;
      GD.Value.setFromOpaqueValue(P);
      return GD;
    }
  
    GlobalDecl getWithDecl(const Decl *D) {
      GlobalDecl Result(*this);
      Result.Value.setPointer(D);
      return Result;
    }
  
    GlobalDecl getWithCtorType(CXXCtorType Type) {
      assert(isa<CXXConstructorDecl>(getDecl()));
      GlobalDecl Result(*this);
      Result.Value.setInt(Type);
      return Result;
    }
  
    GlobalDecl getWithDtorType(CXXDtorType Type) {
      assert(isa<CXXDestructorDecl>(getDecl()));
      GlobalDecl Result(*this);
      Result.Value.setInt(Type);
      return Result;
    }
  
    GlobalDecl getWithMultiVersionIndex(unsigned Index) {
      assert(isa<FunctionDecl>(getDecl()) &&
             !isa<CXXConstructorDecl>(getDecl()) &&
             !isa<CXXDestructorDecl>(getDecl()) &&
             "Decl is not a plain FunctionDecl!");
      GlobalDecl Result(*this);
      Result.MultiVersionIndex = Index;
      return Result;
    }
  };
  
  } // namespace clang
  
  namespace llvm {
  
    template<> struct DenseMapInfo<clang::GlobalDecl> {
      static inline clang::GlobalDecl getEmptyKey() {
        return clang::GlobalDecl();
      }
  
      static inline clang::GlobalDecl getTombstoneKey() {
        return clang::GlobalDecl::
          getFromOpaquePtr(reinterpret_cast<void*>(-1));
      }
  
      static unsigned getHashValue(clang::GlobalDecl GD) {
        return DenseMapInfo<void*>::getHashValue(GD.getAsOpaquePtr());
      }
  
      static bool isEqual(clang::GlobalDecl LHS,
                          clang::GlobalDecl RHS) {
        return LHS == RHS;
      }
    };
  
  } // namespace llvm
  
  #endif // LLVM_CLANG_AST_GLOBALDECL_H
  