From 0f5e9f00b07606871a6289060fa904555d41ae7d Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 31 Aug 2026 17:18:39 +0200 Subject: Reject comparison of uncompatible types --- gcc/gcc/elna-builtins.cc | 19 +++++++++--- gcc/gcc/elna-generic.cc | 72 +++++++++++++------------------------------ gcc/gcc/elna-module-loader.cc | 8 ++--- gcc/gcc/elna-tree.cc | 39 +++++++++++++---------- 4 files changed, 63 insertions(+), 75 deletions(-) (limited to 'gcc') diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc index 18dcc52..23315e5 100644 --- a/gcc/gcc/elna-builtins.cc +++ b/gcc/gcc/elna-builtins.cc @@ -16,6 +16,7 @@ along with GCC; see the file COPYING3. If not see . */ #include "elna/gcc/elna-builtins.h" +#include "elna/gcc/elna-diagnostic.h" #include "elna/gcc/elna1.h" #include "stor-layout.h" #include "stringpool.h" @@ -304,7 +305,11 @@ namespace elna::gcc const std::shared_ptr& symbols) { tree declaration_type = gcc::build_procedure_type(info.symbol, symbols); - tree fndecl = build_fn_decl(name.c_str(), declaration_type); + const location_t location = info.position.has_value() + ? get_location(&info.position.value()) + : UNKNOWN_LOCATION; + tree fndecl = build_decl(location, FUNCTION_DECL, + get_identifier(name.c_str()), declaration_type); symbols->enter(name, fndecl); if (info.symbol.return_type.no_return) @@ -330,8 +335,11 @@ namespace elna::gcc function_args_iter_next(¶meter_type); } DECL_ARGUMENTS(fndecl) = argument_chain; + // Elna has no exceptions. + TREE_NOTHROW(fndecl) = 1; DECL_EXTERNAL(fndecl) = static_cast(info.is_extern()); - TREE_PUBLIC(fndecl) = static_cast(info.exported); + // An extern procedure has C linkage whether or not Elna re-exports the name. + TREE_PUBLIC(fndecl) = static_cast(info.exported || info.is_extern()); } tree declare_variable(const std::string& name, const boot::variable_info& info, @@ -361,7 +369,7 @@ namespace elna::gcc } void rewrite_symbol_table(const std::shared_ptr& info_table, - const std::shared_ptr& symbols) + const std::shared_ptr& symbols, const bool imported) { for (auto& [symbol_name, symbol_info] : *info_table) { @@ -371,7 +379,10 @@ namespace elna::gcc } else if (auto variable_info = symbol_info->is_variable()) { - declare_variable(symbol_name, *variable_info, symbols); + tree declaration_tree = declare_variable(symbol_name, *variable_info, symbols); + + DECL_EXTERNAL(declaration_tree) = + static_cast(imported || variable_info->is_extern); } else if (auto procedure_info = symbol_info->is_procedure()) { diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index e2d50b4..fb68136 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -176,8 +176,7 @@ namespace elna::gcc for (const boot::field_initializer& initializer : expression->field_initializers) { - tree field_decl = find_field_by_name(get_location(&expression->position()), - record_type, initializer.name()); + tree field_decl = find_field_by_name(record_type, initializer.name()); initializer.value().accept(this); // NOLINTNEXTLINE(misc-const-correctness) CONSTRUCTOR_APPEND_ELT(tree_arguments, field_decl, this->current_expression); @@ -474,8 +473,6 @@ namespace elna::gcc DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping); DECL_SAVED_TREE(fndecl) = mapping; - DECL_PRESERVE_P(fndecl) = 1; - dump_function(TDI_original, fndecl); pop_cfun(); @@ -720,8 +717,7 @@ namespace elna::gcc if (lang_hooks.decls.global_bindings_p()) { - TREE_STATIC(declaration_tree) = - static_cast(!variable_identifier.exported() && !declaration->is_extern); + TREE_STATIC(declaration_tree) = static_cast(!declaration->is_extern); varpool_node::get_create(declaration_tree); varpool_node::finalize_decl(declaration_tree); } @@ -741,14 +737,9 @@ namespace elna::gcc { tree symbol = this->symbols->lookup(expression->name); - if (symbol == NULL_TREE) - { - this->current_expression = error_mark_node; - } - else - { - this->current_expression = symbol; - } + // Name analysis rejects an undeclared name. + gcc_assert(symbol != NULL_TREE); + this->current_expression = symbol; } void generic_visitor::visit(boot::array_access_expression *expression) @@ -813,15 +804,12 @@ namespace elna::gcc } else { - tree field_declaration = find_field_by_name(expression_location, + tree field_declaration = find_field_by_name( TREE_TYPE(this->current_expression), expression->field().name()); - if (field_declaration != error_mark_node) - { - this->current_expression = build3_loc(expression_location, COMPONENT_REF, - TREE_TYPE(field_declaration), this->current_expression, - field_declaration, NULL_TREE); - } + this->current_expression = build3_loc(expression_location, COMPONENT_REF, + TREE_TYPE(field_declaration), this->current_expression, + field_declaration, NULL_TREE); } } @@ -866,10 +854,7 @@ namespace elna::gcc } result = make_if_branch(statement->branch(), result); - if (result != error_mark_node) - { - append_statement(result); - } + append_statement(result); this->current_expression = NULL_TREE; } @@ -1010,16 +995,13 @@ namespace elna::gcc } result = make_if_branch(statement->branch(), result, goto_check); - if (result != error_mark_node) - { - tree check_label_expr = build1_loc(prerequisite_location, LABEL_EXPR, - void_type_node, while_check_label); - tree end_label_expr = build1(LABEL_EXPR, void_type_node, while_end_label); + tree check_label_expr = build1_loc(prerequisite_location, LABEL_EXPR, + void_type_node, while_check_label); + tree end_label_expr = build1(LABEL_EXPR, void_type_node, while_end_label); - append_statement(check_label_expr); - append_statement(result); - append_statement(end_label_expr); - } + append_statement(check_label_expr); + append_statement(result); + append_statement(end_label_expr); this->current_expression = NULL_TREE; } @@ -1077,7 +1059,7 @@ namespace elna::gcc case_label->accept(this); const location_t case_location = get_location(&case_label->position()); - assert_constant(case_location); + assert_constant(); tree case_label_declaration = create_artificial_label(case_location); tree case_expression = build_case_label(this->current_expression, NULL_TREE, case_label_declaration); @@ -1130,10 +1112,7 @@ namespace elna::gcc for (boot::expression *const case_label : case_block.labels) { case_label->accept(this); - if (!assert_constant(get_location(&case_label->position()))) - { - continue; - } + assert_constant(); tree label_comparison = build_equality_comparison(get_location(&case_label->position()), condition_value, this->current_expression, statement->condition().type_decoration, EQ_EXPR); @@ -1153,19 +1132,12 @@ namespace elna::gcc } } - bool generic_visitor::assert_constant(location_t expression_location) + void generic_visitor::assert_constant() { tree constant_expression = extract_constant(this->current_expression); - if (constant_expression == NULL_TREE) - { - error_at(expression_location, "Expected a constant expression"); - this->current_expression = error_mark_node; - } - else - { - this->current_expression = constant_expression; - } - return this->current_expression != error_mark_node; + // Type checking rejects a case label that is not a constant expression. + gcc_assert(constant_expression != NULL_TREE); + this->current_expression = constant_expression; } } diff --git a/gcc/gcc/elna-module-loader.cc b/gcc/gcc/elna-module-loader.cc index 8827a1e..5852bbe 100644 --- a/gcc/gcc/elna-module-loader.cc +++ b/gcc/gcc/elna-module-loader.cc @@ -78,9 +78,9 @@ namespace elna::gcc } void module_loader::finalize(const std::filesystem::path&, - const std::shared_ptr& module_scope) const + const std::shared_ptr& module_scope, const bool imported) const { - rewrite_symbol_table(module_scope, this->symbols); + rewrite_symbol_table(module_scope, this->symbols, imported); } void compile_files(const char *const *filenames, unsigned int count) @@ -99,9 +99,9 @@ namespace elna::gcc report_errors(diagnostics); } - if (result.value != nullptr) + if (result.value != nullptr && result.errors.empty()) { - linemap_add(line_table, LC_ENTER, 0, key.native().c_str(), 1); + linemap_add(line_table, LC_ENTER, 0, ggc_strdup(key.native().c_str()), 1); generic_visitor visitor{ state.custom, state.find(key)->second, target }; result.value->accept(&visitor); linemap_add(line_table, LC_LEAVE, 0, nullptr, 0); diff --git a/gcc/gcc/elna-tree.cc b/gcc/gcc/elna-tree.cc index cddb407..7aa4012 100644 --- a/gcc/gcc/elna-tree.cc +++ b/gcc/gcc/elna-tree.cc @@ -97,6 +97,14 @@ namespace elna::gcc return field_declaration; } + // The generic Pointer has no pointee size; it advances byte by byte. + static tree pointer_stride(tree pointer_type, tree offset_type) + { + return pointer_type == elna_pointer_type_node + ? size_one_node + : fold_convert(offset_type, size_in_bytes(TREE_TYPE(pointer_type))); + } + tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right, location_t operation_location) { @@ -124,9 +132,7 @@ namespace elna::gcc { return error_mark_node; } - tree size_exp = pointer_type == elna_pointer_type_node - ? size_one_node - : fold_convert(TREE_TYPE(offset), size_in_bytes(TREE_TYPE(TREE_TYPE(pointer)))); + tree size_exp = pointer_stride(pointer_type, TREE_TYPE(offset)); offset = fold_build2(MULT_EXPR, TREE_TYPE(offset), offset, size_exp); offset = fold_convert(size_type_node, offset); @@ -139,7 +145,7 @@ namespace elna::gcc { tree pointer_type = left_type; tree offset_type = right_type; - tree size_exp = fold_convert(offset_type, size_in_bytes(TREE_TYPE(pointer_type))); + tree size_exp = pointer_stride(pointer_type, offset_type); tree convert_expression = fold_build2(MULT_EXPR, offset_type, right, size_exp); convert_expression = fold_convert(size_type_node, convert_expression); @@ -156,13 +162,11 @@ namespace elna::gcc gcc_unreachable(); } - tree find_field_by_name(location_t, tree type, const std::string& field_name) + tree find_field_by_name(tree type, const std::string& field_name) { - // NOLINTNEXTLINE(readability-simplify-boolean-expr) - if (type == error_mark_node || !RECORD_OR_UNION_TYPE_P(type)) - { - return error_mark_node; - } + // Name analysis rejects a field the record does not have. + gcc_assert(RECORD_OR_UNION_TYPE_P(type)); + for (tree field = TYPE_FIELDS(type); field != NULL_TREE; field = TREE_CHAIN(field)) { if (field_name == IDENTIFIER_POINTER(DECL_NAME(field))) @@ -170,7 +174,7 @@ namespace elna::gcc return field; } } - return error_mark_node; + gcc_unreachable(); } tree build_static_array_type(tree type, const std::uint64_t size) @@ -233,8 +237,13 @@ namespace elna::gcc tree extract_constant(tree expression) { const int code = TREE_CODE(expression); + // A mutable variable can have a constant initializer too, so readonly is + // what marks one whose value is known at compile time. + const bool constant_variable = code == VAR_DECL && TREE_READONLY(expression) + && DECL_INITIAL(expression) != NULL_TREE + && TREE_CONSTANT(DECL_INITIAL(expression)); - if (code == CONST_DECL) + if (code == CONST_DECL || constant_variable) { return DECL_INITIAL(expression); } @@ -333,11 +342,7 @@ namespace elna::gcc for (const auto& [field_name, field_value] : fields) { - tree field_decl = find_field_by_name(UNKNOWN_LOCATION, type, field_name); - if (field_decl == error_mark_node) - { - return NULL_TREE; - } + tree field_decl = find_field_by_name(type, field_name); tree value_tree = constant_to_tree(field_value, symbols, TREE_TYPE(field_decl)); if (value_tree == NULL_TREE) { -- cgit v1.2.3