Switch from llvm::errs()+exit() to FATAL_USER_ERROR() stream-based handling. (#670)

This is intended to:

- Standardize use of line_num (and highlight where no line_num is available).
- Standardize indications of runtime/compilation errors.
- Make it incrementally easier to write new errors.

Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This commit is contained in:
Jon Meow
2021-07-28 10:47:33 -07:00
committed by GitHub
co-authored by Chandler Carruth
parent dcc694c2e0
commit f0af3cb795
24 changed files with 206 additions and 170 deletions
+35 -10
View File
@@ -11,28 +11,53 @@
namespace Carbon {
// Prints an error and exits. This should be used for non-recoverable errors
// with user input.
//
// For example:
// FatalUserError() << "Input is not valid!";
class FatalUserError {
namespace ErrorInternal {
// An error-printing stream that exits on destruction.
class ExitingStream {
public:
FatalUserError() { llvm::errs() << "ERROR: "; }
~FatalUserError() {
// Finish with a newline.
// Ends the error with a newline and exits.
LLVM_ATTRIBUTE_NORETURN virtual ~ExitingStream() {
llvm::errs() << "\n";
exit(-1);
}
// Forward output to llvm::errs.
template <typename T>
FatalUserError& operator<<(const T& message) {
ExitingStream& operator<<(const T& message) {
llvm::errs() << message;
return *this;
}
};
} // namespace ErrorInternal
// Prints an error and exits. This should be used for non-recoverable errors
// with user input.
//
// For example:
// FATAL_USER_ERROR(line_num) << "Line is bad!";
// FATAL_USER_ERROR_NO_LINE() << "Application is bad!";
//
// Where possible, try to identify the error as a compilation error or runtime
// error. The generic user error option is provided as a fallback for cases that
// don't fit either of those classifications.
#define FATAL_USER_ERROR_NO_LINE() ErrorInternal::ExitingStream() << "ERROR: "
#define FATAL_USER_ERROR(line) FATAL_USER_ERROR_NO_LINE() << line << ": "
#define FATAL_COMPILATION_ERROR_NO_LINE() \
ErrorInternal::ExitingStream() << "COMPILATION ERROR: "
#define FATAL_COMPILATION_ERROR(line) \
FATAL_COMPILATION_ERROR_NO_LINE() << line << ": "
#define FATAL_RUNTIME_ERROR_NO_LINE() \
ErrorInternal::ExitingStream() << "RUNTIME ERROR: "
#define FATAL_RUNTIME_ERROR(line) FATAL_RUNTIME_ERROR_NO_LINE() << line << ": "
} // namespace Carbon
#endif // EXECUTABLE_SEMANTICS_COMMON_ERROR_H_
+23 -1
View File
@@ -7,9 +7,31 @@
#include "gtest/gtest.h"
namespace Carbon {
namespace {
TEST(ErrorTest, FatalUserError) {
ASSERT_DEATH({ FatalUserError() << "test"; }, "ERROR: test\n");
ASSERT_DEATH({ FATAL_RUNTIME_ERROR_NO_LINE() << "test"; }, "ERROR: test\n");
}
TEST(ErrorTest, FatalRuntimeError) {
ASSERT_DEATH({ FATAL_RUNTIME_ERROR_NO_LINE() << "test"; },
"RUNTIME ERROR: test\n");
}
TEST(ErrorTest, FatalCompilationError) {
ASSERT_DEATH({ FATAL_COMPILATION_ERROR_NO_LINE() << "test"; },
"COMPILATION ERROR: test\n");
}
TEST(ErrorTest, FatalUserErrorLine) {
ASSERT_DEATH({ FATAL_USER_ERROR(1) << "test"; }, "ERROR: 1: test\n");
}
auto NoReturnRequired() -> int { FATAL_USER_ERROR_NO_LINE() << "test"; }
TEST(ErrorTest, NoReturnRequired) {
ASSERT_DEATH({ NoReturnRequired(); }, "ERROR: test\n");
}
} // namespace
} // namespace Carbon