aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-29 01:16:18 +0200
committerEugen Wissner <belka@caraus.de>2026-07-29 01:16:18 +0200
commitf8daedce5c73e02dfb2fc59d75777190185584df (patch)
tree9ec211b96c3d7efd2fca0da37baeaa8b341e31fb /gcc
parent36a274c9a8bca944234589220def025d3920b3ef (diff)
downloadelna-f8daedce5c73e02dfb2fc59d75777190185584df.tar.gz
Validate cast compatibility during semantic analysis
Diffstat (limited to 'gcc')
-rw-r--r--gcc/gcc/elna-diagnostic.cc107
-rw-r--r--gcc/gcc/elna-generic.cc135
-rw-r--r--gcc/gcc/elna-tree.cc39
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);