From 5b49a04ddc57d157c1a2050aed70ea65aa098970 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Thu, 4 Jan 2024 09:08:55 -0800 Subject: [PATCH 1/4] New assertions support This adds three new assertion macros: * `ASSERT` - always compiled in, always checked * `CONDITIONAL_ASSERT` - always compiled in, checked whenever the `-compiler-assertions` flag is provided * `DEBUG_ASSERT` - only compiled into debug builds, always checked when compiled in (functionally the same as Standard C `assert`) The new `-compiler-assertions` flag is recognized by both `swift-frontend` and `swiftc`. The goal is to eventually replace every use of `assert` in the compiler with one of the above: * Most assertions will use `ASSERT` (most assertions should always be present and checked, even in release builds) * Expensive assertions can use `CONDITIONAL_ASSERT` to be suppressed by default * A few very expensive and/or brittle assertions can use `DEBUG_ASSERT` to be compiled out of release builds This should: * Improve quality by catching errors earlier, * Accelerate compiler triage and debugging by providing more accurate crash dumps by default, and * Allow compiler engineers and end users alike to add `-compiler-assertions` to get more accurate failure diagnostics with any compiler --- include/swift/Basic/Assertions.h | 174 ++++++++++++++++++++++++++++ include/swift/Basic/Compiler.h | 25 ---- include/swift/Option/Options.td | 6 + lib/Basic/Assertions.cpp | 55 +++++++++ lib/Basic/CMakeLists.txt | 1 + lib/Driver/Driver.cpp | 5 + lib/Driver/ToolChains.cpp | 1 + lib/Frontend/CompilerInvocation.cpp | 10 ++ 8 files changed, 252 insertions(+), 25 deletions(-) create mode 100644 include/swift/Basic/Assertions.h create mode 100644 lib/Basic/Assertions.cpp diff --git a/include/swift/Basic/Assertions.h b/include/swift/Basic/Assertions.h new file mode 100644 index 0000000000000..1065ad414aff7 --- /dev/null +++ b/include/swift/Basic/Assertions.h @@ -0,0 +1,174 @@ +//===--- Assertions.h - Assertion macros ----===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file provides three alternatives to the C/C++ standard `assert()` macro +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_BASIC_ASSERTIONS_H +#define SWIFT_BASIC_ASSERTIONS_H + +#include + +// ================================ Mandatory Asserts ================================ + +// `ASSERT(expr)`: +// * is always compiled into the executable and +// * always checks the condition, regardless of build or runtime settings. +// This should be used for most assertions, which is why it +// deserves the short name. In particular, for simple checks +// (e.g., validating that something is non-null), this is just as +// fast as a disabled `CONDITIONAL_ASSERT`, so there's no point in +// using the conditional form. +// +// You can globally replace `assert` with `ASSERT` in a piece of code +// to have all your assertions enabled in all builds. If you do this, +// please do a little profiling first, just in case you have some checks +// that are more expensive than you think. You can switch those to +// `CONDITIONAL_ASSERT` or `DEBUG_ASSERT` as needed. + +#define ASSERT(expr) \ + do { \ + if (!(expr)) { \ + ASSERT_failure(#expr, __FILE__, __LINE__, __func__); \ + } \ + } while (0) + +// Function that reports the actual failure when it occurs. +[[noreturn]] void ASSERT_failure(const char *expr, const char *file, int line, const char *func); + +// ================================ Conditional Asserts ================================ + +// `CONDITIONAL_ASSERT(expr)`: +// * is always compiled into the executable, but +// * only checks the condition if a runtime flag is defined. +// That runtime flag is disabled by default in release builds +// but can be enabled with the command-line flag `-compiler-assertions` +// +// Use this for asserts that are comparatively expensive to check. +// +// You can globally change `assert` to `CONDITIONAL_ASSERT` to make all your +// assertions _optionally_ available in release builds. Anyone can then add +// `-compiler-assertions` to their build flags to get more information about a +// compiler problem. Before you check it in, do a little checking for +// assertions that might be checked huge numbers of times (e.g., invariants +// for inner loops or core utilities); those may need to become `DEBUG_ASSERT` +// or else refactored to be checked more selectively. +// +// Over time, plan to change most of the resulting `CONDITIONAL_ASSERT` into +// plain `ASSERT` to enable them by default. + +#define CONDITIONAL_ASSERT(expr) \ + do { \ + if (CONDITIONAL_ASSERT_enabled()) { \ + ASSERT(expr); \ + } \ + } while (0) + +// Use `CONDITIONAL_ASSERT_enabled()` to guard complex, expensive code that +// should only run when assertions are enabled. This is exactly the +// same check that's used to enable `CONDITIONAL_ASSERT()` at runtime. +// This is not often used -- if you are just setting a flag or updating +// a counter, it's likely cheaper just to do it than to test whether or not +// to do it. Only use this for relatively complex operations. +// +// if (CONDITIONAL_ASSERT_enabled()) { +// ... stuff ... +// } + +// Declare a callable function version of this runtime test. +int CONDITIONAL_ASSERT_enabled(); + +// Define a macro version of this test +extern int CONDITIONAL_ASSERT_Global_enable_flag; +#define CONDITIONAL_ASSERT_enabled() \ + (CONDITIONAL_ASSERT_Global_enable_flag != 0) + +// Profiling note: If you uncomment the line below to #undef the macro, then +// we'll always call the function, which lets you profile assertions by +// counting calls to this function. + +// #undef CONDITIONAL_ASSERT_enabled + +// ================================ Debug Asserts ================================ + +// `DEBUG_ASSERT(expr)`: +// * is only compiled into the executable in debug or "asserts enabled" builds, and +// * always performs the check (whenever it is compiled in). +// +// This basically makes it a synonym for the Standard C `assert(expr)`. +// +// You should mostly avoid this except for occasional experiments in your +// local tree. It can be useful in two situations: +// +// * Assertions that are known to mis-fire. +// Such assertions should not be `ASSERT` (since that will cause unnecessary +// broken compiles) and `CONDITIONAL_ASSERT` gets enabled a lot by people who +// are not compiler experts. So `DEBUG_ASSERT` is appropriate there until the +// check can be fixed so it doesn't mis-fire. +// +// * Inner loops that can run billions of times. +// For these, even the cost of testing whether `CONDITIONAL_ASSERT` is enabled +// can be prohibitive. Use `DEBUG_ASSERT`, but also look for ways to refactor +// so you can verify correctness without having an assertion in an inner loop. +// +// P.S. Please do not bulk replace `assert` with `DEBUG_ASSERT`. The whole +// point of this package is to move us toward having assertions always compiled +// in and always enabled. +#ifdef NDEBUG + #define DEBUG_ASSERT(expr) do { } while (0) + #undef DEBUG_ASSERT_enabled +#else + #define DEBUG_ASSERT(expr) ASSERT(expr) + #define DEBUG_ASSERT_enabled 1 +#endif + +// Code that's only needed within `DEBUG_ASSERT` can be guarded as follows: +// +// #ifndef NDEBUG +// ... code that's only needed for DEBUG_ASSERT ... +// #endif +// +// or with the equivalent +// +// #ifdef DEBUG_ASSERT_enabled +// ... code that's only needed for DEBUG_ASSERT ... +// #endif +// +// For example, you may need this for variables or functions that +// are only used within DEBUG_ASSERT statements. + +// A common case is to declare a variable or perform a simple +// expression. These can be used to avoid some boilerplate: +// +// void doThings() { +// DEBUG_ASSERT_DECL(std::vector thingsToVerify;); +// while (!done) { +// // ... do each thing ... +// DEBUG_ASSERT_EXPR(thingsToVerify.append(item)); +// } +// DEBUG_ASSERT(verifyAllThe(thingsToVerify)); +// } + +#ifdef DEBUG_ASSERT_enabled + #define DEBUG_ASSERT_DECL(...) __VA_ARGS__ + #define DEBUG_ASSERT_EXPR(...) do { __VA_ARGS__; } while (false) +#else + #define DEBUG_ASSERT_DECL(...) + #define DEBUG_ASSERT_EXPR(...) do { } while (false) +#endif + +// Older version of the same idea: +#define SWIFT_ASSERT_ONLY_DECL DEBUG_ASSERT_DECL +#define SWIFT_ASSERT_ONLY DEBUG_ASSERT_EXPR + +#endif // SWIFT_BASIC_ASSERTIONS_H diff --git a/include/swift/Basic/Compiler.h b/include/swift/Basic/Compiler.h index 72ae92448fcd1..2a93441bb7a7e 100644 --- a/include/swift/Basic/Compiler.h +++ b/include/swift/Basic/Compiler.h @@ -117,31 +117,6 @@ #define SWIFT_CRASH_BUG_REPORT_MESSAGE \ "Please " SWIFT_BUG_REPORT_MESSAGE_BASE " and include the crash backtrace." -// Conditionally exclude declarations or statements that are only needed for -// assertions from release builds (NDEBUG) without cluttering the surrounding -// code by #ifdefs. -// -// struct DoThings { -// SWIFT_ASSERT_ONLY_DECL(unsigned verifyCount = 0); -// DoThings() { -// SWIFT_ASSERT_ONLY(verifyCount = getNumberOfThingsToDo()); -// } -// void doThings() { -// do { -// // ... do each thing -// SWIFT_ASSERT_ONLY(--verifyCount); -// } while (!done()); -// assert(verifyCount == 0 && "did not do everything"); -// } -// }; -#ifdef NDEBUG -#define SWIFT_ASSERT_ONLY_DECL(...) -#define SWIFT_ASSERT_ONLY(...) do { } while (false) -#else -#define SWIFT_ASSERT_ONLY_DECL(...) __VA_ARGS__ -#define SWIFT_ASSERT_ONLY(...) do { __VA_ARGS__; } while (false) -#endif - #if defined(__LP64__) || defined(_WIN64) #define SWIFT_POINTER_IS_8_BYTES 1 #define SWIFT_POINTER_IS_4_BYTES 0 diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 3030d86051c7a..fcc2007192ff3 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -193,6 +193,12 @@ def no_strict_implicit_module_context : Flags<[FrontendOption, HelpHidden]>, HelpText<"Disable the strict forwarding of compilation context to downstream implicit module dependencies">; +def compiler_assertions : + Flag<["-"], "compiler-assertions">, + Group, + Flags<[FrontendOption, DoesNotAffectIncrementalBuild, CacheInvariant]>, + HelpText<"Enable internal self-checks while compiling">; + def validate_clang_modules_once : Flag<["-"], "validate-clang-modules-once">, Flags<[FrontendOption]>, diff --git a/lib/Basic/Assertions.cpp b/lib/Basic/Assertions.cpp new file mode 100644 index 0000000000000..cfcec4f04a8d5 --- /dev/null +++ b/lib/Basic/Assertions.cpp @@ -0,0 +1,55 @@ +//===--- Assertions.cpp - Swift Version Number -------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 - 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines custom assertion support functions +// +//===----------------------------------------------------------------------===// + +#include "swift/Basic/Assertions.h" +#undef NDEBUG +#include +#include + +int CONDITIONAL_ASSERT_Global_enable_flag = +#ifdef NDEBUG + 0; // Default to `off` in release builds +#else + 0; // TODO: Default to `on` in debug builds +#endif + +[[noreturn]] void ASSERT_failure(const char *expr, const char *file, int line, const char *func) { + // Only print the last component of `file` + const char *f = file; + for (const char *p = file; *p != '\0'; p++) { + if ((p[0] == '/' || p[0] == '\\') + && p[1] != '/' && p[1] != '\\' && p[1] != '\0') { + f = p + 1; + } + } + // Format here matches that used by `assert` on macOS: + std::cerr + << "Assertion failed: " + << "(" << expr << "), " + << "function " << func << ", " + << "file " << f << ", " + << "line " << line << "." + << std::endl; + abort(); +} + +// This has to be callable in the same way as the macro version, +// so we can't put it inside a namespace. +#undef CONDITIONAL_ASSERT_enabled +int CONDITIONAL_ASSERT_enabled() { + return (CONDITIONAL_ASSERT_Global_enable_flag != 0); +} + diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index fb3d66258847b..32da9a1a860ac 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -42,6 +42,7 @@ generate_revision_inc(llvm_revision_inc LLVM "${LLVM_MAIN_SRC_DIR}") generate_revision_inc(swift_revision_inc Swift "${SWIFT_SOURCE_DIR}") add_swift_host_library(swiftBasic STATIC + Assertions.cpp BasicBridging.cpp BasicSourceInfo.cpp Cache.cpp diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index db29750e66364..3a4f42e06cb67 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -20,6 +20,7 @@ #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsDriver.h" #include "swift/AST/DiagnosticsFrontend.h" +#include "swift/Basic/Assertions.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/LangOptions.h" #include "swift/Basic/OutputFileMap.h" @@ -1942,6 +1943,10 @@ bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) { return false; } + if (Args.hasArg(options::OPT_compiler_assertions)) { + CONDITIONAL_ASSERT_Global_enable_flag = 1; + } + if (Args.hasArg(options::OPT_version)) { // Follow gcc/clang behavior and use stdout for --version and stderr for -v. printVersion(TC, llvm::outs()); diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index a945f376fa32d..49dfb4707f8c9 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -343,6 +343,7 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_enable_experimental_cxx_interop); inputArgs.AddLastArg(arguments, options::OPT_cxx_interoperability_mode); inputArgs.AddLastArg(arguments, options::OPT_enable_builtin_module); + inputArgs.AddLastArg(arguments, options::OPT_compiler_assertions); // Pass on any build config options inputArgs.AddAllArgs(arguments, options::OPT_D); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 083a81cc178bc..a2b0f80d7a293 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -15,6 +15,7 @@ #include "ArgsToFrontendOptionsConverter.h" #include "swift/AST/DiagnosticsFrontend.h" +#include "swift/Basic/Assertions.h" #include "swift/Basic/Feature.h" #include "swift/Basic/Platform.h" #include "swift/Option/Options.h" @@ -328,6 +329,13 @@ bool CompilerInvocation::setModuleAliasMap(std::vector args, return ModuleAliasesConverter::computeModuleAliases(args, FrontendOpts, diags); } +static void ParseAssertionArgs(ArgList &args) { + using namespace options; + if (args.hasArg(OPT_compiler_assertions)) { + CONDITIONAL_ASSERT_Global_enable_flag = 1; + } +} + static bool ParseFrontendArgs( FrontendOptions &opts, ArgList &args, DiagnosticEngine &diags, SmallVectorImpl> *buffers) { @@ -3392,6 +3400,8 @@ bool CompilerInvocation::parseArgs( return true; } + ParseAssertionArgs(ParsedArgs); + if (ParseLangArgs(LangOpts, ParsedArgs, Diags, FrontendOpts)) { return true; } From f09fb7dfa462fb5746f55439d469bd78c9363989 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Thu, 16 May 2024 12:50:23 -0700 Subject: [PATCH 2/4] Update a couple of files to pull assertion helpers from the new header --- include/swift/SIL/FieldSensitivePrunedLiveness.h | 1 + include/swift/SILOptimizer/Analysis/ClosureScope.h | 1 + .../swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h | 1 + lib/SILOptimizer/Mandatory/AddressLowering.h | 1 + lib/SILOptimizer/Utils/OwnershipOptUtils.cpp | 1 + 5 files changed, 5 insertions(+) diff --git a/include/swift/SIL/FieldSensitivePrunedLiveness.h b/include/swift/SIL/FieldSensitivePrunedLiveness.h index ddf7fbdc95f70..7ce4f26715c2e 100644 --- a/include/swift/SIL/FieldSensitivePrunedLiveness.h +++ b/include/swift/SIL/FieldSensitivePrunedLiveness.h @@ -21,6 +21,7 @@ #define SWIFT_SIL_FIELDSENSITIVEPRUNTEDLIVENESS_H #include "swift/AST/TypeExpansionContext.h" +#include "swift/Basic/Assertions.h" #include "swift/Basic/Debug.h" #include "swift/Basic/FrozenMultiMap.h" #include "swift/Basic/STLExtras.h" diff --git a/include/swift/SILOptimizer/Analysis/ClosureScope.h b/include/swift/SILOptimizer/Analysis/ClosureScope.h index 31ca420676899..45131f01d42f2 100644 --- a/include/swift/SILOptimizer/Analysis/ClosureScope.h +++ b/include/swift/SILOptimizer/Analysis/ClosureScope.h @@ -50,6 +50,7 @@ #ifndef SWIFT_SILOPTIMIZER_ANALYSIS_CLOSURESCOPE_H #define SWIFT_SILOPTIMIZER_ANALYSIS_CLOSURESCOPE_H +#include "swift/Basic/Assertions.h" #include "swift/Basic/BlotSetVector.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILModule.h" diff --git a/include/swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h b/include/swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h index 994a17924145e..b0b2a83128673 100644 --- a/include/swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h @@ -28,6 +28,7 @@ #ifndef SWIFT_SILOPTIMIZER_ANALYSIS_NONLOCALACCESSBLOCKS_H #define SWIFT_SILOPTIMIZER_ANALYSIS_NONLOCALACCESSBLOCKS_H +#include "swift/Basic/Assertions.h" #include "swift/Basic/Compiler.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "llvm/ADT/SmallPtrSet.h" diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.h b/lib/SILOptimizer/Mandatory/AddressLowering.h index 7d383e6e6b874..332207b55b3cd 100644 --- a/lib/SILOptimizer/Mandatory/AddressLowering.h +++ b/lib/SILOptimizer/Mandatory/AddressLowering.h @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "swift/Basic/Assertions.h" #include "swift/Basic/LLVM.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" diff --git a/lib/SILOptimizer/Utils/OwnershipOptUtils.cpp b/lib/SILOptimizer/Utils/OwnershipOptUtils.cpp index f68ef9522e8e4..66e89fef43208 100644 --- a/lib/SILOptimizer/Utils/OwnershipOptUtils.cpp +++ b/lib/SILOptimizer/Utils/OwnershipOptUtils.cpp @@ -18,6 +18,7 @@ #include "swift/SILOptimizer/Utils/OwnershipOptUtils.h" +#include "swift/Basic/Assertions.h" #include "swift/Basic/Defer.h" #include "swift/SIL/BasicBlockUtils.h" #include "swift/SIL/InstructionUtils.h" From 37e5f30d0bdd6b472c8a82aea5d78263c6fc97b9 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Thu, 16 May 2024 15:04:49 -0700 Subject: [PATCH 3/4] Add some basic assertion handling control options --- include/swift/Basic/Assertions.h | 9 ++++++- lib/Basic/Assertions.cpp | 40 +++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/include/swift/Basic/Assertions.h b/include/swift/Basic/Assertions.h index 1065ad414aff7..c8705ccd65d74 100644 --- a/include/swift/Basic/Assertions.h +++ b/include/swift/Basic/Assertions.h @@ -44,7 +44,7 @@ } while (0) // Function that reports the actual failure when it occurs. -[[noreturn]] void ASSERT_failure(const char *expr, const char *file, int line, const char *func); +void ASSERT_failure(const char *expr, const char *file, int line, const char *func); // ================================ Conditional Asserts ================================ @@ -171,4 +171,11 @@ extern int CONDITIONAL_ASSERT_Global_enable_flag; #define SWIFT_ASSERT_ONLY_DECL DEBUG_ASSERT_DECL #define SWIFT_ASSERT_ONLY DEBUG_ASSERT_EXPR +// ================================ Utility and Helper Functions ================================ + +// Utility function to print out help information for +// various command-line options that affect the assertion +// behavior. +void ASSERT_help(); + #endif // SWIFT_BASIC_ASSERTIONS_H diff --git a/lib/Basic/Assertions.cpp b/lib/Basic/Assertions.cpp index cfcec4f04a8d5..a26e896fadfd5 100644 --- a/lib/Basic/Assertions.cpp +++ b/lib/Basic/Assertions.cpp @@ -14,11 +14,20 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/CommandLine.h" #include "swift/Basic/Assertions.h" #undef NDEBUG #include #include +llvm::cl::opt AssertContinue( + "assert-continue", llvm::cl::init(false), + llvm::cl::desc("Do not stop on an assertion failure")); + +llvm::cl::opt AssertHelp( + "assert-help", llvm::cl::init(false), + llvm::cl::desc("Print help for managing assertions")); + int CONDITIONAL_ASSERT_Global_enable_flag = #ifdef NDEBUG 0; // Default to `off` in release builds @@ -26,7 +35,7 @@ int CONDITIONAL_ASSERT_Global_enable_flag = 0; // TODO: Default to `on` in debug builds #endif -[[noreturn]] void ASSERT_failure(const char *expr, const char *file, int line, const char *func) { +void ASSERT_failure(const char *expr, const char *file, int line, const char *func) { // Only print the last component of `file` const char *f = file; for (const char *p = file; *p != '\0'; p++) { @@ -35,6 +44,14 @@ int CONDITIONAL_ASSERT_Global_enable_flag = f = p + 1; } } + + if (AssertHelp) { + ASSERT_help(); + } else { + std::cerr << "Assertion help: -Xllvm -assert-help" << std::endl; + } + + // Format here matches that used by `assert` on macOS: std::cerr << "Assertion failed: " @@ -43,9 +60,30 @@ int CONDITIONAL_ASSERT_Global_enable_flag = << "file " << f << ", " << "line " << line << "." << std::endl; + + if (AssertContinue) { + std::cerr << "Continuing after failed assertion (-Xllvm -assert-continue)" << std::endl; + return; + } + abort(); } +void ASSERT_help() { + static int ASSERT_help_shown = 0; + if (ASSERT_help_shown) { + return; + } + ASSERT_help_shown = 1; + + std::cerr << std::endl; + std::cerr << "Control assertion behavior with one or more of the following options:" << std::endl; + std::cerr << std::endl; + std::cerr << " -Xllvm -assert-continue" << std::endl; + std::cerr << " Continue after any failed assertion" << std::endl; + std::cerr << std::endl; +} + // This has to be callable in the same way as the macro version, // so we can't put it inside a namespace. #undef CONDITIONAL_ASSERT_enabled From bb8c96c2b97ce4c533210741ede4593f5ed49ca0 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Fri, 17 May 2024 09:30:03 -0700 Subject: [PATCH 4/4] Optimize for assertion success and assertions disabled --- include/swift/Basic/Assertions.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/swift/Basic/Assertions.h b/include/swift/Basic/Assertions.h index c8705ccd65d74..4156d6af1a7c2 100644 --- a/include/swift/Basic/Assertions.h +++ b/include/swift/Basic/Assertions.h @@ -19,6 +19,13 @@ #include +// Only for use in this header +#if __has_builtin(__builtin_expect) +#define ASSERT_UNLIKELY(expression) (__builtin_expect(!!(expression), 0)) +#else +#define ASSERT_UNLIKELY(expression) ((expression)) +#endif + // ================================ Mandatory Asserts ================================ // `ASSERT(expr)`: @@ -38,7 +45,7 @@ #define ASSERT(expr) \ do { \ - if (!(expr)) { \ + if (ASSERT_UNLIKELY(!expr)) { \ ASSERT_failure(#expr, __FILE__, __LINE__, __func__); \ } \ } while (0) @@ -69,7 +76,7 @@ void ASSERT_failure(const char *expr, const char *file, int line, const char *fu #define CONDITIONAL_ASSERT(expr) \ do { \ - if (CONDITIONAL_ASSERT_enabled()) { \ + if (ASSERT_UNLIKELY(CONDITIONAL_ASSERT_enabled())) { \ ASSERT(expr); \ } \ } while (0)