diff --git a/common/BUILD b/common/BUILD index d11aaf2ed34e..dd3c1a4a87c3 100644 --- a/common/BUILD +++ b/common/BUILD @@ -4,6 +4,24 @@ package(default_visibility = ["//visibility:public"]) +cc_library( + name = "check", + hdrs = ["check.h"], + deps = [ + "@llvm-project//llvm:Support", + ], +) + +cc_test( + name = "check_test", + srcs = ["check_test.cpp"], + deps = [ + ":check", + "@llvm-project//llvm:gtest", + "@llvm-project//llvm:gtest_main", + ], +) + cc_library( name = "indirect_value", srcs = ["indirect_value.h"], diff --git a/common/check.h b/common/check.h new file mode 100644 index 000000000000..09ef9b9e6893 --- /dev/null +++ b/common/check.h @@ -0,0 +1,18 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef COMMON_CHECK_H_ +#define COMMON_CHECK_H_ + +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" + +#define CHECK(condition) \ + if (!(condition)) { \ + llvm::sys::PrintStackTrace(llvm::errs()); \ + llvm::report_fatal_error("CHECK failure: " #condition); \ + } + +#endif // COMMON_CHECK_H_ diff --git a/common/check_test.cpp b/common/check_test.cpp new file mode 100644 index 000000000000..eddaa642d1c5 --- /dev/null +++ b/common/check_test.cpp @@ -0,0 +1,17 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "common/check.h" + +#include "gtest/gtest.h" + +namespace Carbon { + +TEST(CheckTest, CheckTrue) { CHECK(true); } + +TEST(CheckTest, CheckFalse) { + ASSERT_DEATH({ CHECK(false); }, "LLVM ERROR: CHECK failure: false"); +} + +} // namespace Carbon diff --git a/executable_semantics/ast/BUILD b/executable_semantics/ast/BUILD index 1b755bcd7268..f43f338a3c87 100644 --- a/executable_semantics/ast/BUILD +++ b/executable_semantics/ast/BUILD @@ -49,7 +49,10 @@ cc_library( name = "statement", srcs = ["statement.cpp"], hdrs = ["statement.h"], - deps = [":expression"], + deps = [ + ":expression", + "//common:check", + ], ) cc_library( diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index b35740b94c24..27f288a2a451 100644 --- a/executable_semantics/ast/expression.cpp +++ b/executable_semantics/ast/expression.cpp @@ -4,7 +4,6 @@ #include "executable_semantics/ast/expression.h" -#include #include namespace Carbon { diff --git a/executable_semantics/ast/statement.cpp b/executable_semantics/ast/statement.cpp index 428e2c18c226..7101d25eef22 100644 --- a/executable_semantics/ast/statement.cpp +++ b/executable_semantics/ast/statement.cpp @@ -4,63 +4,64 @@ #include "executable_semantics/ast/statement.h" -#include #include +#include "common/check.h" + namespace Carbon { const Expression* Statement::GetExpression() const { - assert(tag == StatementKind::ExpressionStatement); + CHECK(tag == StatementKind::ExpressionStatement); return u.exp; } Assignment Statement::GetAssign() const { - assert(tag == StatementKind::Assign); + CHECK(tag == StatementKind::Assign); return u.assign; } VariableDefinition Statement::GetVariableDefinition() const { - assert(tag == StatementKind::VariableDefinition); + CHECK(tag == StatementKind::VariableDefinition); return u.variable_definition; } IfStatement Statement::GetIf() const { - assert(tag == StatementKind::If); + CHECK(tag == StatementKind::If); return u.if_stmt; } const Expression* Statement::GetReturn() const { - assert(tag == StatementKind::Return); + CHECK(tag == StatementKind::Return); return u.return_stmt; } Sequence Statement::GetSequence() const { - assert(tag == StatementKind::Sequence); + CHECK(tag == StatementKind::Sequence); return u.sequence; } Block Statement::GetBlock() const { - assert(tag == StatementKind::Block); + CHECK(tag == StatementKind::Block); return u.block; } While Statement::GetWhile() const { - assert(tag == StatementKind::While); + CHECK(tag == StatementKind::While); return u.while_stmt; } Match Statement::GetMatch() const { - assert(tag == StatementKind::Match); + CHECK(tag == StatementKind::Match); return u.match_stmt; } Continuation Statement::GetContinuation() const { - assert(tag == StatementKind::Continuation); + CHECK(tag == StatementKind::Continuation); return u.continuation; } Run Statement::GetRun() const { - assert(tag == StatementKind::Run); + CHECK(tag == StatementKind::Run); return u.run; } diff --git a/executable_semantics/interpreter/BUILD b/executable_semantics/interpreter/BUILD index 0ee87130202c..e07ece8d6a1c 100644 --- a/executable_semantics/interpreter/BUILD +++ b/executable_semantics/interpreter/BUILD @@ -23,6 +23,7 @@ cc_library( ], deps = [ ":containers", + "//common:check", "//executable_semantics:tracing_flag", "//executable_semantics/ast:declaration", "//executable_semantics/ast:expression", @@ -41,4 +42,5 @@ cc_library( "dictionary.h", "stack.h", ], + deps = ["//common:check"], ) diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index ed9f298c7a05..a7e2fb809da2 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -4,7 +4,6 @@ #include "executable_semantics/interpreter/interpreter.h" -#include #include #include #include @@ -13,6 +12,7 @@ #include #include +#include "common/check.h" #include "executable_semantics/ast/expression.h" #include "executable_semantics/ast/function_definition.h" #include "executable_semantics/interpreter/stack.h" @@ -36,7 +36,7 @@ auto Heap::AllocateValue(const Value* v) -> Address { // ensures that we don't do anything else in between, which is really bad! // Consider whether to include a copy of the input v in this function // or to leave it up to the caller. - assert(v != nullptr); + CHECK(v != nullptr); Address a = values_.size(); values_.push_back(v); alive_.push_back(true); @@ -49,7 +49,7 @@ auto Heap::Read(Address a, int line_num) -> const Value* { } auto Heap::Write(Address a, const Value* v, int line_num) -> void { - assert(v != nullptr); + CHECK(v != nullptr); this->CheckAlive(a, line_num); values_[a] = v; } @@ -838,7 +838,7 @@ void StepStmt() { Frame* frame = state->stack.Top(); Action* act = frame->todo.Top(); const Statement* stmt = act->u.stmt; - assert(stmt != nullptr && "null statement!"); + CHECK(stmt != nullptr && "null statement!"); if (tracing_output) { std::cout << "--- step stmt "; PrintStatement(stmt, 1); diff --git a/executable_semantics/interpreter/stack.h b/executable_semantics/interpreter/stack.h index 31635628277d..ab233b5b9306 100644 --- a/executable_semantics/interpreter/stack.h +++ b/executable_semantics/interpreter/stack.h @@ -5,10 +5,10 @@ #ifndef EXECUTABLE_SEMANTICS_INTERPRETER_STACK_H_ #define EXECUTABLE_SEMANTICS_INTERPRETER_STACK_H_ -#include #include #include +#include "common/check.h" #include "executable_semantics/interpreter/list_node.h" namespace Carbon { @@ -73,7 +73,7 @@ struct Stack { // // - Requires: !this->IsEmpty() auto Pop() -> T { - assert(!IsEmpty() && "Can't pop from empty stack."); + CHECK(!IsEmpty() && "Can't pop from empty stack."); auto r = head->curr; head = head->next; return r; @@ -83,9 +83,9 @@ struct Stack { // // - Requires: n >= 0 && n <= Count() void Pop(int n) { - assert(n >= 0 && "Negative pop count disallowed."); + CHECK(n >= 0 && "Negative pop count disallowed."); while (n--) { - assert(head != nullptr && "Can only pop as many elements as stack has."); + CHECK(head != nullptr && "Can only pop as many elements as stack has."); head = head->next; } } @@ -103,7 +103,7 @@ struct Stack { // // - Requires: !this->IsEmpty() auto Top() const -> T { - assert(!IsEmpty() && "Empty stack has no Top()."); + CHECK(!IsEmpty() && "Empty stack has no Top()."); return head->curr; } diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index f58a2f9b6937..a3f6e66fe110 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -5,85 +5,85 @@ #include "executable_semantics/interpreter/value.h" #include -#include #include +#include "common/check.h" #include "executable_semantics/interpreter/interpreter.h" namespace Carbon { int Value::GetInteger() const { - assert(tag == ValKind::IntV); + CHECK(tag == ValKind::IntV); return u.integer; } bool Value::GetBoolean() const { - assert(tag == ValKind::BoolV); + CHECK(tag == ValKind::BoolV); return u.boolean; } Function Value::GetFunction() const { - assert(tag == ValKind::FunV); + CHECK(tag == ValKind::FunV); return u.fun; } StructConstructor Value::GetStruct() const { - assert(tag == ValKind::StructV); + CHECK(tag == ValKind::StructV); return u.struct_val; } AlternativeConstructor Value::GetAlternativeConstructor() const { - assert(tag == ValKind::AltConsV); + CHECK(tag == ValKind::AltConsV); return u.alt_cons; } Alternative Value::GetAlternative() const { - assert(tag == ValKind::AltV); + CHECK(tag == ValKind::AltV); return u.alt; } TupleValue Value::GetTuple() const { - assert(tag == ValKind::TupleV); + CHECK(tag == ValKind::TupleV); return u.tuple; } Address Value::GetPointer() const { - assert(tag == ValKind::PtrV); + CHECK(tag == ValKind::PtrV); return u.ptr; } std::string* Value::GetVariableType() const { - assert(tag == ValKind::VarTV); + CHECK(tag == ValKind::VarTV); return u.var_type; } VariablePatternValue Value::GetVariablePattern() const { - assert(tag == ValKind::VarPatV); + CHECK(tag == ValKind::VarPatV); return u.var_pat; } FunctionTypeValue Value::GetFunctionType() const { - assert(tag == ValKind::FunctionTV); + CHECK(tag == ValKind::FunctionTV); return u.fun_type; } PointerType Value::GetPointerType() const { - assert(tag == ValKind::PointerTV); + CHECK(tag == ValKind::PointerTV); return u.ptr_type; } StructType Value::GetStructType() const { - assert(tag == ValKind::StructTV); + CHECK(tag == ValKind::StructTV); return u.struct_type; } ChoiceType Value::GetChoiceType() const { - assert(tag == ValKind::ChoiceTV); + CHECK(tag == ValKind::ChoiceTV); return u.choice_type; } ContinuationValue Value::GetContinuation() const { - assert(tag == ValKind::ContinuationV); + CHECK(tag == ValKind::ContinuationV); return u.continuation; } @@ -116,7 +116,7 @@ auto FieldsEqual(VarValues* ts1, VarValues* ts2) -> bool { auto FindTupleField(const std::string& name, const Value* tuple) -> std::optional
{ - assert(tuple->tag == ValKind::TupleV); + CHECK(tuple->tag == ValKind::TupleV); for (const TupleElement& element : *tuple->GetTuple().elements) { if (element.name == name) { return element.address;