Use colon instead of as to cast

This commit is contained in:
2025-02-14 08:05:03 +01:00
parent c564847c6b
commit ee4ebf64b9
10 changed files with 488 additions and 290 deletions

View File

@ -43,6 +43,94 @@ namespace gcc
this->symbol_map = symbol_table;
}
void generic_visitor::build_procedure_call(location_t call_location,
tree symbol, const std::vector<boot::expression *>& arguments)
{
vec<tree, va_gc> *argument_trees = nullptr;
tree current_parameter = TYPE_ARG_TYPES(TREE_TYPE(symbol));
vec_alloc(argument_trees, arguments.size());
for (boot::expression *const argument : arguments)
{
location_t argument_location = get_location(&argument->position());
if (is_void_type(TREE_VALUE(current_parameter)))
{
error_at(argument_location, "too many arguments, expected %i, got %lu",
list_length(TYPE_ARG_TYPES(TREE_TYPE(symbol))) - 1, arguments.size());
this->current_expression = error_mark_node;
break;
}
argument->accept(this);
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'",
print_type(TREE_TYPE(this->current_expression)).c_str(),
print_type(TREE_VALUE(current_parameter)).c_str());
this->current_expression = error_mark_node;
}
current_parameter = TREE_CHAIN(current_parameter);
argument_trees->quick_push(this->current_expression);
}
tree stmt = build_call_expr_loc_vec(call_location, symbol, argument_trees);
if (!is_void_type(TREE_VALUE(current_parameter)))
{
error_at(call_location, "too few arguments, expected %i, got %lu",
list_length(TYPE_ARG_TYPES(TREE_TYPE(symbol))) - 1, arguments.size());
this->current_expression = error_mark_node;
}
else if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node)
{
append_statement(stmt);
this->current_expression = NULL_TREE;
}
else
{
this->current_expression = stmt;
}
}
void generic_visitor::build_record_call(location_t call_location,
tree symbol, const std::vector<boot::expression *>& arguments)
{
vec<constructor_elt, va_gc> *tree_arguments = nullptr;
tree record_fields = TYPE_FIELDS(symbol);
for (boot::expression *const argument : arguments)
{
location_t argument_location = get_location(&argument->position());
if (is_void_type(record_fields))
{
error_at(argument_location, "too many arguments, expected %i, got %lu",
list_length(TYPE_FIELDS(symbol)), arguments.size());
this->current_expression = error_mark_node;
break;
}
argument->accept(this);
if (!is_assignable_from(TREE_TYPE(record_fields), this->current_expression))
{
error_at(argument_location,
"cannot assign value of type '%s' to variable of type '%s'",
print_type(TREE_TYPE(this->current_expression)).c_str(),
print_type(TREE_TYPE(record_fields)).c_str());
this->current_expression = error_mark_node;
}
CONSTRUCTOR_APPEND_ELT(tree_arguments, record_fields, this->current_expression);
record_fields = TREE_CHAIN(record_fields);
}
if (!is_void_type(record_fields))
{
error_at(call_location, "too few arguments, expected %i, got %lu",
list_length(TYPE_FIELDS(symbol)), arguments.size());
this->current_expression = error_mark_node;
}
else
{
this->current_expression = build_constructor(symbol, tree_arguments);
}
}
void generic_visitor::visit(boot::call_expression *expression)
{
tree symbol = this->lookup(expression->name());
@ -56,37 +144,11 @@ namespace gcc
}
else if (DECL_P(symbol) && is_procedure_type(TREE_TYPE(symbol)))
{
vec<tree, va_gc> *arguments = nullptr;
vec_alloc(arguments, expression->arguments().size());
for (boot::expression *const argument : expression->arguments())
{
argument->accept(this);
arguments->quick_push(this->current_expression);
}
tree stmt = build_call_expr_loc_vec(get_location(&expression->position()), symbol, arguments);
if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node)
{
append_statement(stmt);
this->current_expression = NULL_TREE;
}
else
{
this->current_expression = stmt;
}
build_procedure_call(call_location, symbol, expression->arguments());
}
else if (TYPE_P(symbol) && is_record_type(symbol))
else if (TYPE_P(symbol) && TREE_CODE(symbol) == RECORD_TYPE)
{
vec<constructor_elt, va_gc> *arguments = nullptr;
tree record_fields = TYPE_FIELDS(symbol);
for (boot::expression *const argument : expression->arguments())
{
argument->accept(this);
CONSTRUCTOR_APPEND_ELT(arguments, record_fields, this->current_expression);
record_fields = TREE_CHAIN(record_fields);
}
this->current_expression = build_constructor(symbol, arguments);
build_record_call(call_location, symbol, expression->arguments());
}
else
{
@ -107,11 +169,9 @@ namespace gcc
cast_target, this->current_expression);
}
void generic_visitor::visit(boot::size_of_expression *expression)
void generic_visitor::visit(boot::type_expression *expression)
{
auto body_type = build_type(expression->body());
this->current_expression = build1(CONVERT_EXPR, elna_word_type_node, size_in_bytes(body_type));
this->current_expression = build_type(expression->body());
}
void generic_visitor::visit(boot::program *program)
@ -185,7 +245,7 @@ namespace gcc
for (std::size_t i = 0; i < definition->parameters.size(); ++i)
{
parameter_types[i] = build_type(definition->parameters.at(i)->type());
parameter_types[i] = build_type(definition->parameters.at(i)->variable_type());
}
tree return_type = definition->return_type() == nullptr
? void_type_node
@ -315,12 +375,12 @@ namespace gcc
void generic_visitor::visit(boot::number_literal<std::int32_t> *literal)
{
this->current_expression = build_int_cst(elna_int_type_node, literal->number());
this->current_expression = build_int_cst(elna_int_type_node, literal->value);
}
void generic_visitor::visit(boot::number_literal<std::uint32_t> *literal)
{
this->current_expression = build_int_cstu(elna_word_type_node, literal->number());
this->current_expression = build_int_cstu(elna_word_type_node, literal->value);
}
void generic_visitor::visit(boot::number_literal<double> *literal)
@ -329,7 +389,7 @@ namespace gcc
mpfr_t number;
mpfr_init2(number, SIGNIFICAND_BITS);
mpfr_set_d(number, literal->number(), MPFR_RNDN);
mpfr_set_d(number, literal->value, MPFR_RNDN);
real_from_mpfr(&real_value1, number, double_type_node, MPFR_RNDN);
@ -340,12 +400,12 @@ namespace gcc
void generic_visitor::visit(boot::number_literal<bool> *boolean)
{
this->current_expression = boolean->number() ? boolean_true_node : boolean_false_node;
this->current_expression = boolean->value ? boolean_true_node : boolean_false_node;
}
void generic_visitor::visit(boot::number_literal<unsigned char> *character)
{
this->current_expression = build_int_cstu(elna_char_type_node, character->number());
this->current_expression = build_int_cstu(elna_char_type_node, character->value);
}
void generic_visitor::visit(boot::number_literal<nullptr_t> *)
@ -355,10 +415,10 @@ namespace gcc
void generic_visitor::visit(boot::number_literal<std::string> *string)
{
tree index_constant = build_int_cstu(elna_word_type_node, string->number().size());
tree index_constant = build_int_cstu(elna_word_type_node, string->value.size());
tree string_type = build_array_type(elna_char_type_node, build_index_type(index_constant));
tree string_literal = build_string(string->number().size(), string->number().c_str());
tree string_literal = build_string(string->value.size(), string->value.c_str());
TREE_TYPE(string_literal) = string_type;
TREE_CONSTANT(string_literal) = 1;
TREE_READONLY(string_literal) = 1;
@ -390,11 +450,49 @@ namespace gcc
expression, operator_code, left, right, elna_bool_type_node);
}
tree generic_visitor::build_logic_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right)
tree generic_visitor::build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right)
{
return build_binary_operation(TREE_TYPE(left) == elna_bool_type_node,
expression, operator_code, left, right, elna_bool_type_node);
location_t expression_location = get_location(&expression->position());
tree left_type = TREE_TYPE(left);
tree right_type = TREE_TYPE(right);
tree_code logical_code, bit_code;
if (expression->operation() == boot::binary_operator::conjunction)
{
bit_code = BIT_AND_EXPR;
logical_code = TRUTH_ANDIF_EXPR;
}
else if (expression->operation() == boot::binary_operator::disjunction)
{
bit_code = BIT_IOR_EXPR;
logical_code = TRUTH_ORIF_EXPR;
}
else if (expression->operation() == boot::binary_operator::exclusive_disjunction)
{
bit_code = BIT_XOR_EXPR;
logical_code = TRUTH_XOR_EXPR;
}
else
{
gcc_unreachable();
}
if (left_type == elna_bool_type_node)
{
return build2_loc(expression_location, logical_code, elna_bool_type_node, left, right);
}
else if (is_integral_type(left_type))
{
return build2_loc(expression_location, bit_code, left_type, left, right);
}
else
{
error_at(expression_location,
"invalid operands of type '%s' and '%s' for operator %s",
print_type(left_type).c_str(), print_type(right_type).c_str(),
elna::boot::print_binary_operator(expression->operation()));
return error_mark_node;
}
}
tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree left, tree right)
@ -475,7 +573,9 @@ namespace gcc
}
return;
}
if (left_type != right_type && !are_compatible_pointers(left, right) && !are_compatible_pointers(right, left))
if (left_type != right_type
&& !are_compatible_pointers(left_type, right)
&& !are_compatible_pointers(right_type, left))
{
error_at(expression_location,
"invalid operands of type %s and %s for operator %s",
@ -514,10 +614,13 @@ namespace gcc
this->current_expression = build_comparison_operation(expression, GE_EXPR, left, right);
break;
case boot::binary_operator::conjunction:
this->current_expression = build_logic_operation(expression, TRUTH_ANDIF_EXPR, left, right);
this->current_expression = build_bit_logic_operation(expression, left, right);
break;
case boot::binary_operator::disjunction:
this->current_expression = build_logic_operation(expression, TRUTH_ORIF_EXPR, left, right);
this->current_expression = build_bit_logic_operation(expression, left, right);
break;
case boot::binary_operator::exclusive_disjunction:
this->current_expression = build_bit_logic_operation(expression, left, right);
break;
case boot::binary_operator::equals:
this->current_expression = build_equality_operation(expression, left, right);
@ -531,23 +634,47 @@ namespace gcc
void generic_visitor::visit(boot::unary_expression *expression)
{
expression->operand().accept(this);
location_t location = get_location(&expression->position());
switch (expression->operation())
{
case boot::unary_operator::reference:
TREE_ADDRESSABLE(this->current_expression) = 1;
this->current_expression = build_fold_addr_expr_with_type_loc(get_location(&expression->position()),
this->current_expression = build_fold_addr_expr_with_type_loc(location,
this->current_expression,
build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true));
TREE_NO_TRAMPOLINE(this->current_expression) = 1;
break;
case boot::unary_operator::negation:
this->current_expression = build1_loc(get_location(&expression->position()), TRUTH_NOT_EXPR,
boolean_type_node, this->current_expression);
if (TREE_TYPE(this->current_expression) == elna_bool_type_node)
{
this->current_expression = build1_loc(location, TRUTH_NOT_EXPR,
boolean_type_node, this->current_expression);
}
else if (is_integral_type(TREE_TYPE(this->current_expression)))
{
this->current_expression = build1_loc(location, BIT_NOT_EXPR,
TREE_TYPE(this->current_expression), this->current_expression);
}
else
{
error_at(location, "type '%s' cannot be negated",
print_type(TREE_TYPE(this->current_expression)).c_str());
this->current_expression = error_mark_node;
}
break;
case boot::unary_operator::minus:
this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression),
this->current_expression);
if (is_integral_type(TREE_TYPE(this->current_expression)))
{
this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression),
this->current_expression);
}
else
{
error_at(location, "type '%s' cannot be negated",
print_type(TREE_TYPE(this->current_expression)).c_str());
this->current_expression = error_mark_node;
}
}
}
@ -603,9 +730,9 @@ namespace gcc
}
}
tree generic_visitor::build_type(boot::type_expression& type)
tree generic_visitor::build_type(boot::top_type& type)
{
if (boot::basic_type_expression *basic_type = type.is_basic())
if (boot::basic_type *basic_type = type.is_basic())
{
tree symbol = this->lookup(basic_type->base_name());
@ -618,7 +745,7 @@ namespace gcc
return error_mark_node;
}
else if (boot::array_type_expression *array_type = type.is_array())
else if (boot::array_type *array_type = type.is_array())
{
tree lower_bound = build_int_cst_type(integer_type_node, 0);
tree upper_bound = build_int_cst_type(integer_type_node, array_type->size);
@ -632,7 +759,7 @@ namespace gcc
return build_array_type(base_type, range_type);
}
else if (boot::pointer_type_expression *pointer_type = type.is_pointer())
else if (boot::pointer_type *pointer_type = type.is_pointer())
{
tree base_type = build_type(pointer_type->base());
@ -642,7 +769,7 @@ namespace gcc
}
return build_pointer_type_for_mode(base_type, VOIDmode, true);
}
else if (boot::record_type_expression *record_type = type.is_record())
else if (boot::record_type *record_type = type.is_record())
{
std::set<std::string> field_names;
tree record_type_node = make_node(RECORD_TYPE);
@ -669,7 +796,7 @@ namespace gcc
return record_type_node;
}
else if (boot::union_type_expression *union_type = type.is_union())
else if (boot::union_type *union_type = type.is_union())
{
std::set<std::string> field_names;
tree union_type_node = make_node(UNION_TYPE);
@ -701,7 +828,7 @@ namespace gcc
void generic_visitor::visit(boot::variable_declaration *declaration)
{
tree declaration_type = build_type(declaration->type());
tree declaration_type = build_type(declaration->variable_type());
gcc_assert(declaration_type != NULL_TREE);
location_t declaration_location = get_location(&declaration->position());
@ -709,6 +836,10 @@ namespace gcc
get_identifier(declaration->identifier.c_str()), declaration_type);
bool result = this->symbol_map->enter(declaration->identifier, declaration_tree);
if (is_pointer_type(declaration_type))
{
DECL_INITIAL(declaration_tree) = elna_pointer_nil_node;
}
if (!result)
{
error_at(declaration_location, "variable '%s' already declared in this scope",
@ -795,32 +926,56 @@ namespace gcc
void generic_visitor::visit(boot::field_access_expression *expression)
{
expression->base().accept(this);
tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression));
while (field_declaration != NULL_TREE)
{
tree declaration_name = DECL_NAME(field_declaration);
const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name);
if (expression->field() == identifier_pointer)
{
break;
}
field_declaration = TREE_CHAIN(field_declaration);
}
location_t expression_location = get_location(&expression->position());
if (field_declaration == NULL_TREE)
if (TYPE_P(this->current_expression))
{
error_at(expression_location,
"record type does not have a field named '%s'",
expression->field().c_str());
this->current_expression = error_mark_node;
if (expression->field() == "size")
{
this->current_expression = build1(CONVERT_EXPR, elna_word_type_node,
size_in_bytes(this->current_expression));
}
else if (expression->field() == "alignment")
{
this->current_expression = build_int_cstu(elna_word_type_node,
TYPE_ALIGN_UNIT(this->current_expression));
}
else
{
error_at(expression_location, "type '%s' does not have property '%s'",
print_type(this->current_expression).c_str(), expression->field().c_str());
this->current_expression = error_mark_node;
}
}
else
else if (is_aggregate_type(TREE_TYPE(this->current_expression)))
{
this->current_expression = build3_loc(expression_location, COMPONENT_REF,
TREE_TYPE(field_declaration), this->current_expression,
field_declaration, NULL_TREE);
tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression));
while (field_declaration != NULL_TREE)
{
tree declaration_name = DECL_NAME(field_declaration);
const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name);
if (expression->field() == identifier_pointer)
{
break;
}
field_declaration = TREE_CHAIN(field_declaration);
}
if (field_declaration == NULL_TREE)
{
error_at(expression_location,
"record type does not have a field named '%s'",
expression->field().c_str());
this->current_expression = error_mark_node;
}
else
{
this->current_expression = build3_loc(expression_location, COMPONENT_REF,
TREE_TYPE(field_declaration), this->current_expression,
field_declaration, NULL_TREE);
}
}
}
@ -848,8 +1003,7 @@ namespace gcc
this->current_expression = error_mark_node;
return;
}
if (TREE_TYPE(this->current_expression) == TREE_TYPE(lvalue)
|| are_compatible_pointers(lvalue, this->current_expression))
if (is_assignable_from(TREE_TYPE(lvalue), this->current_expression))
{
tree assignment = build2_loc(statement_location, MODIFY_EXPR,
void_type_node, lvalue, this->current_expression);

View File

@ -62,20 +62,27 @@ namespace gcc
return type == NULL_TREE || type == void_type_node;
}
bool is_record_type(tree type)
bool is_aggregate_type(tree type)
{
return TREE_CODE(type) == RECORD_TYPE;
gcc_assert(TYPE_P(type));
return TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == UNION_TYPE;
}
bool are_compatible_pointers(tree lhs, tree rhs)
bool are_compatible_pointers(tree lhs_type, tree rhs)
{
tree lhs_type = TREE_TYPE(lhs);
gcc_assert(TYPE_P(lhs_type));
tree rhs_type = TREE_TYPE(rhs);
return (is_pointer_type(lhs_type) && rhs == elna_pointer_nil_node)
|| (is_pointer_type(lhs_type) && lhs_type == rhs_type);
}
bool is_assignable_from(tree assignee, tree assignment)
{
return TREE_TYPE(assignment) == assignee
|| are_compatible_pointers(assignee, assignment);
}
void append_statement(tree statement_tree)
{
if (!vec_safe_is_empty(f_binding_level->defers))