diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-07-24 21:28:33 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-07-25 02:22:34 +0200 |
| commit | 1e0f89df48ba10cdde80bd623b84e20fb48b977d (patch) | |
| tree | 58f550342ff7ef42e506131b5c04a35ffdeb4a00 /gcc | |
| parent | 6301c1f2f669b84a429e836888629873721e7219 (diff) | |
| download | elna-1e0f89df48ba10cdde80bd623b84e20fb48b977d.tar.gz | |
Accept any constant types in case labels
Diffstat (limited to 'gcc')
| -rw-r--r-- | gcc/gcc/elna-builtins.cc | 4 | ||||
| -rw-r--r-- | gcc/gcc/elna-generic.cc | 108 | ||||
| -rw-r--r-- | gcc/gcc/elna-tree.cc | 2 | ||||
| -rw-r--r-- | gcc/gcc/elna1.cc | 4 |
4 files changed, 88 insertions, 30 deletions
diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc index 57d2875..6ea8874 100644 --- a/gcc/gcc/elna-builtins.cc +++ b/gcc/gcc/elna-builtins.cc @@ -65,8 +65,8 @@ namespace elna::gcc return builtin_table; } - tree build_composite_type(const std::vector<boot::type_field>& fields, tree composite_type_node, - std::shared_ptr<symbol_table> symbols) + tree build_composite_type(const boot::ordered_map<boot::type>& fields, + tree composite_type_node, std::shared_ptr<symbol_table> symbols) { for (auto& field : fields) { diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index c462924..f77f371 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -429,6 +429,14 @@ namespace elna::gcc { return null_pointer_node; } + else if (std::holds_alternative<boot::constant_aggregate<boot::ordered_map>>(constant_value)) + { + return NULL_TREE; // Compound constants are not lowered to trees yet. + } + else if (std::holds_alternative<boot::constant_aggregate<std::vector>>(constant_value)) + { + return NULL_TREE; // Compound constants are not lowered to trees yet. + } return NULL_TREE; } @@ -498,26 +506,33 @@ namespace elna::gcc this->current_expression = build_constructor(slice_type, elms); } - tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree left, tree right) + tree generic_visitor::build_equality(boot::binary_expression *expression, tree left, tree right) { - location_t expression_location = get_location(&expression->position()); - tree_code equality_code, combination_code; + tree_code equality_code; if (expression->operation() == boot::binary_operator::equals) { equality_code = EQ_EXPR; - combination_code = TRUTH_ANDIF_EXPR; } else if (expression->operation() == boot::binary_operator::not_equals) { equality_code = NE_EXPR; - combination_code = TRUTH_ORIF_EXPR; } else { gcc_unreachable(); } - if (expression->lhs().type_decoration.get<boot::slice_type>() != nullptr) + return build_equality_comparison(get_location(&expression->position()), left, right, + expression->lhs().type_decoration, equality_code); + } + + tree generic_visitor::build_equality_comparison(location_t loc, tree left, tree right, + const boot::type& left_type, tree_code equality_code) + { + tree_code combination_code = equality_code == EQ_EXPR + ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; + + if (left_type.get<boot::slice_type>() != nullptr) { tree lhs_ptr_field = TYPE_FIELDS(TREE_TYPE(left)); tree lhs_length_field = TREE_CHAIN(lhs_ptr_field); @@ -543,22 +558,20 @@ namespace elna::gcc return build2(combination_code, elna_bool_type_node, length_equality, equals_zero); } - else if (expression->lhs().type_decoration.get<boot::record_type>() != nullptr - || expression->lhs().type_decoration.get<boot::array_type>() != nullptr) + else if (left_type.get<boot::record_type>() != nullptr + || left_type.get<boot::array_type>() != nullptr) { tree size = fold_convert(elna_word_type_node, size_in_bytes(TREE_TYPE(left))); - tree lhs_addr = build1(ADDR_EXPR, - build_pointer_type(TREE_TYPE(left)), left); - tree rhs_addr = build1(ADDR_EXPR, - build_pointer_type(TREE_TYPE(right)), right); + tree lhs_addr = build1(ADDR_EXPR, build_pointer_type(TREE_TYPE(left)), left); + tree rhs_addr = build1(ADDR_EXPR, build_pointer_type(TREE_TYPE(right)), right); tree memcmp_call = call_built_in(UNKNOWN_LOCATION, "__builtin_memcmp", integer_type_node, lhs_addr, rhs_addr, size); return build2(equality_code, elna_bool_type_node, memcmp_call, integer_zero_node); } else { - return build2_loc(expression_location, equality_code, elna_bool_type_node, left, right); + return build2_loc(loc, equality_code, elna_bool_type_node, left, right); } } @@ -574,9 +587,11 @@ namespace elna::gcc location_t expression_location = get_location(&expression->position()); + const bool is_pointer_arithmetic_operation + = expression->operation() == boot::binary_operator::sum + || expression->operation() == boot::binary_operator::subtraction; if ((POINTER_TYPE_P(left_type) || POINTER_TYPE_P(right_type)) - && (expression->operation() == boot::binary_operator::sum - || expression->operation() == boot::binary_operator::subtraction)) + && is_pointer_arithmetic_operation) { this->current_expression = do_pointer_arithmetic(expression->operation(), left, right, expression_location); @@ -655,7 +670,7 @@ namespace elna::gcc break; case equals: case not_equals: - this->current_expression = build_equality_operation(expression, left, right); + this->current_expression = build_equality(expression, left, right); break; case shift_left: this->current_expression = fold_build2_loc(expression_location, @@ -1247,16 +1262,21 @@ namespace elna::gcc { statement->condition().accept(this); tree condition_expression = this->current_expression; - tree unqualified_condition = get_qualified_type(TREE_TYPE(this->current_expression), TYPE_UNQUALIFIED); + tree unqualified_condition = get_qualified_type(TREE_TYPE(condition_expression), TYPE_UNQUALIFIED); - if (!INTEGRAL_TYPE_P(unqualified_condition)) + if (INTEGRAL_TYPE_P(unqualified_condition)) { - error_at(get_location(&statement->condition().position()), - "Case expressions can only be integral numbers, characters and enumerations, given '%s'", - print_type(unqualified_condition).c_str()); - this->current_expression = NULL_TREE; - return; + build_case_integral(statement, condition_expression); } + else + { + build_case_general(statement, condition_expression); + } + this->current_expression = NULL_TREE; + } + + void generic_visitor::build_case_integral(boot::case_statement *statement, tree condition_expression) + { tree end_label_declaration = create_artificial_label(get_location(&statement->position())); tree switch_statements = alloc_stmt_list(); @@ -1296,13 +1316,51 @@ namespace elna::gcc } tree switch_expression = build2(SWITCH_EXPR, TREE_TYPE(condition_expression), condition_expression, switch_statements); - append_statement(switch_expression); tree end_label_expression = build1(LABEL_EXPR, void_type_node, end_label_declaration); append_statement(end_label_expression); + } - this->current_expression = NULL_TREE; + void generic_visitor::build_case_general(boot::case_statement *statement, tree condition_expression) + { + tree condition_value = build1(SAVE_EXPR, TREE_TYPE(condition_expression), condition_expression); + + // Build from the bottom up: else branch first. + tree result = NULL_TREE; + if (statement->alternative != nullptr) + { + enter_scope(); + visit_statements(*statement->alternative); + result = leave_scope(); + } + for (const boot::switch_case& case_block : statement->cases | std::views::reverse) + { + tree case_condition = boolean_false_node; + for (boot::expression *const case_label : case_block.labels) + { + case_label->accept(this); + if (!assert_constant(get_location(&case_label->position()))) + { + continue; + } + tree label_comparison = build_equality_comparison(get_location(&case_label->position()), + condition_value, this->current_expression, + statement->condition().type_decoration, EQ_EXPR); + case_condition = build2(TRUTH_ORIF_EXPR, elna_bool_type_node, + case_condition, label_comparison); + } + + enter_scope(); + visit_statements(case_block.statements); + tree then_body = leave_scope(); + + result = build3(COND_EXPR, void_type_node, case_condition, then_body, result); + } + if (result != NULL_TREE) + { + append_statement(result); + } } bool generic_visitor::assert_constant(location_t expression_location) diff --git a/gcc/gcc/elna-tree.cc b/gcc/gcc/elna-tree.cc index 26936fe..c47bb94 100644 --- a/gcc/gcc/elna-tree.cc +++ b/gcc/gcc/elna-tree.cc @@ -252,7 +252,7 @@ namespace elna::gcc { return DECL_INITIAL(expression); } - else if (TREE_CODE_CLASS(code) == tcc_constant) + else if (TREE_CODE_CLASS(code) == tcc_constant || TREE_CONSTANT(expression)) { return expression; } diff --git a/gcc/gcc/elna1.cc b/gcc/gcc/elna1.cc index 94055e5..fde2adc 100644 --- a/gcc/gcc/elna1.cc +++ b/gcc/gcc/elna1.cc @@ -136,14 +136,14 @@ static elna::boot::dependency elna_parse_file(dependency_state& state, const cha std::filesystem::path sub_path = find_module(sub_tree)[0]; dependency_state::const_iterator cached_import = state.find(sub_path); - if (cached_import == state.cend()) + if (cached_import == std::cend(state)) { auto filename_pointer = ggc_strdup(sub_path.native().c_str()); elna_parse_file(state, filename_pointer); cached_import = state.find(sub_path); } - if (cached_import != state.cend()) + if (cached_import != std::cend(state)) { outcome_bag.add_import(cached_import->second); } |
