#pragma once #include #include #include namespace codeql { class UntypedTrapLabel { uint64_t id_; friend class std::hash; template friend class TrapLabel; static constexpr uint64_t undefined = 0xffffffffffffffff; protected: UntypedTrapLabel() : id_{undefined} {} UntypedTrapLabel(uint64_t id) : id_{id} {} public: friend std::ostream& operator<<(std::ostream& out, UntypedTrapLabel l) { // TODO: this is a temporary fix to catch us from outputting undefined labels to trap // this should be moved to a validity check, probably aided by code generation and carried out // by `SwiftDispatcher` assert(l.id_ != undefined && "outputting an undefined label!"); out << '#' << std::hex << l.id_ << std::dec; return out; } friend bool operator==(UntypedTrapLabel lhs, UntypedTrapLabel rhs) { return lhs.id_ == rhs.id_; } }; template class TrapLabel : public UntypedTrapLabel { template friend class TrapLabel; using UntypedTrapLabel::UntypedTrapLabel; public: using Tag = TagParam; TrapLabel() = default; // The caller is responsible for ensuring ID uniqueness. static TrapLabel unsafeCreateFromExplicitId(uint64_t id) { return {id}; } static TrapLabel unsafeCreateFromUntyped(UntypedTrapLabel label) { return {label.id_}; } template TrapLabel(const TrapLabel& other) : UntypedTrapLabel(other) { static_assert(std::is_base_of_v, "wrong label assignment!"); } }; inline auto trapQuoted(const std::string& s) { return std::quoted(s, '"', '"'); } template struct Binding { TrapLabel id; }; } // namespace codeql namespace std { template <> struct hash { size_t operator()(const codeql::UntypedTrapLabel& l) const noexcept { return std::hash{}(l.id_); } }; } // namespace std