Skip to content
65 changes: 41 additions & 24 deletions include/swift/Basic/Assertions.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,22 @@
#ifndef SWIFT_BASIC_ASSERTIONS_H
#define SWIFT_BASIC_ASSERTIONS_H

#include "swift/Basic/LLVM.h"

// 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

// Visual Studio doesn't have __FILE_NAME__
#ifdef __FILE_NAME__
#define _FILENAME_FOR_ASSERT __FILE_NAME__
#else
#define _FILENAME_FOR_ASSERT __FILE__
#endif

// ================================ Mandatory Asserts ================================

// `ASSERT(expr)`:
Expand All @@ -41,27 +50,13 @@
// that are more expensive than you think. You can switch those to
// `CONDITIONAL_ASSERT` or `DEBUG_ASSERT` as needed.

// Visual Studio doesn't have __FILE_NAME__
#ifdef __FILE_NAME__

#define ASSERT(expr) \
do { \
if (ASSERT_UNLIKELY(!(expr))) { \
ASSERT_failure(#expr, __FILE_NAME__, __LINE__, __func__); \
} \
#define ASSERT(expr) \
do { \
if (ASSERT_UNLIKELY(!(expr))) { \
ASSERT_failure(#expr, _FILENAME_FOR_ASSERT, __LINE__, __func__); \
} \
} while (0)

#else

#define ASSERT(expr) \
do { \
if (ASSERT_UNLIKELY(!(expr))) { \
ASSERT_failure(#expr, __FILE__, __LINE__, __func__); \
} \
} while (0)

#endif

// Function that reports the actual failure when it occurs.
void ASSERT_failure(const char *expr, const char *file, int line, const char *func);

Expand Down Expand Up @@ -190,11 +185,33 @@ 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 ================================
// ================================ Abort ======================================

// Utility function to print out help information for
// various command-line options that affect the assertion
// behavior.
void ASSERT_help();
/// Implementation for \c ABORT, not to be used directly.
[[noreturn]]
void _ABORT(const char *file, int line, const char *func,
llvm::function_ref<void(llvm::raw_ostream &)> message);

/// Implementation for \c ABORT, not to be used directly.
[[noreturn]]
void _ABORT(const char *file, int line, const char *func,
llvm::StringRef message);

// Aborts the program, printing a given message to a PrettyStackTrace frame
// before exiting. This should be preferred over manually logging to stderr and
// `abort()`'ing since that won't be picked up by the crash reporter.
//
// There are two different forms of ABORT:
//
// ```
// ABORT("abort with string");
//
// ABORT([&](auto &out) {
// out << "abort with arbitrary stream";
// node.dump(out);
// });
// ```
//
#define ABORT(arg) _ABORT(_FILENAME_FOR_ASSERT, __LINE__, __func__, (arg))

#endif // SWIFT_BASIC_ASSERTIONS_H
11 changes: 0 additions & 11 deletions include/swift/Basic/PrettyStackTrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,6 @@ class PrettyStackTraceSwiftVersion : public llvm::PrettyStackTraceEntry {
void print(llvm::raw_ostream &OS) const override;
};

/// Aborts the program, printing a given message to a PrettyStackTrace frame
/// before exiting.
[[noreturn]]
void abortWithPrettyStackTraceMessage(
llvm::function_ref<void(llvm::raw_ostream &)> message);

/// Aborts the program, printing a given message to a PrettyStackTrace frame
/// before exiting.
[[noreturn]]
void abortWithPrettyStackTraceMessage(llvm::StringRef message);

} // end namespace swift

#endif // SWIFT_BASIC_PRETTYSTACKTRACE_H
11 changes: 6 additions & 5 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -557,11 +557,12 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
}

if (substConf.isInvalid()) {
llvm::errs() << "Invalid substituted conformance in SIL cloner:\n";
Functor.dump(llvm::errs());
llvm::errs() << "\noriginal conformance:\n";
conformance.dump(llvm::errs());
abort();
ABORT([&](auto &out) {
out << "Invalid substituted conformance in SIL cloner:\n";
Functor.dump(out);
out << "\noriginal conformance:\n";
conformance.dump(out);
});
}

if (asImpl().shouldSubstOpaqueArchetypes()) {
Expand Down
7 changes: 4 additions & 3 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5819,9 +5819,10 @@ ProtocolConformanceRef ProtocolConformanceRef::forAbstract(
break;

default:
llvm::errs() << "Abstract conformance with bad subject type:\n";
conformingType->dump(llvm::errs());
abort();
ABORT([&](auto &out) {
out << "Abstract conformance with bad subject type:\n";
conformingType->dump(out);
});
}

// Figure out which arena this should go in.
Expand Down
20 changes: 10 additions & 10 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1446,8 +1446,7 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
case TypeKind::BuiltinUnsafeValueBuffer:
return appendOperator("BB");
case TypeKind::BuiltinUnboundGeneric:
llvm::errs() << "Don't know how to mangle a BuiltinUnboundGenericType\n";
abort();
ABORT("Don't know how to mangle a BuiltinUnboundGenericType");
case TypeKind::Locatable: {
auto loc = cast<LocatableType>(tybase);
return appendType(loc->getSinglyDesugaredType(), sig, forDecl);
Expand Down Expand Up @@ -1756,9 +1755,10 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
case TypeKind::PackArchetype:
case TypeKind::ElementArchetype:
case TypeKind::ExistentialArchetype:
llvm::errs() << "Cannot mangle free-standing archetype: ";
tybase->dump(llvm::errs());
abort();
ABORT([&](auto &out) {
out << "Cannot mangle free-standing archetype: ";
tybase->dump(out);
});

case TypeKind::OpaqueTypeArchetype: {
auto opaqueType = cast<OpaqueTypeArchetypeType>(tybase);
Expand Down Expand Up @@ -4468,8 +4468,7 @@ static unsigned conformanceRequirementIndex(
++result;
}

llvm::errs() <<"Conformance access path step is missing from requirements";
abort();
ABORT("Conformance access path step is missing from requirements");
}

void ASTMangler::appendDependentProtocolConformance(
Expand Down Expand Up @@ -4573,9 +4572,10 @@ void ASTMangler::appendAnyProtocolConformance(
} else if (conformance.isPack()) {
appendPackProtocolConformance(conformance.getPack(), genericSig);
} else {
llvm::errs() << "Bad conformance in mangler: ";
conformance.dump(llvm::errs());
abort();
ABORT([&](auto &out) {
out << "Bad conformance in mangler: ";
conformance.dump(out);
});
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTScopePrinting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ void ASTScopeImpl::dumpOneScopeMapLocation(

void ASTScopeImpl::abortWithVerificationError(
llvm::function_ref<void(llvm::raw_ostream &)> messageFn) const {
abortWithPrettyStackTraceMessage([&](auto &out) {
ABORT([&](auto &out) {
out << "ASTScopeImpl verification error in source file '"
<< getSourceFile()->getFilename() << "':\n";
messageFn(out);
Expand Down
19 changes: 10 additions & 9 deletions lib/AST/AvailabilityScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,15 +519,16 @@ static void verificationError(
ASTContext &ctx, llvm::StringRef msg,
std::initializer_list<std::pair<const char *, const AvailabilityScope *>>
labelsAndNodes) {
llvm::errs() << msg << "\n";
for (auto pair : labelsAndNodes) {
auto label = std::get<0>(pair);
auto scope = std::get<1>(pair);
llvm::errs() << label << ":\n";
scope->print(llvm::errs(), ctx.SourceMgr);
llvm::errs() << "\n";
}
abort();
ABORT([&](auto &out) {
out << msg << "\n";
for (auto pair : labelsAndNodes) {
auto label = std::get<0>(pair);
auto scope = std::get<1>(pair);
out << label << ":\n";
scope->print(out, ctx.SourceMgr);
out << "\n";
}
});
}

void AvailabilityScope::verify(const AvailabilityScope *parent,
Expand Down
11 changes: 6 additions & 5 deletions lib/AST/Bridging/MiscBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ static SwiftMetatype declMetatypes[(unsigned)DeclKind::Last_Decl + 1];
SwiftMetatype Decl::getDeclMetatype(DeclKind kind) {
SwiftMetatype metatype = declMetatypes[(unsigned)kind];
if (declMetatypesInitialized && !metatype) {
llvm::errs() << "Decl " << getKindName(kind) << " not registered\n";
abort();
ABORT([&](auto &out) {
out << "Decl " << getKindName(kind) << " not registered";
});
}
return metatype;
}
Expand All @@ -83,9 +84,9 @@ void registerBridgedDecl(BridgedStringRef bridgedClassName,
.Default(std::nullopt);

if (!declKind) {
llvm::errs() << "Unknown Decl class " << bridgedClassName.unbridged()
<< "\n";
abort();
ABORT([&](auto &out) {
out << "Unknown Decl class " << bridgedClassName.unbridged();
});
}
declMetatypes[(unsigned)declKind.value()] = metatype;
}
Expand Down
7 changes: 4 additions & 3 deletions lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1994,9 +1994,10 @@ unsigned AbstractClosureExpr::getDiscriminator() const {
}

if (getRawDiscriminator() == InvalidDiscriminator) {
llvm::errs() << "Closure does not have an assigned discriminator:\n";
dump(llvm::errs());
abort();
ABORT([&](auto &out) {
out << "Closure does not have an assigned discriminator:\n";
this->dump(out);
});
}

return getRawDiscriminator();
Expand Down
Loading