/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
/*
* (C) 2001 by Argonne National Laboratory.
* See COPYRIGHT in top-level directory.
*/
#if !defined(MPIASSERT_H_INCLUDED)
#define MPIASSERT_H_INCLUDED
#include "mpiu_type_defs.h"
/* modern versions of clang support lots of C11 features */
#if defined(__has_extension)
# if __has_extension(c_generic_selections)
# define HAVE_C11__GENERIC 1
# endif
# if __has_extension(c_static_assert)
# define HAVE_C11__STATIC_ASSERT 1
# endif
#endif
/* GCC 4.6 added support for _Static_assert:
* http://gcc.gnu.org/gcc-4.6/changes.html */
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && !defined __cplusplus
# define HAVE_C11__STATIC_ASSERT 1
#endif
/* prototypes for assertion implementation helpers */
int MPIR_Assert_fail(const char *cond, const char *file_name, int line_num);
int MPIR_Assert_fail_fmt(const char *cond, const char *file_name, int line_num, const char *fmt, ...);
/*
* MPIU_Assert()
*
* Similar to assert() except that it performs an MPID_Abort() when the
* assertion fails. Also, for Windows, it doesn't popup a
* mesage box on a remote machine.
*
* MPIU_AssertDecl may be used to include declarations only needed
* when MPIU_Assert is non-null (e.g., when assertions are enabled)
*/
#if (!defined(NDEBUG) && defined(HAVE_ERROR_CHECKING))
# define MPIU_AssertDecl(a_) a_
# define MPIU_AssertDeclValue(_a,_b) _a = _b
# define MPIU_Assert(a_) \
do { \
if (unlikely(!(a_))) { \
MPIR_Assert_fail(#a_, __FILE__, __LINE__); \
} \
} while (0)
#else
# define MPIU_Assert(a_)
/* Empty decls not allowed in C */
# define MPIU_AssertDecl(a_) a_
# define MPIU_AssertDeclValue(_a,_b) _a ATTRIBUTE((unused)) = _b
#endif
/*
* MPIU_Assertp()
*
* Similar to MPIU_Assert() except that these assertions persist regardless of
* NDEBUG or HAVE_ERROR_CHECKING. MPIU_Assertp() may
* be used for error checking in prototype code, although it should be
* converted real error checking and reporting once the
* prototype becomes part of the official and supported code base.
*/
#define MPIU_Assertp(a_) \
do { \
if (unlikely(!(a_))) { \
MPIR_Assert_fail(#a_, __FILE__, __LINE__); \
} \
} while (0)
/* Define the MPIU_Assert_fmt_msg macro. This macro takes two arguments. The
* first is the condition to assert. The second is a parenthesized list of
* arguments suitable for passing directly to printf that will yield a relevant
* error message. The macro will first evaluate the condition. If it evaluates
* to false the macro will take four steps:
*
* 1) It will emit an "Assertion failed..." message in the valgrind output with
* a backtrace, if valgrind client requests are available and the process is
* running under valgrind. It will also evaluate and print the supplied
* message.
* 2) It will emit an "Assertion failed..." message via MPL_internal_error_printf.
* The supplied error message will also be evaluated and printed.
* 3) It will similarly emit the assertion failure and caller supplied messages
* to the debug log, if enabled, via MPIU_DBG_MSG_FMT.
* 4) It will invoke MPID_Abort, just like the other MPIU_Assert* macros.
*
* If the compiler doesn't support (...)/__VA_ARGS__ in macros then the user
* message will not be evaluated or printed. If NDEBUG is defined or
* HAVE_ERROR_CHECKING is undefined, this macro will expand to nothing, just
* like MPIU_Assert.
*
* Example usage:
*
* MPIU_Assert_fmg_msg(foo > bar,("foo is larger than bar: foo=%d bar=%d",foo,bar));
*/
#if (!defined(NDEBUG) && defined(HAVE_ERROR_CHECKING))
# if defined(HAVE_MACRO_VA_ARGS)
/* newlines are added internally by the impl function, callers do not need to include them */
# define MPIU_Assert_fmt_msg(cond_,fmt_arg_parens_) \
do { \
if (unlikely(!(cond_))) { \
MPIR_Assert_fail_fmt(#cond_, __FILE__, __LINE__, \
MPIU_Assert_fmt_msg_expand_ fmt_arg_parens_); \
} \
} while (0)
/* helper to just expand the parens arg inline */
# define MPIU_Assert_fmt_msg_expand_(...) __VA_ARGS__
# else /* defined(HAVE_MACRO_VA_ARGS) */
# define MPIU_Assert_fmt_msg(cond_,fmt_arg_parens_) \
do { \
if (unlikely(!(cond_))) { \
MPIR_Assert_fail_fmt(#cond_, __FILE__, __LINE__, \
"%s", "macro __VA_ARGS__ not supported, unable to print user message"); \
} \
} while (0)
# endif
#else /* !defined(NDEBUG) && defined(HAVE_ERROR_CHECKING) */
# define MPIU_Assert_fmt_msg(cond_,fmt_arg_parens_)
#endif
#ifdef HAVE_C11__STATIC_ASSERT
# define MPIU_Static_assert(cond_,msg_) _Static_assert(cond_,msg_)
#endif
/* fallthrough to a run-time assertion */
#ifndef MPIU_Static_assert
# define MPIU_Static_assert(cond_,msg_) MPIU_Assert_fmt_msg((cond_), ("%s", (msg_)))
#endif
/* evaluates to TRUE if ((a_)*(b_)>(max_)), only detects overflow for positive
* a_ and _b. */
#define MPIU_Prod_overflows_max(a_, b_, max_) \
( (a_) > 0 && (b_) > 0 && ((a_) > ((max_) / (b_))) )
/* asserts that ((a_)*(b_)<=(max_)) holds in a way that is robust against
* undefined integer overflow behavior and is suitable for both signed and
* unsigned math (only suitable for positive values of (a_) and (b_)) */
#define MPIU_Assert_prod_pos_overflow_safe(a_, b_, max_) \
MPIU_Assert_fmt_msg(!MPIU_Prod_overflows_max((a_),(b_),(max_)), \
("overflow detected: (%llx * %llx) > %s", (a_), (b_), #max_)); \
/* -------------------------------------------------------------------------- */
/* static type checking macros */
/* implement using C11's "_Generic" functionality (optimal case) */
#ifdef HAVE_C11__GENERIC
# define MPIU_Assert_has_type(expr_,type_) \
MPIU_Static_assert(_Generic((expr_), type_: 1, default: 0), \
"expression '" #expr_ "' does not have type '" #type_ "'")
#endif
/* fallthrough to do nothing */
#ifndef MPIU_Assert_has_type
# define MPIU_Assert_has_type(expr_,type_) do {} while (0)
#endif
#endif /* !defined(MPIASSERT_H_INCLUDED) */