91 lines · c
1//===-- Definition of a libc internal assert macro --------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_SRC___SUPPORT_LIBC_ASSERT_H10#define LLVM_LIBC_SRC___SUPPORT_LIBC_ASSERT_H11 12#if defined(LIBC_COPT_USE_C_ASSERT) || !defined(LIBC_FULL_BUILD)13 14// The build is configured to just use the public <assert.h> API15// for libc's internal assertions.16 17#ifndef LIBC_ASSERT18#include <assert.h>19 20#define LIBC_ASSERT(COND) assert(COND)21#endif // LIBC_ASSERT22 23#else // Not LIBC_COPT_USE_C_ASSERT24 25#include "src/__support/OSUtil/exit.h"26#include "src/__support/OSUtil/io.h"27#include "src/__support/integer_to_string.h"28#include "src/__support/macros/attributes.h" // For LIBC_INLINE29#include "src/__support/macros/config.h"30#include "src/__support/macros/optimization.h" // For LIBC_UNLIKELY31 32namespace LIBC_NAMESPACE_DECL {33 34// This is intended to be removed in a future patch to use a similar design to35// below, but it's necessary for the external assert.36LIBC_INLINE void report_assertion_failure(const char *assertion,37 const char *filename, unsigned line,38 const char *funcname) {39 const IntegerToString<unsigned> line_buffer(line);40 write_to_stderr(filename);41 write_to_stderr(":");42 write_to_stderr(line_buffer.view());43 write_to_stderr(": Assertion failed: '");44 write_to_stderr(assertion);45 write_to_stderr("' in function: '");46 write_to_stderr(funcname);47 write_to_stderr("'\n");48}49 50} // namespace LIBC_NAMESPACE_DECL51 52#ifdef LIBC_ASSERT53#error "Unexpected: LIBC_ASSERT macro already defined"54#endif55 56// The public "assert" macro calls abort on failure. Should it be same here?57// The libc internal assert can fire from anywhere inside the libc. So, to58// avoid potential chicken-and-egg problems, it is simple to do an exit59// on assertion failure instead of calling abort. We also don't want to use60// __builtin_trap as it could potentially be implemented using illegal61// instructions which can be very misleading when debugging.62#ifdef NDEBUG63#define LIBC_ASSERT(COND) \64 do { \65 } while (false)66#else67 68// Convert __LINE__ to a string using macros. The indirection is necessary69// because otherwise it will turn "__LINE__" into a string, not its value. The70// value is evaluated in the indirection step.71#define __LIBC_MACRO_TO_STR(x) #x72#define __LIBC_MACRO_TO_STR_INDIR(y) __LIBC_MACRO_TO_STR(y)73#define __LIBC_LINE_STR__ __LIBC_MACRO_TO_STR_INDIR(__LINE__)74 75#define LIBC_ASSERT(COND) \76 do { \77 if (LIBC_UNLIKELY(!(COND))) { \78 LIBC_NAMESPACE::write_to_stderr(__FILE__ ":" __LIBC_LINE_STR__ \79 ": Assertion failed: '" #COND \80 "' in function: '"); \81 LIBC_NAMESPACE::write_to_stderr(__PRETTY_FUNCTION__); \82 LIBC_NAMESPACE::write_to_stderr("'\n"); \83 LIBC_NAMESPACE::internal::exit(0xFF); \84 } \85 } while (false)86#endif // NDEBUG87 88#endif // LIBC_COPT_USE_C_ASSERT89 90#endif // LLVM_LIBC_SRC___SUPPORT_LIBC_ASSERT_H91