diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-07-29 01:16:18 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-07-29 01:16:18 +0200 |
| commit | f8daedce5c73e02dfb2fc59d75777190185584df (patch) | |
| tree | 9ec211b96c3d7efd2fca0da37baeaa8b341e31fb /gcc | |
| parent | 36a274c9a8bca944234589220def025d3920b3ef (diff) | |
| download | elna-f8daedce5c73e02dfb2fc59d75777190185584df.tar.gz | |
Validate cast compatibility during semantic analysis
Diffstat (limited to 'gcc')
| -rw-r--r-- | gcc/gcc/elna-diagnostic.cc | 107 | ||||
| -rw-r--r-- | gcc/gcc/elna-generic.cc | 135 | ||||
| -rw-r--r-- | gcc/gcc/elna-tree.cc | 39 |
3 files changed, 62 insertions, 219 deletions
diff --git a/gcc/gcc/elna-diagnostic.cc b/gcc/gcc/elna-diagnostic.cc index 3dcdb98..909869c 100644 --- a/gcc/gcc/elna-diagnostic.cc +++ b/gcc/gcc/elna-diagnostic.cc @@ -16,8 +16,6 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "elna/gcc/elna-diagnostic.h" -#include "elna/gcc/elna-tree.h" -#include "elna/gcc/elna1.h" namespace elna::gcc { @@ -65,111 +63,6 @@ namespace elna::gcc return make_location(caret, start, end); } - static std::string print_aggregate_name(tree type, const std::string& kind_name) - { - if (TYPE_IDENTIFIER(type) == NULL_TREE) - { - return kind_name; - } - else - { - return std::string(IDENTIFIER_POINTER(TYPE_IDENTIFIER(type))); - } - } - - std::string print_type(tree type) - { - gcc_assert(TYPE_P(type)); - - tree unqualified_type = get_qualified_type(type, TYPE_UNQUALIFIED); - tree_code code = TREE_CODE(type); - - if (unqualified_type == elna_int_type_node) - { - return "Int"; - } - else if (unqualified_type == elna_word_type_node) - { - return "Word"; - } - else if (unqualified_type == elna_bool_type_node) - { - return "Bool"; - } - else if (unqualified_type == elna_pointer_type_node) - { - return "Pointer"; - } - else if (unqualified_type == elna_float_type_node) - { - return "Float"; - } - else if (unqualified_type == elna_char_type_node) - { - return "Char"; - } - else if (is_void_type(unqualified_type)) // For procedures without a return type. - { - return "()"; - } - else if (POINTER_TYPE_P(unqualified_type)) - { - tree pointer_target_type = TREE_TYPE(type); - - if (TREE_CODE(pointer_target_type) == FUNCTION_TYPE) - { - return print_type(pointer_target_type); - } - else - { - return std::string("^" + print_type(pointer_target_type)); - } - } - else if (code == FUNCTION_TYPE) - { - std::string output = "proc("; - tree parameter_type = TYPE_ARG_TYPES(type); - while (TREE_VALUE(parameter_type) != void_type_node) - { - output += print_type(TREE_VALUE(parameter_type)); - parameter_type = TREE_CHAIN(parameter_type); - if (TREE_VALUE(parameter_type) == void_type_node) - { - break; - } - else - { - output += ", "; - } - } - output += ')'; - tree return_type = TREE_TYPE(type); - - if (!is_void_type(return_type)) - { - output += " -> " + print_type(return_type); - } - return output; - } - else if (code == ARRAY_TYPE) - { - return "array"; - } - else if (code == RECORD_TYPE) - { - return print_aggregate_name(unqualified_type, "record"); - } - else if (code == ENUMERAL_TYPE) - { - return print_aggregate_name(unqualified_type, "enumeration"); - } - else - { - return "<<unknown-type>>"; - } - gcc_unreachable(); - } - void report_errors(const std::deque<std::unique_ptr<boot::error>>& errors) { for (const auto& error : errors) diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index 559d09c..1104cf1 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -62,37 +62,22 @@ namespace elna::gcc void generic_visitor::build_assert_builtin(location_t call_location, const std::vector<boot::expression *>& arguments) { - if (arguments.size() != 1) + arguments.at(0)->accept(this); + tree constant_expression = extract_constant(this->current_expression); + + if (constant_expression == boolean_false_node) { - error_at(call_location, "assert expects exactly one boolean argument, got %lu", arguments.size()); - this->current_expression = error_mark_node; + this->current_expression = call_built_in(call_location, "__builtin_unreachable", void_type_node); + } + else if (constant_expression != boolean_true_node) + { + tree assert_expression = call_built_in(call_location, "__builtin_trap", void_type_node); + this->current_expression = build3(COND_EXPR, void_type_node, this->current_expression, + NULL_TREE, assert_expression); } 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) - { - tree assert_expression = call_built_in(call_location, "__builtin_trap", void_type_node); - this->current_expression = build3(COND_EXPR, void_type_node, this->current_expression, - NULL_TREE, assert_expression); - } - else - { - this->current_expression = NULL_TREE; - } + this->current_expression = NULL_TREE; } } @@ -145,18 +130,34 @@ namespace elna::gcc tree cast_target = get_inner_alias(expression->type_decoration, this->symbols); expression->value().accept(this); - tree cast_source = TREE_TYPE(this->current_expression); - - if (is_castable_type(cast_target) && (is_castable_type(cast_source))) - { - this->current_expression = fold_convert_loc(get_location(&expression->position()), - cast_target, this->current_expression); + location_t cast_location = get_location(&expression->position()); + auto source_slice = resolve_underlying_type(expression->value().type_decoration) + .get<boot::slice_type>(); + auto target_slice = resolve_underlying_type(expression->type_decoration) + .get<boot::slice_type>(); + + if (source_slice != nullptr && target_slice != nullptr) + { + tree slice_fields = TYPE_FIELDS(TREE_TYPE(this->current_expression)); + tree ptr = build3_loc(cast_location, COMPONENT_REF, TREE_TYPE(slice_fields), + this->current_expression, slice_fields, NULL_TREE); + tree slice_chain = TREE_CHAIN(slice_fields); + tree old_length = build3_loc(cast_location, COMPONENT_REF, TREE_TYPE(slice_chain), + this->current_expression, slice_chain, NULL_TREE); + + tree source_size = TYPE_SIZE_UNIT(get_inner_alias(source_slice->base, this->symbols)); + tree target_size = TYPE_SIZE_UNIT(get_inner_alias(target_slice->base, this->symbols)); + tree size_ratio = build2(TRUNC_DIV_EXPR, elna_word_type_node, + fold_convert(elna_word_type_node, source_size), + fold_convert(elna_word_type_node, target_size)); + old_length = build2(MULT_EXPR, elna_word_type_node, old_length, size_ratio); + tree new_length = fold_convert(TREE_TYPE(slice_chain), old_length); + + this->current_expression = build_slice(cast_target, ptr, new_length); } else { - error_at(get_location(&expression->position()), "Type '%s' cannot be converted to '%s'", - print_type(cast_source).c_str(), print_type(cast_target).c_str()); - this->current_expression = error_mark_node; + this->current_expression = fold_convert_loc(cast_location, cast_target, this->current_expression); } } @@ -209,7 +210,6 @@ namespace elna::gcc location_t location = get_location(&expression->position()); tree slice_type = get_inner_alias(expression->type_decoration, this->symbols); tree ptr_field = TYPE_FIELDS(slice_type); - tree length_field = TREE_CHAIN(ptr_field); expression->base().accept(this); tree base = this->current_expression; @@ -239,14 +239,10 @@ namespace elna::gcc expression->end().accept(this); tree end_index = fold_convert(elna_word_type_node, this->current_expression); - tree slice_length = build2(MINUS_EXPR, elna_word_type_node, - end_index, start_index); + tree slice_length = build2(MINUS_EXPR, elna_word_type_node, end_index, start_index); slice_length = build2(PLUS_EXPR, elna_word_type_node, slice_length, elna_word_one_node); - vec<constructor_elt, va_gc> *tree_arguments = nullptr; - CONSTRUCTOR_APPEND_ELT(tree_arguments, ptr_field, slice_ptr); - CONSTRUCTOR_APPEND_ELT(tree_arguments, length_field, slice_length); - this->current_expression = build_constructor(slice_type, tree_arguments); + this->current_expression = build_slice(slice_type, slice_ptr, slice_length); } void generic_visitor::visit(boot::unit *unit) @@ -541,11 +537,7 @@ namespace elna::gcc string_literal, integer_zero_node, NULL_TREE, NULL_TREE); string_literal = build1(ADDR_EXPR, ptr_type, string_literal); - vec<constructor_elt, va_gc> *elms = nullptr; - CONSTRUCTOR_APPEND_ELT(elms, ptr_field, string_literal); - CONSTRUCTOR_APPEND_ELT(elms, TREE_CHAIN(ptr_field), index_constant); - - this->current_expression = build_constructor(slice_type, elms); + this->current_expression = build_slice(slice_type, string_literal, index_constant); } void generic_visitor::visit(boot::traits_expression *trait) @@ -783,13 +775,6 @@ namespace elna::gcc location_t location = get_location(&expression->position()); expression->index().accept(this); - if (!is_integral_type(TREE_TYPE(this->current_expression))) - { - error_at(location, "Type '%s' cannot be used as index", - print_type(TREE_TYPE(this->current_expression)).c_str()); - this->current_expression = error_mark_node; - return; - } tree offset = fold_convert(elna_word_type_node, this->current_expression); if (TREE_CODE(TREE_TYPE(designator)) == ARRAY_TYPE) @@ -799,7 +784,7 @@ namespace elna::gcc this->current_expression = build4_loc(location, ARRAY_REF, element_type, designator, offset, elna_word_one_node, NULL_TREE); } - else if (expression->base().type_decoration.get<boot::slice_type>() != nullptr) + else { tree ptr_field = TYPE_FIELDS(TREE_TYPE(designator)); offset = build2(MINUS_EXPR, elna_word_type_node, offset, elna_word_one_node); @@ -810,12 +795,6 @@ namespace elna::gcc this->current_expression = build_simple_mem_ref_loc(location, target_pointer); } - else - { - error_at(location, "Indexing is not allowed on type '%s'", - print_type(TREE_TYPE(designator)).c_str()); - this->current_expression = error_mark_node; - } } void generic_visitor::visit(boot::field_access_expression *expression) @@ -867,19 +846,9 @@ namespace elna::gcc { expression->base().accept(this); location_t expression_location = get_location(&expression->position()); - tree expression_type = TREE_TYPE(this->current_expression); - if (POINTER_TYPE_P(expression_type)) - { - this->current_expression = build_simple_mem_ref_loc(expression_location, - this->current_expression); - } - else - { - error_at(expression_location, "Type '%s' cannot be dereferenced, it is not a pointer", - print_type(expression_type).c_str()); - this->current_expression = error_mark_node; - } + this->current_expression = build_simple_mem_ref_loc(expression_location, + this->current_expression); } void generic_visitor::visit(boot::assign_statement *statement) @@ -892,22 +861,8 @@ namespace elna::gcc statement->rvalue().accept(this); tree rvalue = prepare_rvalue(this->current_expression); - if (TREE_CODE(lvalue) == CONST_DECL) - { - error_at(statement_location, "Cannot modify constant '%s'", - statement->lvalue().is_named()->name.c_str()); - } - else if (TYPE_READONLY(TREE_TYPE(lvalue))) - { - error_at(statement_location, "Cannot modify a constant expression of type '%s'", - print_type(TREE_TYPE(lvalue)).c_str()); - } - else - { - tree assignment = fold_build2_loc(statement_location, MODIFY_EXPR, void_type_node, lvalue, rvalue); - - append_statement(assignment); - } + tree assignment = fold_build2_loc(statement_location, MODIFY_EXPR, void_type_node, lvalue, rvalue); + append_statement(assignment); this->current_expression = NULL_TREE; } diff --git a/gcc/gcc/elna-tree.cc b/gcc/gcc/elna-tree.cc index 352d413..7862eaa 100644 --- a/gcc/gcc/elna-tree.cc +++ b/gcc/gcc/elna-tree.cc @@ -193,37 +193,21 @@ namespace elna::gcc gcc_unreachable(); } - tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name) + tree find_field_by_name(location_t, tree type, const std::string& field_name) { - if (type == error_mark_node) - { - return type; - } - tree field_declaration = TYPE_FIELDS(type); // NOLINTNEXTLINE(readability-simplify-boolean-expr) - if (!RECORD_OR_UNION_TYPE_P(type)) + if (type == error_mark_node || !RECORD_OR_UNION_TYPE_P(type)) { - error_at(expression_location, "Type '%s' does not have a field named '%s'", - print_type(type).c_str(), field_name.c_str()); return error_mark_node; } - while (field_declaration != NULL_TREE) + for (tree field = TYPE_FIELDS(type); field != NULL_TREE; field = TREE_CHAIN(field)) { - tree declaration_name = DECL_NAME(field_declaration); - const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name); - - if (field_name == identifier_pointer) + if (field_name == IDENTIFIER_POINTER(DECL_NAME(field))) { - break; + return field; } - field_declaration = TREE_CHAIN(field_declaration); - } - if (field_declaration == NULL_TREE) - { - error_at(expression_location, "Aggregate type does not have a field '%s'", field_name.c_str()); - return error_mark_node; } - return field_declaration; + return error_mark_node; } tree build_static_array_type(tree type, const std::uint64_t size) @@ -234,6 +218,17 @@ namespace elna::gcc return build_array_type(type, range_type); } + tree build_slice(tree slice_type, tree ptr, tree length) + { + tree ptr_field = TYPE_FIELDS(slice_type); + vec<constructor_elt, va_gc> *elements = nullptr; + + CONSTRUCTOR_APPEND_ELT(elements, ptr_field, ptr); + CONSTRUCTOR_APPEND_ELT(elements, TREE_CHAIN(ptr_field), length); + + return build_constructor(slice_type, elements); + } + tree build_enumeration_type(const std::vector<std::string>& members) { tree composite_type_node = make_node(ENUMERAL_TYPE); |
