Replace unreachable() with assert(false)

This commit is contained in:
Eugen Wissner 2025-04-20 11:20:04 +02:00
parent c99237fd9c
commit 09ad85b058
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
7 changed files with 104 additions and 25 deletions

View File

@ -339,7 +339,7 @@ namespace elna::boot
std::shared_ptr<variable_info> variable_info::is_variable()
{
return std::static_pointer_cast<variable_info>(shared_from_this());;
return std::static_pointer_cast<variable_info>(shared_from_this());
}
std::shared_ptr<symbol_table> builtin_symbol_table()

View File

@ -73,8 +73,6 @@ namespace elna::gcc
declare_builtin_type(symbol_table, "Float", elna_float_type_node);
declare_builtin_type(symbol_table, "String", elna_string_type_node);
symbol_table->enter("unreachable", *elna_global_decls->get("__builtin_unreachable"));
return symbol_table;
}
}

View File

@ -148,7 +148,7 @@ namespace elna::gcc
if (!is_assignable_from(TREE_VALUE(current_parameter), this->current_expression))
{
error_at(argument_location,
"cannot assign value of type '%s' to variable of type '%s'",
"Cannot assign value of type '%s' to variable of type '%s'",
print_type(TREE_TYPE(this->current_expression)).c_str(),
print_type(TREE_VALUE(current_parameter)).c_str());
this->current_expression = error_mark_node;
@ -202,7 +202,7 @@ namespace elna::gcc
}
if (!is_void_type(record_fields))
{
error_at(call_location, "too few arguments, expected %i, got %lu",
error_at(call_location, "Too few arguments, expected %i, got %lu",
list_length(TYPE_FIELDS(symbol)), arguments.size());
this->current_expression = error_mark_node;
}
@ -212,8 +212,62 @@ namespace elna::gcc
}
}
void generic_visitor::build_assert_builtin(location_t call_location,
const std::vector<boot::expression *>& arguments)
{
if (arguments.size() != 1)
{
error_at(call_location, "assert expects exactly one boolean argument, got %lu", arguments.size());
this->current_expression = error_mark_node;
}
else
{
arguments.at(0)->accept(this);
tree argument_type = TREE_TYPE(this->current_expression);
if (argument_type != elna_bool_type_node)
{
error_at(call_location, "assert expects exactly one boolean argument, got %s",
print_type(argument_type).c_str());
this->current_expression = error_mark_node;
}
tree constant_expression = extract_constant(this->current_expression);
if (constant_expression == boolean_false_node)
{
this->current_expression = call_built_in(call_location, "__builtin_unreachable", void_type_node);
}
else if (constant_expression != boolean_true_node)
{
this->current_expression = call_built_in(call_location, "__builtin_trap", void_type_node);
}
else
{
this->current_expression = NULL_TREE;
}
}
}
bool generic_visitor::build_builtin_procedures(boot::procedure_call *call)
{
location_t call_location = get_location(&call->position());
if (boot::variable_expression *named_call = call->callable().is_variable())
{
if (named_call->name == "assert")
{
build_assert_builtin(call_location, call->arguments);
return true;
}
}
return false;
}
void generic_visitor::visit(boot::procedure_call *call)
{
if (build_builtin_procedures(call))
{
return;
}
location_t call_location = get_location(&call->position());
call->callable().accept(this);
@ -599,13 +653,8 @@ namespace elna::gcc
right, elna_string_ptr_field_node, NULL_TREE);
tree length_equality = build2(equality_code, elna_bool_type_node, lhs_length, rhs_length);
tree *memcmp = elna_global_decls->get("__builtin_memcmp");
gcc_assert(memcmp != nullptr);
tree fndecl_type = build_function_type(integer_type_node, TYPE_ARG_TYPES(*memcmp));
tree memcmp_addr = build1(ADDR_EXPR, build_pointer_type(fndecl_type), *memcmp);
tree memcmp_call = build_call_nary(integer_type_node, memcmp_addr, 3, lhs_ptr, rhs_ptr, lhs_length);
tree memcmp_call = call_built_in(UNKNOWN_LOCATION, "__builtin_memcmp", integer_type_node,
lhs_ptr, rhs_ptr, lhs_length);
tree equals_zero = build2(equality_code, elna_bool_type_node, memcmp_call, integer_zero_node);
return build2(combination_code, elna_bool_type_node, length_equality, equals_zero);
@ -768,7 +817,7 @@ namespace elna::gcc
location_t definition_location = get_location(&definition->position());
definition->body().accept(this);
if (extract_constant(definition_location))
if (assert_constant(definition_location))
{
this->current_expression = fold_init(this->current_expression);
}
@ -1490,7 +1539,7 @@ namespace elna::gcc
case_label->accept(this);
location_t case_location = get_location(&case_label->position());
if (extract_constant(case_location)
if (assert_constant(case_location)
&& !is_assignable_from(unqualified_condition, this->current_expression))
{
error_at(case_location, "Case type '%s' does not match the expression type '%s'",
@ -1535,20 +1584,19 @@ namespace elna::gcc
this->current_expression = NULL_TREE;
}
bool generic_visitor::extract_constant(location_t expression_location)
bool generic_visitor::assert_constant(location_t expression_location)
{
int code = TREE_CODE(this->current_expression);
tree constant_expression = extract_constant(this->current_expression);
if (code == CONST_DECL)
{
this->current_expression = DECL_INITIAL(this->current_expression);
}
else if (TREE_CODE_CLASS(code) != tcc_constant)
if (constant_expression == NULL_TREE)
{
error_at(expression_location, "Expected a constant expression");
this->current_expression = error_mark_node;
return false;
}
return true;
else
{
this->current_expression = constant_expression;
}
return this->current_expression != error_mark_node;
}
}

View File

@ -249,4 +249,19 @@ namespace elna::gcc
return label_decl;
}
tree extract_constant(tree expression)
{
int code = TREE_CODE(expression);
if (code == CONST_DECL)
{
return DECL_INITIAL(expression);
}
else if (TREE_CODE_CLASS(code) == tcc_constant)
{
return expression;
}
return NULL_TREE;
}
}

