(root)/
gcc-13.2.0/
libcody/
internal.hh
// CODYlib		-*- mode:c++ -*-
// Copyright (C) 2020 Nathan Sidwell, nathan@acm.org
// License: Apache v2.0

#include "cody.hh"

#ifndef __has_builtin
#define __has_builtin(X) 0
#endif
#ifndef __has_include
#define __has_include(X) 0
#endif

// C++
#if __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE)
#define CODY_LOC_BUILTIN 1
#elif __has_include (<source_location>)
#include <source_location>
#ifdef __cpp_lib_source_location
#define CODY_LOC_SOURCE 1
#endif
#endif

// C
#include <cstdio>

namespace Cody {

// Location is needed regardless of checking, to make the fatal
// handler simpler
class Location
{
protected:
  char const *file;
  unsigned line;

public:
  constexpr Location (char const *file_
#if CODY_LOC_BUILTIN
		      = __builtin_FILE ()
#elif !CODY_LOC_SOURCE
		      = nullptr
#endif
		      , unsigned line_
#if CODY_LOC_BUILTIN
		      = __builtin_LINE ()
#elif !CODY_LOC_SOURCE
		      = 0
#endif
		      )
    :file (file_), line (line_)
  {
  }

#if !CODY_LOC_BUILTIN && CODY_LOC_SOURCE
  using source_location = std::source_location;

  constexpr Location (source_location loc = source_location::current ())
    : Location (loc.file (), loc.line ())
  {
  }
#endif

public:
  constexpr char const *File () const
  {
    return file;
  }
  constexpr unsigned Line () const
  {
    return line;
  }
};

void HCF [[noreturn]]
(
 char const *msg
#if NMS_CHECKING
 , Location const = Location ()
#if !CODY_LOC_BUILTIN && !CODY_LOC_SOURCE
#define HCF(M) HCF ((M), Cody::Location (__FILE__, __LINE__))
#endif
#endif
 ) noexcept;

#if NMS_CHECKING
void AssertFailed [[noreturn]] (Location loc = Location ()) noexcept;
void Unreachable [[noreturn]] (Location loc = Location ()) noexcept;
#if !CODY_LOC_BUILTIN && !CODY_LOC_SOURCE
#define AssertFailed() AssertFailed (Cody::Location (__FILE__, __LINE__))
#define Unreachable() Unreachable (Cody::Location (__FILE__, __LINE__))
#endif

// Do we have __VA_OPT__, alas no specific feature macro for it :(
// From stack overflow
// https://stackoverflow.com/questions/48045470/portably-detect-va-opt-support
// Relies on having variadic macros, but they're a C++11 thing, so
// we're good
#define HAVE_ARG_3(a,b,c,...) c
#define HAVE_VA_OPT_(...) HAVE_ARG_3(__VA_OPT__(,),true,false,)
#define HAVE_VA_OPT HAVE_VA_OPT_(?)

// Oh, for lazily evaluated function parameters
#if HAVE_VA_OPT
// Assert is variadic, so you can write Assert (TPL<A,B>(C)) without
// extraneous parens.  I don't think we need that though.
#define Assert(EXPR, ...)						\
  (__builtin_expect (bool (EXPR __VA_OPT__ (, __VA_ARGS__)), true)	\
   ? (void)0 : AssertFailed ())
#else
// If you don't have the GNU ,##__VA_ARGS__ pasting extension, we'll
// need another fallback
#define Assert(EXPR, ...)						\
  (__builtin_expect (bool (EXPR, ##__VA_ARGS__), true)			\
   ? (void)0 : AssertFailed ())
#endif
#else
// Not asserting, use EXPR in an unevaluated context
#if  HAVE_VA_OPT
#define Assert(EXPR, ...)					\
  ((void)sizeof (bool (EXPR __VA_OPT__ (, __VA_ARGS__))), (void)0)
#else
#define Assert(EXPR, ...)					\
  ((void)sizeof (bool (EXPR, ##__VA_ARGS__)), (void)0)
#endif

inline void Unreachable () noexcept
{
  __builtin_unreachable ();
}
#endif

}