From 44a0c221d51c9aa036b47b218a6caea4424f5996 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 17 Jul 2026 13:49:20 +0200 Subject: Handle const Pointer as const pointer to const data --- include/elna/boot/name_analysis.h | 153 ++++++++++++++++++ include/elna/boot/semantic.h | 324 -------------------------------------- include/elna/boot/type_check.h | 225 ++++++++++++++++++++++++++ include/elna/gcc/elna-generic.h | 1 - 4 files changed, 378 insertions(+), 325 deletions(-) create mode 100644 include/elna/boot/name_analysis.h delete mode 100644 include/elna/boot/semantic.h create mode 100644 include/elna/boot/type_check.h (limited to 'include') diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h new file mode 100644 index 0000000..4498d0c --- /dev/null +++ b/include/elna/boot/name_analysis.h @@ -0,0 +1,153 @@ +/* Name analysis. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#pragma once + +#include +#include +#include + +#include "elna/boot/ast.h" +#include "elna/boot/result.h" +#include "elna/boot/symbol.h" +#include "elna/boot/type_check.h" + +namespace elna::boot +{ + /** + * Error declaring a symbol. + */ + class declaration_error : public error + { + public: + enum class kind + { + undeclared, + local_export + }; + + private: + std::string identifier; + kind error_kind; + + public: + + declaration_error(const kind error_kind, + const boot::identifier& identifier); + + std::string what() const override; + }; + + /** + * Attempted to redefine a name that is already in use in the + * current scope. + */ + class redefinition_error : public error + { + std::string identifier; + std::optional original; + + public: + redefinition_error(const boot::identifier& identifier, + std::optional original); + + std::string what() const override; + + std::optional> note() const override; + }; + + /** + * Origin of a field in a composite type. + */ + struct field_origin + { + std::optional declaration; + type base_type; + }; + + /** + * Performs name analysis. + */ + class name_analysis_visitor final : public walking_visitor, public error_container + { + type current_type; + + symbol_bag bag; + + std::pair> build_procedure( + procedure_type_expression& expression); + std::vector build_composite_type(const std::vector& fields, + std::map& known_names, + type aggregate); + std::shared_ptr register_variable(const std::string& name, + const bool is_extern, const source_position position); + + type lookup_primitive_type(const std::string& name); + type lookup_field(const type& composite_type, const std::string& field_name); + + public: + name_analysis_visitor(symbol_bag bag); + + void visit(array_type_expression *expression) override; + void visit(pointer_type_expression *expression) override; + void visit(constant_type_expression *expression) override; + void visit(type_declaration *declaration) override; + void visit(record_type_expression *expression) override; + void visit(record_constructor_expression *expression) override; + void visit(array_constructor_expression *expression) override; + void visit(procedure_type_expression *expression) override; + void visit(enumeration_type_expression *expression) override; + + void visit(variable_declaration *declaration) override; + void visit(procedure_declaration *declaration) override; + + void visit(procedure_call *call) override; + void visit(unit *unit) override; + void visit(cast_expression *expression) override; + void visit(traits_expression *trait) override; + void visit(binary_expression *expression) override; + void visit(unary_expression *expression) override; + void visit(named_expression *expression) override; + void visit(array_access_expression *expression) override; + void visit(field_access_expression *expression) override; + void visit(dereference_expression *expression) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + }; + + /** + * Collects global declarations without resolving any symbols. + */ + class declaration_visitor final : public empty_visitor, public error_container + { + public: + forward_table unresolved; + + explicit declaration_visitor(); + + void visit(import_declaration *) override; + void visit(unit *unit) override; + void visit(type_declaration *declaration) override; + void visit(procedure_declaration *declaration) override; + void visit(variable_declaration *declaration) override; + }; +} diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h deleted file mode 100644 index 3d2de10..0000000 --- a/include/elna/boot/semantic.h +++ /dev/null @@ -1,324 +0,0 @@ -/* Name analysis. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#pragma once - -#include -#include -#include - -#include "elna/boot/ast.h" -#include "elna/boot/result.h" -#include "elna/boot/symbol.h" - -namespace elna::boot -{ - /** - * Error declaring a symbol. - */ - class declaration_error : public error - { - public: - enum class kind - { - undeclared, - local_export - }; - - private: - std::string identifier; - kind error_kind; - - public: - - declaration_error(const kind error_kind, - const boot::identifier& identifier); - - std::string what() const override; - }; - - /** - * Attempted to redefine a name that is already in use in the - * current scope. - */ - class redefinition_error : public error - { - std::string identifier; - std::optional original; - - public: - redefinition_error(const boot::identifier& identifier, - std::optional original); - - std::string what() const override; - - std::optional> note() const override; - }; - - /** - * Expected type does not match the actual type of an expression. - */ - class type_mismatch_error : public error - { - type expected; - type actual; - - public: - type_mismatch_error(const source_position position, - type expected, type actual); - - std::string what() const override; - }; - - /** - * Attempted to assign a value whose type contains constant members. - */ - class constant_assignment_error : public error - { - type assignee; - - public: - constant_assignment_error(const source_position position, type assignee); - - std::string what() const override; - }; - - /** - * Attempted to access a field that does not exist on the given type. - */ - class field_not_found_error : public error - { - std::string field_name; - type composite_type; - - public: - field_not_found_error(const identifier& field_name, - type composite_type); - - std::string what() const override; - }; - - /** - * Field with the same name is already declared in this type. - */ - class duplicate_member_error : public error - { - std::string member_name; - type aggregate; - std::optional original; - std::optional base_name; - - public: - duplicate_member_error(const boot::identifier& member_name, - type aggregate, std::optional original = std::nullopt, - std::optional base_name = std::nullopt); - - std::string what() const override; - - std::optional> note() const override; - }; - - /** - * Cyclic type declaration. - */ - class cyclic_declaration_error : public error - { - std::vector cycle; - - public: - cyclic_declaration_error(const std::vector& cycle, const source_position position); - - std::string what() const override; - }; - - /** - * Procedure with a return type does not return. - */ - class return_error : public error - { - std::string identifier; - type return_type; - - public: - return_error(const std::string& identifier, const source_position position, - type return_type = type()); - - std::string what() const override; - }; - - /** - * Base type of a record is not a record. - */ - class base_type_error : public error - { - type actual; - - public: - base_type_error(type actual, const source_position position); - - std::string what() const override; - }; - - /** - * Argument count in a procedure or record call doesn't match - * the expected number of parameters or fields. - */ - class argument_count_error : public error - { - std::size_t expected; - std::size_t actual; - - public: - argument_count_error(std::size_t expected, std::size_t actual, - const source_position position); - - std::string what() const override; - }; - - /** - * Type passed to a trait like #min or #max does not support - * the trait. - */ - class unsupported_trait_type_error : public error - { - type actual; - std::string trait_name; - - public: - unsupported_trait_type_error(const identifier& trait, type actual); - - std::string what() const override; - }; - - /** - * Checks types. - */ - class type_analysis_visitor final : public walking_visitor, public error_container - { - symbol_bag bag; - std::shared_ptr current_procedure; - - /* - * Whether an expression of type assignment can be assigned to a variable - * of type assignee. - */ - static bool is_assignable_from(const type& assignee, const type& assignment); - /* - * Checks whether derived has base in its parent chain. - * base should not be null, derived can be null. - */ - static bool is_base_of(const std::shared_ptr& base, - const std::shared_ptr& derived); - static bool check_unresolved_symbol(std::shared_ptr alias, - std::vector& path); - - public: - explicit type_analysis_visitor(symbol_bag bag); - - void visit(procedure_declaration *declaration) override; - void visit(unit *unit) override; - void visit(assign_statement *statement) override; - void visit(variable_declaration *declaration) override; - void visit(type_declaration *declaration) override; - void visit(record_type_expression *expression) override; - void visit(procedure_call *call) override; - void visit(case_statement *statement) override; - void visit(record_constructor_expression *expression) override; - void visit(array_constructor_expression *expression) override; - }; - - /** - * Origin of a field in a composite type. - */ - struct field_origin - { - std::optional declaration; - type base_type; - }; - - /** - * Performs name analysis. - */ - class name_analysis_visitor final : public walking_visitor, public error_container - { - type current_type; - - symbol_bag bag; - - std::pair> build_procedure( - procedure_type_expression& expression); - std::vector build_composite_type(const std::vector& fields, - std::map& known_names, - type aggregate); - std::shared_ptr register_variable(const std::string& name, - const bool is_extern, const source_position position); - - type lookup_primitive_type(const std::string& name); - type lookup_field(const type& composite_type, const std::string& field_name); - - public: - name_analysis_visitor(symbol_bag bag); - - void visit(array_type_expression *expression) override; - void visit(pointer_type_expression *expression) override; - void visit(constant_type_expression *expression) override; - void visit(type_declaration *declaration) override; - void visit(record_type_expression *expression) override; - void visit(record_constructor_expression *expression) override; - void visit(array_constructor_expression *expression) override; - void visit(procedure_type_expression *expression) override; - void visit(enumeration_type_expression *expression) override; - - void visit(variable_declaration *declaration) override; - void visit(procedure_declaration *declaration) override; - - void visit(procedure_call *call) override; - void visit(unit *unit) override; - void visit(cast_expression *expression) override; - void visit(traits_expression *trait) override; - void visit(binary_expression *expression) override; - void visit(unary_expression *expression) override; - void visit(named_expression *expression) override; - void visit(array_access_expression *expression) override; - void visit(field_access_expression *expression) override; - void visit(dereference_expression *expression) override; - void visit(literal *literal) override; - void visit(literal *literal) override; - void visit(literal *literal) override; - void visit(literal *literal) override; - void visit(literal *literal) override; - void visit(literal *literal) override; - void visit(literal *literal) override; - }; - - /** - * Collects global declarations without resolving any symbols. - */ - class declaration_visitor final : public empty_visitor, public error_container - { - public: - forward_table unresolved; - - explicit declaration_visitor(); - - void visit(import_declaration *) override; - void visit(unit *unit) override; - void visit(type_declaration *declaration) override; - void visit(procedure_declaration *declaration) override; - void visit(variable_declaration *declaration) override; - }; -} diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h new file mode 100644 index 0000000..b250f48 --- /dev/null +++ b/include/elna/boot/type_check.h @@ -0,0 +1,225 @@ +/* Type analysis. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#pragma once + +#include +#include +#include + +#include "elna/boot/ast.h" +#include "elna/boot/result.h" +#include "elna/boot/symbol.h" + +namespace elna::boot +{ + /** + * Expected type does not match the actual type of an expression. + */ + class type_mismatch_error : public error + { + type expected; + type actual; + + public: + type_mismatch_error(const source_position position, + type expected, type actual); + + std::string what() const override; + }; + + /** + * Attempted to assign a value whose type contains constant members. + */ + class constant_assignment_error : public error + { + type assignee; + + public: + constant_assignment_error(const source_position position, type assignee); + + std::string what() const override; + }; + + /** + * Attempted to access a field that does not exist on the given type. + */ + class field_not_found_error : public error + { + std::string field_name; + type composite_type; + + public: + field_not_found_error(const identifier& field_name, + type composite_type); + + std::string what() const override; + }; + + /** + * Field with the same name is already declared in this type. + */ + class duplicate_member_error : public error + { + std::string member_name; + type aggregate; + std::optional original; + std::optional base_name; + + public: + duplicate_member_error(const boot::identifier& member_name, + type aggregate, std::optional original = std::nullopt, + std::optional base_name = std::nullopt); + + std::string what() const override; + + std::optional> note() const override; + }; + + /** + * Cyclic type declaration. + */ + class cyclic_declaration_error : public error + { + std::vector cycle; + + public: + cyclic_declaration_error(const std::vector& cycle, const source_position position); + + std::string what() const override; + }; + + /** + * Procedure with a return type does not return. + */ + class return_error : public error + { + std::string identifier; + type return_type; + + public: + return_error(const std::string& identifier, const source_position position, + type return_type = type()); + + std::string what() const override; + }; + + /** + * Base type of a record is not a record. + */ + class base_type_error : public error + { + type actual; + + public: + base_type_error(type actual, const source_position position); + + std::string what() const override; + }; + + /** + * Argument count in a procedure or record call doesn't match + * the expected number of parameters or fields. + */ + class argument_count_error : public error + { + std::size_t expected; + std::size_t actual; + + public: + argument_count_error(std::size_t expected, std::size_t actual, + const source_position position); + + std::string what() const override; + }; + + /** + * Type passed to a trait like #min or #max does not support + * the trait. + */ + class unsupported_trait_type_error : public error + { + type actual; + std::string trait_name; + + public: + unsupported_trait_type_error(const identifier& trait, type actual); + + std::string what() const override; + }; + + /** + * Chain of responsibility for type compatibility checks. + * + * Populate \c ctx with pre-resolved types, then call \c run(). + * Each handler inspects the context and returns a verdict — + * the first non-\c pass verdict wins. + */ + struct assign_check + { + enum class verdict { pass, accept, reject }; + + struct context + { + type aliased_assignee; + type aliased_assignment; + type resolved_assignee; + type resolved_assignment; + }; + context ctx; + + verdict guard_const_laundering(); + verdict check_exact_match(); + verdict check_pointer_hatch(); + verdict check_pointer_conversion(); + + bool run(); + }; + + /** + * Checks types: assignment compatibility, const-correctness, + * procedure argument counts, record field validity, + * and type declaration well-formedness. + */ + class type_analysis_visitor final : public walking_visitor, public error_container + { + symbol_bag bag; + std::shared_ptr current_procedure; + + /* + * Whether an expression of type assignment can be assigned to a variable + * of type assignee. + */ + static bool is_assignable_from(const type& assignee, const type& assignment); + static bool check_unresolved_symbol(std::shared_ptr alias, + std::vector& path); + + public: + explicit type_analysis_visitor(symbol_bag bag); + + void visit(procedure_declaration *declaration) override; + void visit(unit *unit) override; + void visit(assign_statement *statement) override; + void visit(variable_declaration *declaration) override; + void visit(type_declaration *declaration) override; + void visit(record_type_expression *expression) override; + void visit(procedure_call *call) override; + void visit(case_statement *statement) override; + void visit(record_constructor_expression *expression) override; + void visit(array_constructor_expression *expression) override; + }; +} diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index a1689be..dd5c9ef 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -20,7 +20,6 @@ along with GCC; see the file COPYING3. If not see #include #include "elna/boot/ast.h" #include "elna/boot/symbol.h" -#include "elna/boot/semantic.h" #include "elna/gcc/elna-tree.h" #include "config.h" -- cgit v1.2.3