Summary: This patch adds a temporary `__assert_fail` and `assert` definition to make it available to internal llvm libc code. `__assert_fail` writes to fd 2 directly instead of `stderr`, using SYS_write. I have not put it in its own linux directory because this is temporary and it should be using stdio's api in the future. It does not currently print out the line number (although we could do that by stringifying `__LINE__` if reviewers wish).
Reviewers: sivachandra, gchatelet, PaulkaToast
Reviewed By: sivachandra
Subscribers: mgorny, MaskRay, tschuett, libc-commits
Differential Revision: https://reviews.llvm.org/D75420
}];
}
+def AssertMacro : MacroDef<"assert"> {
+ let Defn = [{
+ #undef assert
+
+ #ifdef NDEBUG
+ #define assert(e) (void)0
+ #else
+
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+ _Noreturn void __assert_fail(const char *, const char *, unsigned, const char *);
+
+ #define assert(e) \
+ ((e) ? (void)0 : __assert_fail(#e, __FILE__, __LINE__, __PRETTY_FUNCTION__))
+
+ #endif
+ }];
+}
+
+def StaticAssertMacro : MacroDef<"static_assert"> {
+ let Defn = [{
+ #ifndef __cplusplus
+ #undef static_assert
+ #define static_assert _Static_assert
+ #endif
+ }];
+}
+
def NullMacro : MacroDef<"NULL"> {
let Defn = [{
#define __need_NULL
}];
}
+def AssertAPI : PublicAPI<"assert.h"> {
+ let Macros = [
+ AssertMacro,
+ StaticAssertMacro,
+ ];
+}
+
def MathAPI : PublicAPI<"math.h"> {
let Functions = [
"acos",
)
add_gen_header(
+ assert_h
+ DEF_FILE assert.h.def
+ GEN_HDR assert.h
+ DEPENDS
+ llvm_libc_common_h
+)
+
+add_gen_header(
string_h
DEF_FILE string.h.def
GEN_HDR string.h
--- /dev/null
+//===---------------- C standard library header assert.h ------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <__llvm-libc-common.h>
+
+// This file may be usefully included multiple times to change assert()'s
+// definition based on NDEBUG.
+
+%%public_api()
add_entrypoint_library(
llvmlibc
DEPENDS
+ # assert.h entrypoints
+ __assert_fail
+
# errno.h entrypoints
__errno_location
PtrType IntPtr = PtrType<IntType>;
+ HeaderSpec Assert = HeaderSpec<
+ "assert.h",
+ [
+ Macro<"static_assert">,
+ Macro<"assert">,
+ ],
+ [], // Types
+ [], // Enumerations
+ []
+ >;
+
HeaderSpec String = HeaderSpec<
"string.h",
[
>;
let Headers = [
+ Assert,
Errno,
Math,
String,
+add_subdirectory(assert)
add_subdirectory(errno)
add_subdirectory(math)
add_subdirectory(signal)
--- /dev/null
+add_entrypoint_object(
+ __assert_fail
+ SRCS
+ __assert_fail.cpp
+ HDRS
+ assert.h
+ DEPENDS
+ abort
+ # These two dependencies are temporary and should be replaced by fprintf
+ # later.
+ sys_syscall_h
+ linux_syscall_h
+)
--- /dev/null
+//===----------------- Implementation of __assert_fail --------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/assert/assert.h"
+#include "src/stdlib/abort.h"
+
+// These includes are temporary.
+#include "config/linux/syscall.h" // For internal syscall function.
+#include "include/sys/syscall.h" // For syscall numbers.
+
+namespace __llvm_libc {
+
+// This is just a temporary solution to make assert available to internal
+// llvm libc code. In the future writeToStderr will not exist and __assert_fail
+// will call fprintf(stderr, ...).
+static void writeToStderr(const char *s) {
+ size_t length = 0;
+ for (const char *curr = s; *curr; ++curr, ++length);
+ __llvm_libc::syscall(SYS_write, 2, s, length);
+}
+
+void LLVM_LIBC_ENTRYPOINT(__assert_fail)(const char *assertion, const char *file,
+ unsigned line, const char *function) {
+ writeToStderr(file);
+ writeToStderr(": Assertion failed: '");
+ writeToStderr(assertion);
+ writeToStderr("' in function: '");
+ writeToStderr(function);
+ writeToStderr("'\n");
+ __llvm_libc::abort();
+}
+
+} // namespace __llvm_libc
--- /dev/null
+//===-------------------- Internal header for assert ----------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_ASSERT_ASSERT_H
+#define LLVM_LIBC_SRC_ASSERT_ASSERT_H
+
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+[[noreturn]] void __assert_fail(const char *assertion, const char *file, unsigned line,
+ const char *function);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_ASSERT_ASSERT_H
+
+#undef assert
+
+#ifdef NDEBUG
+#define assert(e) (void)0
+#else
+#define assert(e) \
+ ((e) ? (void)0 : \
+ __llvm_libc::__assert_fail(#e, __FILE__, __LINE__, __PRETTY_FUNCTION__))
+#endif
+add_subdirectory(assert)
add_subdirectory(errno)
add_subdirectory(signal)
add_subdirectory(stdlib)
--- /dev/null
+add_libc_testsuite(libc_assert_unittests)
+
+add_libc_unittest(
+ assert_test
+ SUITE
+ libc_assert_unittests
+ SRCS
+ assert_test.cpp
+ DEPENDS
+ __assert_fail
+ # These are necessary for now because dependencies are not properly added.
+ abort
+ raise
+ _Exit
+)
--- /dev/null
+//===---------------------- Unittests for assert --------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#undef NDEBUG
+#include "src/assert/assert.h"
+#include "utils/UnitTest/Test.h"
+
+extern "C" int close(int);
+
+TEST(Assert, Enabled) {
+ // -1 matches against any signal, which is necessary for now until
+ // __llvm_libc::abort() unblocks SIGABRT. Close standard error for the
+ // child process so we don't print the assertion failure message.
+ EXPECT_DEATH(
+ [] {
+ close(2);
+ assert(0);
+ },
+ -1);
+}
+
+#define NDEBUG
+#include "src/assert/assert.h"
+
+TEST(Assert, Disabled) {
+ EXPECT_EXITS([] { assert(0); }, 0);
+}