Replace unreachable() with assert(false)
This commit is contained in:
		| @@ -339,7 +339,7 @@ namespace elna::boot | ||||
|  | ||||
|     std::shared_ptr<variable_info> variable_info::is_variable() | ||||
|     { | ||||
|         return std::static_pointer_cast<variable_info>(shared_from_this());; | ||||
|         return std::static_pointer_cast<variable_info>(shared_from_this()); | ||||
|     } | ||||
|  | ||||
|     std::shared_ptr<symbol_table> builtin_symbol_table() | ||||
|   | ||||
| @@ -73,8 +73,6 @@ namespace elna::gcc | ||||
|         declare_builtin_type(symbol_table, "Float", elna_float_type_node); | ||||
|         declare_builtin_type(symbol_table, "String", elna_string_type_node); | ||||
|  | ||||
|         symbol_table->enter("unreachable", *elna_global_decls->get("__builtin_unreachable")); | ||||
|  | ||||
|         return symbol_table; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -148,7 +148,7 @@ namespace elna::gcc | ||||
|             if (!is_assignable_from(TREE_VALUE(current_parameter), this->current_expression)) | ||||
|             { | ||||
|                 error_at(argument_location, | ||||
|                         "cannot assign value of type '%s' to variable of type '%s'", | ||||
|                         "Cannot assign value of type '%s' to variable of type '%s'", | ||||
|                         print_type(TREE_TYPE(this->current_expression)).c_str(), | ||||
|                         print_type(TREE_VALUE(current_parameter)).c_str()); | ||||
|                 this->current_expression = error_mark_node; | ||||
| @@ -202,7 +202,7 @@ namespace elna::gcc | ||||
|         } | ||||
|         if (!is_void_type(record_fields)) | ||||
|         { | ||||
|                 error_at(call_location, "too few arguments, expected %i, got %lu", | ||||
|                 error_at(call_location, "Too few arguments, expected %i, got %lu", | ||||
|                         list_length(TYPE_FIELDS(symbol)), arguments.size()); | ||||
|                 this->current_expression = error_mark_node; | ||||
|         } | ||||
| @@ -212,8 +212,62 @@ namespace elna::gcc | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::build_assert_builtin(location_t call_location, | ||||
|             const std::vector<boot::expression *>& arguments) | ||||
|     { | ||||
|         if (arguments.size() != 1) | ||||
|         { | ||||
|             error_at(call_location, "assert expects exactly one boolean argument, got %lu", arguments.size()); | ||||
|             this->current_expression = error_mark_node; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             arguments.at(0)->accept(this); | ||||
|             tree argument_type = TREE_TYPE(this->current_expression); | ||||
|  | ||||
|             if (argument_type != elna_bool_type_node) | ||||
|             { | ||||
|                 error_at(call_location, "assert expects exactly one boolean argument, got %s", | ||||
|                         print_type(argument_type).c_str()); | ||||
|                 this->current_expression = error_mark_node; | ||||
|             } | ||||
|             tree constant_expression = extract_constant(this->current_expression); | ||||
|             if (constant_expression == boolean_false_node) | ||||
|             { | ||||
|                 this->current_expression = call_built_in(call_location, "__builtin_unreachable", void_type_node); | ||||
|             } | ||||
|             else if (constant_expression != boolean_true_node) | ||||
|             { | ||||
|                 this->current_expression = call_built_in(call_location, "__builtin_trap", void_type_node); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 this->current_expression = NULL_TREE; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool generic_visitor::build_builtin_procedures(boot::procedure_call *call) | ||||
|     { | ||||
|         location_t call_location = get_location(&call->position()); | ||||
|  | ||||
|         if (boot::variable_expression *named_call = call->callable().is_variable()) | ||||
|         { | ||||
|             if (named_call->name == "assert") | ||||
|             { | ||||
|                 build_assert_builtin(call_location, call->arguments); | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::visit(boot::procedure_call *call) | ||||
|     { | ||||
|         if (build_builtin_procedures(call)) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|         location_t call_location = get_location(&call->position()); | ||||
|         call->callable().accept(this); | ||||
|  | ||||
| @@ -599,13 +653,8 @@ namespace elna::gcc | ||||
|                     right, elna_string_ptr_field_node, NULL_TREE); | ||||
|  | ||||
|             tree length_equality = build2(equality_code, elna_bool_type_node, lhs_length, rhs_length); | ||||
|             tree *memcmp = elna_global_decls->get("__builtin_memcmp"); | ||||
|             gcc_assert(memcmp != nullptr); | ||||
|  | ||||
|             tree fndecl_type = build_function_type(integer_type_node, TYPE_ARG_TYPES(*memcmp)); | ||||
|             tree memcmp_addr = build1(ADDR_EXPR, build_pointer_type(fndecl_type), *memcmp); | ||||
|             tree memcmp_call = build_call_nary(integer_type_node, memcmp_addr, 3, lhs_ptr, rhs_ptr, lhs_length); | ||||
|  | ||||
|             tree memcmp_call = call_built_in(UNKNOWN_LOCATION, "__builtin_memcmp", integer_type_node, | ||||
|                     lhs_ptr, rhs_ptr, lhs_length); | ||||
|             tree equals_zero = build2(equality_code, elna_bool_type_node, memcmp_call, integer_zero_node); | ||||
|  | ||||
|             return build2(combination_code, elna_bool_type_node, length_equality, equals_zero); | ||||
| @@ -768,7 +817,7 @@ namespace elna::gcc | ||||
|         location_t definition_location = get_location(&definition->position()); | ||||
|         definition->body().accept(this); | ||||
|  | ||||
|         if (extract_constant(definition_location)) | ||||
|         if (assert_constant(definition_location)) | ||||
|         { | ||||
|             this->current_expression = fold_init(this->current_expression); | ||||
|         } | ||||
| @@ -1490,7 +1539,7 @@ namespace elna::gcc | ||||
|                 case_label->accept(this); | ||||
|                 location_t case_location = get_location(&case_label->position()); | ||||
|  | ||||
|                 if (extract_constant(case_location) | ||||
|                 if (assert_constant(case_location) | ||||
|                         && !is_assignable_from(unqualified_condition, this->current_expression)) | ||||
|                 { | ||||
|                     error_at(case_location, "Case type '%s' does not match the expression type '%s'", | ||||
| @@ -1535,20 +1584,19 @@ namespace elna::gcc | ||||
|         this->current_expression = NULL_TREE; | ||||
|     } | ||||
|  | ||||
|     bool generic_visitor::extract_constant(location_t expression_location) | ||||
|     bool generic_visitor::assert_constant(location_t expression_location) | ||||
|     { | ||||
|         int code = TREE_CODE(this->current_expression); | ||||
|         tree constant_expression = extract_constant(this->current_expression); | ||||
|  | ||||
|         if (code == CONST_DECL) | ||||
|         { | ||||
|             this->current_expression = DECL_INITIAL(this->current_expression); | ||||
|         } | ||||
|         else if (TREE_CODE_CLASS(code) != tcc_constant) | ||||
|         if (constant_expression == NULL_TREE) | ||||
|         { | ||||
|             error_at(expression_location, "Expected a constant expression"); | ||||
|             this->current_expression = error_mark_node; | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|         else | ||||
|         { | ||||
|             this->current_expression = constant_expression; | ||||
|         } | ||||
|         return this->current_expression != error_mark_node; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -249,4 +249,19 @@ namespace elna::gcc | ||||
|  | ||||
|         return label_decl; | ||||
|     } | ||||
|  | ||||
|     tree extract_constant(tree expression) | ||||
|     { | ||||
|         int code = TREE_CODE(expression); | ||||
|  | ||||
|         if (code == CONST_DECL) | ||||
|         { | ||||
|             return DECL_INITIAL(expression); | ||||
|         } | ||||
|         else if (TREE_CODE_CLASS(code) == tcc_constant) | ||||
|         { | ||||
|             return expression; | ||||
|         } | ||||
|         return NULL_TREE; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -40,7 +40,6 @@ namespace elna::gcc | ||||
|             std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved, | ||||
|             std::vector<std::string>& path); | ||||
|  | ||||
|  | ||||
|     class generic_visitor final : public boot::parser_visitor | ||||
|     { | ||||
|         tree current_expression{ NULL_TREE }; | ||||
| @@ -68,11 +67,13 @@ namespace elna::gcc | ||||
|                 tree procedure_address, const std::vector<boot::expression *>& arguments); | ||||
|         void build_record_call(location_t call_location, | ||||
|                 tree symbol, const std::vector<boot::expression *>& arguments); | ||||
|         bool build_builtin_procedures(boot::procedure_call *call); | ||||
|         void build_assert_builtin(location_t call_location, const std::vector<boot::expression *>& arguments); | ||||
|  | ||||
|         bool expect_trait_type_only(boot::traits_expression *trait); | ||||
|         bool expect_trait_for_integral_type(boot::traits_expression *trait); | ||||
|         void visit_statements(const std::vector<boot::statement *>& statements); | ||||
|         bool extract_constant(location_t expression_location); | ||||
|         bool assert_constant(location_t expression_location); | ||||
|  | ||||
|     public: | ||||
|         generic_visitor(std::shared_ptr<symbol_table> symbol_table, | ||||
|   | ||||
| @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see | ||||
|  | ||||
| #include "elna/boot/ast.h" | ||||
| #include "elna/boot/symbol.h" | ||||
| #include "elna/gcc/elna1.h" | ||||
|  | ||||
| namespace elna::gcc | ||||
| { | ||||
| @@ -82,4 +83,18 @@ namespace elna::gcc | ||||
|     tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name); | ||||
|     tree build_global_pointer_type(tree type); | ||||
|     tree build_label_decl(const char *name, location_t loc); | ||||
|  | ||||
|     tree extract_constant(tree expression); | ||||
|  | ||||
|     template<typename... Args> | ||||
|     tree call_built_in(location_t call_location, const char *name, tree return_type, Args... arguments) | ||||
|     { | ||||
|         tree *builtin = elna_global_decls->get(name); | ||||
|         gcc_assert(builtin != nullptr); | ||||
|  | ||||
|         tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(*builtin)); | ||||
|         tree builtin_addr = build1_loc(call_location, ADDR_EXPR, build_pointer_type(fndecl_type), *builtin); | ||||
|  | ||||
|         return build_call_nary(return_type, builtin_addr, sizeof...(Args), arguments...); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License | ||||
| along with GCC; see the file COPYING3.  If not see | ||||
| <http://www.gnu.org/licenses/>.  */ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| enum elna_tree_index | ||||
| { | ||||
|     ELNA_TI_INT_TYPE, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user