aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-09-01 01:55:44 +0200
committerEugen Wissner <belka@caraus.de>2026-09-01 01:55:44 +0200
commitb3a7a5731285625aa9fc6a347841591757860edb (patch)
tree94b267ea425a15e7c9bc63c15d8d5580048dd545
parent0f5e9f00b07606871a6289060fa904555d41ae7d (diff)
downloadelna-cpp.tar.gz
Fix const extern variable declarationsHEADcpp
-rw-r--r--boot/name_analysis.cc2
-rw-r--r--boot/type_check.cc28
-rw-r--r--include/elna/boot/type_check.h1
-rw-r--r--testsuite/compilable/const_element_array.elna9
-rw-r--r--testsuite/compilable/const_extern.elna5
-rw-r--r--testsuite/fail_compilation/assign_const_element.elna11
6 files changed, 55 insertions, 1 deletions
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index 70b9031..3c4c6f8 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -420,7 +420,7 @@ namespace elna::boot
non_constant_expression_error::initializer{ extract_identifiers(declaration->identifiers) });
}
}
- else if (resolve_aliases(variable_type).get<constant_type>() != nullptr)
+ else if (!declaration->is_extern && resolve_aliases(variable_type).get<constant_type>() != nullptr)
{
auto position_span = source_position(declaration->identifiers.front().id().position().start(),
declaration->identifiers.back().id().position().end());
diff --git a/boot/type_check.cc b/boot/type_check.cc
index 068d958..74c8176 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -513,12 +513,40 @@ namespace elna::boot
return verdict::pass;
}
+ assign_check::verdict assign_check::check_array_conversion() const
+ {
+ auto assignee_array = ctx.resolved_assignee.get<array_type>();
+ auto assignment_array = ctx.resolved_assignment.get<array_type>();
+
+ if (assignee_array == nullptr || assignment_array == nullptr
+ || assignee_array->size != assignment_array->size)
+ {
+ return verdict::pass;
+ }
+ auto assignee_element_const = resolve_aliases(assignee_array->base).get<constant_type>();
+ auto assignment_element_const = resolve_aliases(assignment_array->base).get<constant_type>();
+
+ // An array is copied by value, so const can be added to the element type,
+ // but not removed. Writing to such an array is rejected on the lvalue.
+ if (assignee_element_const != nullptr
+ && assignee_element_const->unqualified == assignment_array->base)
+ {
+ return verdict::accept;
+ }
+ if (assignment_element_const != nullptr && assignee_element_const == nullptr)
+ {
+ return verdict::reject;
+ }
+ return verdict::pass;
+ }
+
bool assign_check::run()
{
auto const assign_handlers = {
&assign_check::guard_const_laundering,
&assign_check::check_exact_match,
&assign_check::check_slice_conversion,
+ &assign_check::check_array_conversion,
&assign_check::check_pointer_hatch,
&assign_check::check_pointer_conversion
};
diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h
index 37a4fca..e2f5cc9 100644
--- a/include/elna/boot/type_check.h
+++ b/include/elna/boot/type_check.h
@@ -189,6 +189,7 @@ namespace elna::boot
verdict check_pointer_hatch() const;
verdict check_pointer_conversion() const;
verdict check_slice_conversion() const;
+ verdict check_array_conversion() const;
bool run();
};
diff --git a/testsuite/compilable/const_element_array.elna b/testsuite/compilable/const_element_array.elna
new file mode 100644
index 0000000..a812d23
--- /dev/null
+++ b/testsuite/compilable/const_element_array.elna
@@ -0,0 +1,9 @@
+type
+ CI = const Int
+
+var
+ a: [3]CI := [1, 2, 3]
+ b: [3]CI
+
+begin
+end.
diff --git a/testsuite/compilable/const_extern.elna b/testsuite/compilable/const_extern.elna
new file mode 100644
index 0000000..8df801e
--- /dev/null
+++ b/testsuite/compilable/const_extern.elna
@@ -0,0 +1,5 @@
+var
+ errno_like: const Int := extern
+
+begin
+end.
diff --git a/testsuite/fail_compilation/assign_const_element.elna b/testsuite/fail_compilation/assign_const_element.elna
new file mode 100644
index 0000000..9b9c341
--- /dev/null
+++ b/testsuite/fail_compilation/assign_const_element.elna
@@ -0,0 +1,11 @@
+type
+ CI = const Int
+
+proc f()
+var
+ a: [3]CI := [1, 2, 3]
+begin
+ a[1] := 6 (* @Error Cannot assign to a value of type 'CI', because it is constant or contains constant members *)
+return
+
+end.