View File

@ -40,7 +40,6 @@ namespace elna::gcc
std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved,
std::vector<std::string>& path);
class generic_visitor final : public boot::parser_visitor
{
tree current_expression{ NULL_TREE };
@ -68,11 +67,13 @@ namespace elna::gcc
tree procedure_address, const std::vector<boot::expression *>& arguments);
void build_record_call(location_t call_location,
tree symbol, const std::vector<boot::expression *>& arguments);
bool build_builtin_procedures(boot::procedure_call *call);
void build_assert_builtin(location_t call_location, const std::vector<boot::expression *>& arguments);
bool expect_trait_type_only(boot::traits_expression *trait);
bool expect_trait_for_integral_type(boot::traits_expression *trait);
void visit_statements(const std::vector<boot::statement *>& statements);
bool extract_constant(location_t expression_location);
bool assert_constant(location_t expression_location);
public:
generic_visitor(std::shared_ptr<symbol_table> symbol_table,

View File

@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "elna/boot/ast.h"
#include "elna/boot/symbol.h"
#include "elna/gcc/elna1.h"
namespace elna::gcc
{
@ -82,4 +83,18 @@ namespace elna::gcc
tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name);
tree build_global_pointer_type(tree type);
tree build_label_decl(const char *name, location_t loc);
tree extract_constant(tree expression);
template<typename... Args>
tree call_built_in(location_t call_location, const char *name, tree return_type, Args... arguments)
{
tree *builtin = elna_global_decls->get(name);
gcc_assert(builtin != nullptr);
tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(*builtin));
tree builtin_addr = build1_loc(call_location, ADDR_EXPR, build_pointer_type(fndecl_type), *builtin);
return build_call_nary(return_type, builtin_addr, sizeof...(Args), arguments...);
}
}

View File

@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#pragma once
enum elna_tree_index
{
ELNA_TI_INT_TYPE,