aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot/type_check.cc41
-rw-r--r--gcc/gcc/elna-builtins.cc2
-rw-r--r--gcc/gcc/elna-generic.cc5
-rw-r--r--gcc/gcc/elna-tree.cc1
-rw-r--r--include/elna/boot/type_check.h3
-rw-r--r--testsuite/fail_compilation/assign_to_call_result_field.elna15
-rw-r--r--testsuite/fail_compilation/assign_to_slicing.elna7
-rw-r--r--testsuite/fail_compilation/reference_call_result_field.elna18
-rw-r--r--testsuite/fail_compilation/reference_literal.elna6
-rw-r--r--testsuite/fail_compilation/reference_slicing.elna7
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(&parameter_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.