diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-08-31 00:49:46 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-08-31 00:49:46 +0200 |
| commit | d905e48d6af0445c7941cd2e638461db2f4d9ee8 (patch) | |
| tree | 7af05b7c798864d745fc3bd831e7227c0a51b567 | |
| parent | 26a1b9ad9f347315bc14f2bf3ee064ede51794fc (diff) | |
| download | elna-d905e48d6af0445c7941cd2e638461db2f4d9ee8.tar.gz | |
Type check for value addressability
| -rw-r--r-- | boot/type_check.cc | 41 | ||||
| -rw-r--r-- | gcc/gcc/elna-builtins.cc | 2 | ||||
| -rw-r--r-- | gcc/gcc/elna-generic.cc | 5 | ||||
| -rw-r--r-- | gcc/gcc/elna-tree.cc | 1 | ||||
| -rw-r--r-- | include/elna/boot/type_check.h | 3 | ||||
| -rw-r--r-- | testsuite/fail_compilation/assign_to_call_result_field.elna | 15 | ||||
| -rw-r--r-- | testsuite/fail_compilation/assign_to_slicing.elna | 7 | ||||
| -rw-r--r-- | testsuite/fail_compilation/reference_call_result_field.elna | 18 | ||||
| -rw-r--r-- | testsuite/fail_compilation/reference_literal.elna | 6 | ||||
| -rw-r--r-- | testsuite/fail_compilation/reference_slicing.elna | 7 |
10 files changed, 95 insertions, 10 deletions
diff --git a/boot/type_check.cc b/boot/type_check.cc index abee91f..5b0547b 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -216,6 +216,9 @@ namespace elna::boot case zero_sized: return "Zero-sized type '" + this->actual.to_string() + "' cannot be declared"; + case not_addressable: + return "Expression of type '" + this->actual.to_string() + + "' is not addressable"; default: __builtin_unreachable(); } @@ -353,6 +356,29 @@ namespace elna::boot return std::nullopt; } + // Checks whether the expression designates a storage location: a named + // expression, a dereference, or a field or array access of an addressable + // base. Slicing produces a value, not a location. + static bool is_addressable(expression& subject) + { + if (auto *designator = subject.is_designator()) + { + if (designator->is_named() != nullptr || designator->is_dereference() != nullptr) + { + return true; + } + else if (auto *field_access = designator->is_field_access()) + { + return is_addressable(field_access->base()); + } + else if (auto *array_access = designator->is_array_access()) + { + return is_addressable(array_access->base()); + } + } + return false; + } + bool type_analysis_visitor::is_equality_compatible(const type& left, const type& right) { auto resolved_left = resolve_underlying_type(left); @@ -614,7 +640,13 @@ namespace elna::boot { walking_visitor::visit(statement); - if (contains_constant_member(statement->lvalue().type_decoration)) + if (!is_addressable(statement->lvalue())) + { + add_error<type_requirement_error>(statement->position(), + statement->lvalue().type_decoration, + type_requirement_error::kind::not_addressable); + } + else if (contains_constant_member(statement->lvalue().type_decoration)) { add_error<type_mismatch_error>(statement->position(), statement->lvalue().type_decoration, type_mismatch_error::constant_assignment{}); @@ -1016,12 +1048,11 @@ namespace elna::boot } else if (operation == unary_operator::reference) { - auto *designator = expression->operand().is_designator(); - if (designator == nullptr || designator->is_slicing() != nullptr) + if (!is_addressable(expression->operand())) { - add_error<type_mismatch_error>(expression->position(), + add_error<type_requirement_error>(expression->position(), expression->operand().type_decoration, - type_mismatch_error::unary{ .operation = operation }); + type_requirement_error::kind::not_addressable); } } } diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc index 3d10c44..18dcc52 100644 --- a/gcc/gcc/elna-builtins.cc +++ b/gcc/gcc/elna-builtins.cc @@ -330,7 +330,6 @@ namespace elna::gcc function_args_iter_next(¶meter_type); } DECL_ARGUMENTS(fndecl) = argument_chain; - TREE_ADDRESSABLE(fndecl) = 1; DECL_EXTERNAL(fndecl) = static_cast<unsigned>(info.is_extern()); TREE_PUBLIC(fndecl) = static_cast<unsigned>(info.exported); } @@ -341,7 +340,6 @@ namespace elna::gcc tree variable_type = get_inner_alias(info.symbol, symbols); tree declaration_tree = build_decl(UNKNOWN_LOCATION, VAR_DECL, get_identifier(name.c_str()), variable_type); - TREE_ADDRESSABLE(declaration_tree) = 1; DECL_EXTERNAL(declaration_tree) = static_cast<unsigned>(info.is_extern); TREE_PUBLIC(declaration_tree) = static_cast<unsigned>(info.exported); diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index 659a8c1..e2d50b4 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -650,8 +650,11 @@ namespace elna::gcc { using enum boot::unary_operator; case reference: + if (DECL_P(this->current_expression)) + { + TREE_ADDRESSABLE(this->current_expression) = 1; + } this->current_expression = prepare_rvalue(this->current_expression); - TREE_ADDRESSABLE(this->current_expression) = 1; this->current_expression = build_fold_addr_expr_with_type_loc(location, this->current_expression, build_pointer_type(TREE_TYPE(this->current_expression))); diff --git a/gcc/gcc/elna-tree.cc b/gcc/gcc/elna-tree.cc index e4c8a20..cddb407 100644 --- a/gcc/gcc/elna-tree.cc +++ b/gcc/gcc/elna-tree.cc @@ -92,7 +92,6 @@ namespace elna::gcc { tree field_declaration = build_decl(location, FIELD_DECL, get_identifier(name.c_str()), type); - TREE_ADDRESSABLE(field_declaration) = 1; DECL_CONTEXT(field_declaration) = record_type; return field_declaration; diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h index 330de44..37a4fca 100644 --- a/include/elna/boot/type_check.h +++ b/include/elna/boot/type_check.h @@ -93,7 +93,8 @@ namespace elna::boot opaque_field, opaque_element, opaque_cast, - zero_sized + zero_sized, + not_addressable }; type_requirement_error(const source_position position, diff --git a/testsuite/fail_compilation/assign_to_call_result_field.elna b/testsuite/fail_compilation/assign_to_call_result_field.elna new file mode 100644 index 0000000..509b2dd --- /dev/null +++ b/testsuite/fail_compilation/assign_to_call_result_field.elna @@ -0,0 +1,15 @@ +type + R = record + x: Int + end + +proc make() -> R +var + result: R +begin + result.x := 1 +return result + +begin + make().x := 5 (* @Error Expression of type 'Int' is not addressable *) +end. diff --git a/testsuite/fail_compilation/assign_to_slicing.elna b/testsuite/fail_compilation/assign_to_slicing.elna new file mode 100644 index 0000000..2266431 --- /dev/null +++ b/testsuite/fail_compilation/assign_to_slicing.elna @@ -0,0 +1,7 @@ +var + s: [3]Int + t: [2]Int + +begin + s[1 to 2] := t[1 to 2] (* @Error Expression of type '\[\]Int' is not addressable *) +end. diff --git a/testsuite/fail_compilation/reference_call_result_field.elna b/testsuite/fail_compilation/reference_call_result_field.elna new file mode 100644 index 0000000..5051cc8 --- /dev/null +++ b/testsuite/fail_compilation/reference_call_result_field.elna @@ -0,0 +1,18 @@ +type + R = record + x: Int + end + +var + p: ^Int + +proc make() -> R +var + result: R +begin + result.x := 1 +return result + +begin + p := @make().x (* @Error Expression of type 'Int' is not addressable *) +end. diff --git a/testsuite/fail_compilation/reference_literal.elna b/testsuite/fail_compilation/reference_literal.elna new file mode 100644 index 0000000..1967243 --- /dev/null +++ b/testsuite/fail_compilation/reference_literal.elna @@ -0,0 +1,6 @@ +var + p: ^Int + +begin + p := @5 (* @Error Expression of type 'Int' is not addressable *) +end. diff --git a/testsuite/fail_compilation/reference_slicing.elna b/testsuite/fail_compilation/reference_slicing.elna new file mode 100644 index 0000000..fac8ec6 --- /dev/null +++ b/testsuite/fail_compilation/reference_slicing.elna @@ -0,0 +1,7 @@ +var + s: [3]Int + p: ^Int + +begin + p := @s[1 to 2] (* @Error Expression of type '\[\]Int' is not addressable *) +end. |
