diff options
Diffstat (limited to 'gcc')
24 files changed, 419 insertions, 98 deletions
diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h index 286954a..ff74994 100644 --- a/gcc/diagnostic-core.h +++ b/gcc/diagnostic-core.h @@ -92,6 +92,9 @@ extern void error_n (location_t, unsigned HOST_WIDE_INT, const char *, extern void error_at (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3); extern void error_at (rich_location *, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3); +extern void error_meta (rich_location *, const diagnostic_metadata &, + const char *, ...) + ATTRIBUTE_GCC_DIAG(3,4); extern void fatal_error (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3) ATTRIBUTE_NORETURN; /* Pass one of the OPT_W* from options.h as the second parameter. */ diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc index 22f7b0b..0461b32 100644 --- a/gcc/diagnostic.cc +++ b/gcc/diagnostic.cc @@ -2050,6 +2050,21 @@ error_at (rich_location *richloc, const char *gmsgid, ...) va_end (ap); } +/* Same as above, but with metadata. */ + +void +error_meta (rich_location *richloc, const diagnostic_metadata &metadata, + const char *gmsgid, ...) +{ + gcc_assert (richloc); + + auto_diagnostic_group d; + va_list ap; + va_start (ap, gmsgid); + diagnostic_impl (richloc, &metadata, -1, gmsgid, &ap, DK_ERROR); + va_end (ap); +} + /* "Sorry, not implemented." Use for a language feature which is required by the relevant specification but not implemented by GCC. An object file will not be produced. */ diff --git a/gcc/rust/backend/rust-builtins.h b/gcc/rust/backend/rust-builtins.h index 2bfa6c6..5cd8401 100644 --- a/gcc/rust/backend/rust-builtins.h +++ b/gcc/rust/backend/rust-builtins.h @@ -18,8 +18,9 @@ #define RUST_BUILTINS_H #include "rust-system.h" -#include "tree.h" +#include "rust-tree.h" #include "langhooks.h" +#include "tree.h" namespace Rust { namespace Compile { @@ -99,16 +100,34 @@ private: BuiltinsContext () { setup (); } - void setup () + void setup_overflow_fns () + { + tree overflow_type + = build_varargs_function_type_list (boolean_type_node, NULL_TREE); + + define_builtin ("add_overflow", BUILT_IN_ADD_OVERFLOW, + "__builtin_add_overflow", "add_overflow", overflow_type, 0); + define_builtin ("sub_overflow", BUILT_IN_SUB_OVERFLOW, + "__builtin_sub_overflow", "sub_overflow", overflow_type, 0); + define_builtin ("mul_overflow", BUILT_IN_MUL_OVERFLOW, + "__builtin_mul_overflow", "mul_overflow", overflow_type, 0); + } + + void setup_math_fns () { tree math_function_type_f32 = build_function_type_list (float_type_node, float_type_node, NULL_TREE); define_builtin ("sinf32", BUILT_IN_SINF, "__builtin_sinf", "sinf", math_function_type_f32, builtin_const); - define_builtin ("sqrtf32", BUILT_IN_SQRTF, "__builtin_sqrtf", "sqrtf", math_function_type_f32, builtin_const); + } + + void setup () + { + setup_math_fns (); + setup_overflow_fns (); define_builtin ("unreachable", BUILT_IN_UNREACHABLE, "__builtin_unreachable", NULL, @@ -132,6 +151,16 @@ private: 0); } + static void handle_flags (tree decl, int flags) + { + if (flags & builtin_const) + TREE_READONLY (decl) = 1; + if (flags & builtin_noreturn) + TREE_READONLY (decl) = 1; + if (flags & builtin_novops) + DECL_IS_NOVOPS (decl) = 1; + } + // Define a builtin function. BCODE is the builtin function code // defined by builtins.def. NAME is the name of the builtin function. // LIBNAME is the name of the corresponding library function, and is @@ -144,24 +173,16 @@ private: { tree decl = add_builtin_function (name, fntype, bcode, BUILT_IN_NORMAL, libname, NULL_TREE); - if ((flags & builtin_const) != 0) - TREE_READONLY (decl) = 1; - if ((flags & builtin_noreturn) != 0) - TREE_THIS_VOLATILE (decl) = 1; - if ((flags & builtin_novops) != 0) - DECL_IS_NOVOPS (decl) = 1; + handle_flags (decl, flags); set_builtin_decl (bcode, decl, true); + this->builtin_functions_[name] = decl; if (libname != NULL) { decl = add_builtin_function (libname, fntype, bcode, BUILT_IN_NORMAL, NULL, NULL_TREE); - if ((flags & builtin_const) != 0) - TREE_READONLY (decl) = 1; - if ((flags & builtin_noreturn) != 0) - TREE_THIS_VOLATILE (decl) = 1; - if ((flags & builtin_novops) != 0) - DECL_IS_NOVOPS (decl) = 1; + handle_flags (decl, flags); + this->builtin_functions_[libname] = decl; } diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index 865ad25..e13c08c 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -26,6 +26,7 @@ #include "rust-compile-block.h" #include "rust-compile-implitem.h" #include "rust-constexpr.h" +#include "rust-gcc.h" #include "fold-const.h" #include "realmpfr.h" @@ -146,9 +147,26 @@ CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) return; } - translated - = ctx->get_backend ()->arithmetic_or_logical_expression (op, lhs, rhs, - expr.get_locus ()); + if (ctx->in_fn () && !ctx->const_context_p ()) + { + auto receiver_tmp = NULL_TREE; + auto receiver + = ctx->get_backend ()->temporary_variable (ctx->peek_fn ().fndecl, + NULL_TREE, TREE_TYPE (lhs), + lhs, true, expr.get_locus (), + &receiver_tmp); + auto check + = ctx->get_backend ()->arithmetic_or_logical_expression_checked ( + op, lhs, rhs, expr.get_locus (), receiver); + + ctx->add_statement (check); + translated = receiver->get_tree (expr.get_locus ()); + } + else + { + translated = ctx->get_backend ()->arithmetic_or_logical_expression ( + op, lhs, rhs, expr.get_locus ()); + } } void @@ -176,13 +194,27 @@ CompileExpr::visit (HIR::CompoundAssignmentExpr &expr) return; } - auto operator_expr - = ctx->get_backend ()->arithmetic_or_logical_expression (op, lhs, rhs, - expr.get_locus ()); - tree assignment - = ctx->get_backend ()->assignment_statement (lhs, operator_expr, - expr.get_locus ()); - ctx->add_statement (assignment); + if (ctx->in_fn () && !ctx->const_context_p ()) + { + auto tmp = NULL_TREE; + auto receiver + = ctx->get_backend ()->temporary_variable (ctx->peek_fn ().fndecl, + NULL_TREE, TREE_TYPE (lhs), + lhs, true, expr.get_locus (), + &tmp); + auto check + = ctx->get_backend ()->arithmetic_or_logical_expression_checked ( + op, lhs, rhs, expr.get_locus (), receiver); + ctx->add_statement (check); + + translated = ctx->get_backend ()->assignment_statement ( + lhs, receiver->get_tree (expr.get_locus ()), expr.get_locus ()); + } + else + { + translated = ctx->get_backend ()->arithmetic_or_logical_expression ( + op, lhs, rhs, expr.get_locus ()); + } } void @@ -2378,7 +2410,10 @@ CompileExpr::array_copied_expr (Location expr_locus, return error_mark_node; } + ctx->push_const_context (); tree capacity_expr = CompileExpr::Compile (elems.get_num_copies_expr (), ctx); + ctx->pop_const_context (); + if (!TREE_CONSTANT (capacity_expr)) { rust_error_at (expr_locus, "non const num copies %qT", array_type); diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index ceba51c..96c4e7f 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -160,6 +160,9 @@ CompileItem::visit (HIR::Function &function) function.get_mappings ().get_nodeid (), &canonical_path); rust_assert (ok); + if (function.get_qualifiers ().is_const ()) + ctx->push_const_context (); + tree fndecl = compile_function (ctx, function.get_function_name (), function.get_self_param (), @@ -169,6 +172,9 @@ CompileItem::visit (HIR::Function &function) function.get_definition ().get (), canonical_path, fntype, function.has_function_return_type ()); reference = address_expression (fndecl, ref_locus); + + if (function.get_qualifiers ().is_const ()) + ctx->pop_const_context (); } void diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index eced909..77d8474 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -370,7 +370,11 @@ TyTyResolveCompile::visit (const TyTy::ArrayType &type) { tree element_type = TyTyResolveCompile::compile (ctx, type.get_element_type ()); + + ctx->push_const_context (); tree capacity_expr = CompileExpr::Compile (&type.get_capacity_expr (), ctx); + ctx->pop_const_context (); + tree folded_capacity_expr = fold_expr (capacity_expr); translated diff --git a/gcc/rust/checks/lints/rust-lint-scan-deadcode.h b/gcc/rust/checks/lints/rust-lint-scan-deadcode.h index 591cb30..3e1df39 100644 --- a/gcc/rust/checks/lints/rust-lint-scan-deadcode.h +++ b/gcc/rust/checks/lints/rust-lint-scan-deadcode.h @@ -53,7 +53,7 @@ public: void visit (HIR::Function &function) override { HirId hirId = function.get_mappings ().get_hirid (); - if (should_warn (hirId)) + if (should_warn (hirId) && !function.get_visibility ().is_public ()) { if (mappings->is_impl_item (hirId)) { @@ -78,7 +78,7 @@ public: void visit (HIR::StructStruct &stct) override { HirId hirId = stct.get_mappings ().get_hirid (); - if (should_warn (hirId)) + if (should_warn (hirId) && !stct.get_visibility ().is_public ()) { bool name_starts_underscore = stct.get_identifier ().at (0) == '_'; if (!name_starts_underscore) @@ -92,7 +92,8 @@ public: for (auto &field : stct.get_fields ()) { HirId field_hir_id = field.get_mappings ().get_hirid (); - if (should_warn (field_hir_id)) + if (should_warn (field_hir_id) + && !field.get_visibility ().is_public ()) { rust_warning_at (field.get_locus (), 0, "field is never read: %<%s%>", @@ -106,7 +107,7 @@ public: { // only warn tuple struct unconstructed, and ignoring unused field HirId hirId = stct.get_mappings ().get_hirid (); - if (should_warn (hirId)) + if (should_warn (hirId) && !stct.get_visibility ().is_public ()) { rust_warning_at (stct.get_locus (), 0, "struct is never constructed: %<%s%>", diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index 126283c..cda2642 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -235,13 +235,24 @@ public: // Supported values of OP are enumerated in ArithmeticOrLogicalOperator. virtual tree arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, tree right, - Location) + Location loc) + = 0; + + // Return an expression for the operation LEFT OP RIGHT. + // Supported values of OP are enumerated in ArithmeticOrLogicalOperator. + // This function adds overflow checking and returns a list of statements to + // add to the current function context. The `receiver` variable refers to the + // variable which will contain the result of that operation. + virtual tree + arithmetic_or_logical_expression_checked (ArithmeticOrLogicalOperator op, + tree left, tree right, Location loc, + Bvariable *receiver) = 0; // Return an expression for the operation LEFT OP RIGHT. // Supported values of OP are enumerated in ComparisonOperator. virtual tree comparison_expression (ComparisonOperator op, tree left, - tree right, Location) + tree right, Location loc) = 0; // Return an expression for the operation LEFT OP RIGHT. @@ -416,8 +427,8 @@ public: // variable, and may not be very useful. This function should // return a variable which can be referenced later and should set // *PSTATEMENT to a statement which initializes the variable. - virtual Bvariable *temporary_variable (tree, tree, tree, tree init, - bool address_is_taken, + virtual Bvariable *temporary_variable (tree fndecl, tree bind_tree, tree type, + tree init, bool address_is_taken, Location location, tree *pstatement) = 0; diff --git a/gcc/rust/rust-diagnostics.cc b/gcc/rust/rust-diagnostics.cc index c2d3e4e..79daf6b 100644 --- a/gcc/rust/rust-diagnostics.cc +++ b/gcc/rust/rust-diagnostics.cc @@ -167,6 +167,17 @@ rust_error_at (const Location location, const char *fmt, ...) } void +rust_error_at (const RichLocation &location, const ErrorCode code, + const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + rust_be_error_at (location, code, expand_message (fmt, ap)); + va_end (ap); +} + +void rust_warning_at (const Location location, int opt, const char *fmt, ...) { va_list ap; diff --git a/gcc/rust/rust-diagnostics.h b/gcc/rust/rust-diagnostics.h index 93bd1b3..35a1727 100644 --- a/gcc/rust/rust-diagnostics.h +++ b/gcc/rust/rust-diagnostics.h @@ -50,6 +50,18 @@ // clang-format off // simple location + +struct ErrorCode +{ + explicit ErrorCode (const char *str) : m_str (str) + { + gcc_assert (str); + gcc_assert (str[0] == 'E'); + } + + const char *m_str; +}; + extern void rust_internal_error_at (const Location, const char *fmt, ...) RUST_ATTRIBUTE_GCC_DIAG (2, 3) @@ -72,6 +84,9 @@ rust_inform (const Location, const char *fmt, ...) extern void rust_error_at (const RichLocation &, const char *fmt, ...) RUST_ATTRIBUTE_GCC_DIAG (2, 3); +extern void +rust_error_at (const RichLocation &, const ErrorCode, const char *fmt, ...) + RUST_ATTRIBUTE_GCC_DIAG (3, 4); // clang-format on // These interfaces provide a way for the front end to ask for @@ -97,6 +112,9 @@ rust_be_error_at (const Location, const std::string &errmsg); extern void rust_be_error_at (const RichLocation &, const std::string &errmsg); extern void +rust_be_error_at (const RichLocation &, const ErrorCode, + const std::string &errmsg); +extern void rust_be_warning_at (const Location, int opt, const std::string &warningmsg); extern void rust_be_fatal_error (const Location, const std::string &errmsg) diff --git a/gcc/rust/rust-gcc-diagnostics.cc b/gcc/rust/rust-gcc-diagnostics.cc index db07372..98e2af7 100644 --- a/gcc/rust/rust-gcc-diagnostics.cc +++ b/gcc/rust/rust-gcc-diagnostics.cc @@ -22,6 +22,7 @@ #include "rust-diagnostics.h" #include "options.h" +#include "diagnostic-metadata.h" void rust_be_internal_error_at (const Location location, const std::string &errmsg) @@ -70,6 +71,38 @@ rust_be_error_at (const RichLocation &location, const std::string &errmsg) error_at (&gcc_loc, "%s", errmsg.c_str ()); } +class rust_error_code_rule : public diagnostic_metadata::rule +{ +public: + rust_error_code_rule (const ErrorCode code) : m_code (code) {} + + char *make_description () const final override + { + return xstrdup (m_code.m_str); + } + + char *make_url () const final override + { + return concat ("https://doc.rust-lang.org/error-index.html#", m_code.m_str, + NULL); + } + +private: + const ErrorCode m_code; +}; + +void +rust_be_error_at (const RichLocation &location, const ErrorCode code, + const std::string &errmsg) +{ + /* TODO: 'error_at' would like a non-'const' 'rich_location *'. */ + rich_location &gcc_loc = const_cast<rich_location &> (location.get ()); + diagnostic_metadata m; + rust_error_code_rule rule (code); + m.add_rule (rule); + error_meta (&gcc_loc, m, "%s", errmsg.c_str ()); +} + void rust_be_get_quotechars (const char **open_qu, const char **close_qu) { diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index ffb67f3..e5dc6da 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -50,37 +50,10 @@ #include "rust-linemap.h" #include "rust-backend.h" #include "rust-object-export.h" +#include "rust-gcc.h" #include "backend/rust-tree.h" - -// TODO: this will have to be significantly modified to work with Rust - -// Bvariable is a bit more complicated, because of zero-sized types. -// The GNU linker does not permit dynamic variables with zero size. -// When we see such a variable, we generate a version of the type with -// non-zero size. However, when referring to the global variable, we -// want an expression of zero size; otherwise, if, say, the global -// variable is passed to a function, we will be passing a -// non-zero-sized value to a zero-sized value, which can lead to a -// miscompilation. - -class Bvariable -{ -public: - Bvariable (tree t) : t_ (t), orig_type_ (NULL) {} - - Bvariable (tree t, tree orig_type) : t_ (t), orig_type_ (orig_type) {} - - // Get the tree for use as an expression. - tree get_tree (Location) const; - - // Get the actual decl; - tree get_decl () const { return this->t_; } - -private: - tree t_; - tree orig_type_; -}; +#include "backend/rust-builtins.h" // Get the tree of a variable for use as an expression. If this is a // zero-sized global, create an expression that refers to the decl but @@ -234,6 +207,10 @@ public: tree arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, tree right, Location); + tree arithmetic_or_logical_expression_checked (ArithmeticOrLogicalOperator op, + tree left, tree right, + Location, Bvariable *receiver); + tree comparison_expression (ComparisonOperator op, tree left, tree right, Location); @@ -1408,25 +1385,26 @@ Gcc_backend::negation_expression (NegationOperator op, tree expr_tree, return new_tree; } -// Return an expression for the arithmetic or logical operation LEFT OP RIGHT. tree Gcc_backend::arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, - tree left_tree, tree right_tree, + tree left, tree right, Location location) { /* Check if either expression is an error, in which case we return an error expression. */ - if (left_tree == error_mark_node || right_tree == error_mark_node) + if (left == error_mark_node || right == error_mark_node) return error_mark_node; /* We need to determine if we're doing floating point arithmetics of integer arithmetics. */ - bool floating_point = is_floating_point (left_tree); + bool floating_point = is_floating_point (left); + auto ret = NULL_TREE; /* For arithmetic or logical operators, the resulting type should be the same as the lhs operand. */ - auto tree_type = TREE_TYPE (left_tree); + auto tree_type = TREE_TYPE (left); auto original_type = tree_type; + auto loc = location.gcc_location (); auto tree_code = operator_to_tree_code (op, floating_point); /* For floating point operations we may need to extend the precision of type. @@ -1437,21 +1415,127 @@ Gcc_backend::arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, extended_type = excess_precision_type (tree_type); if (extended_type != NULL_TREE) { - left_tree = convert (extended_type, left_tree); - right_tree = convert (extended_type, right_tree); + left = convert (extended_type, left); + right = convert (extended_type, right); tree_type = extended_type; } } - /* Construct a new tree and build an expression from it. */ - auto new_tree = fold_build2_loc (location.gcc_location (), tree_code, - tree_type, left_tree, right_tree); - TREE_CONSTANT (new_tree) - = TREE_CONSTANT (left_tree) && TREE_CONSTANT (right_tree); + ret = fold_build2_loc (loc, tree_code, tree_type, left, right); + TREE_CONSTANT (ret) = TREE_CONSTANT (left) & TREE_CONSTANT (right); + // TODO: How do we handle floating point? if (floating_point && extended_type != NULL_TREE) - new_tree = convert (original_type, new_tree); - return new_tree; + ret = convert (original_type, ret); + + return ret; +} + +static bool +is_overflowing_expr (ArithmeticOrLogicalOperator op) +{ + switch (op) + { + case ArithmeticOrLogicalOperator::ADD: + case ArithmeticOrLogicalOperator::SUBTRACT: + case ArithmeticOrLogicalOperator::MULTIPLY: + return true; + default: + return false; + } +} + +static std::pair<tree, tree> +fetch_overflow_builtins (ArithmeticOrLogicalOperator op) +{ + auto builtin_ctx = Rust::Compile::BuiltinsContext::get (); + + auto builtin = NULL_TREE; + auto abort = NULL_TREE; + + switch (op) + { + case ArithmeticOrLogicalOperator::ADD: + builtin_ctx.lookup_simple_builtin ("add_overflow", &builtin); + break; + case ArithmeticOrLogicalOperator::SUBTRACT: + builtin_ctx.lookup_simple_builtin ("sub_overflow", &builtin); + break; + case ArithmeticOrLogicalOperator::MULTIPLY: + builtin_ctx.lookup_simple_builtin ("mul_overflow", &builtin); + break; + default: + gcc_unreachable (); + break; + }; + + builtin_ctx.lookup_simple_builtin ("abort", &abort); + + rust_assert (abort); + rust_assert (builtin); + + // FIXME: ARTHUR: This is really ugly. The builtin context should take care of + // that + TREE_SIDE_EFFECTS (abort) = 1; + TREE_READONLY (abort) = 0; + + // FIXME: ARTHUR: Same here. Remove these! + TREE_SIDE_EFFECTS (builtin) = 1; + TREE_READONLY (builtin) = 0; + + return {abort, builtin}; +} + +// Return an expression for the arithmetic or logical operation LEFT OP RIGHT +// with overflow checking when possible +tree +Gcc_backend::arithmetic_or_logical_expression_checked ( + ArithmeticOrLogicalOperator op, tree left, tree right, Location location, + Bvariable *receiver_var) +{ + /* Check if either expression is an error, in which case we return an error + expression. */ + if (left == error_mark_node || right == error_mark_node) + return error_mark_node; + + auto loc = location.gcc_location (); + + // FIXME: Add `if (!debug_mode)` + // No overflow checks for floating point operations or divisions. In that + // case, simply assign the result of the operation to the receiver variable + if (is_floating_point (left) || !is_overflowing_expr (op)) + return assignment_statement ( + receiver_var->get_tree (location), + arithmetic_or_logical_expression (op, left, right, location), location); + + auto receiver = receiver_var->get_tree (location); + TREE_ADDRESSABLE (receiver) = 1; + auto result_ref = build_fold_addr_expr_loc (loc, receiver); + + auto builtins = fetch_overflow_builtins (op); + auto abort = builtins.first; + auto builtin = builtins.second; + + auto abort_call = build_call_expr_loc (loc, abort, 0); + + // FIXME: ARTHUR: Is that needed? + TREE_SIDE_EFFECTS (abort_call) = 1; + TREE_READONLY (abort_call) = 0; + + auto builtin_call + = build_call_expr_loc (loc, builtin, 3, left, right, result_ref); + auto overflow_check + = build2_loc (loc, EQ_EXPR, boolean_type_node, builtin_call, + boolean_constant_expression (true)); + + auto if_block = build3_loc (loc, COND_EXPR, void_type_node, overflow_check, + abort_call, NULL_TREE); + + // FIXME: ARTHUR: Needed? + TREE_SIDE_EFFECTS (if_block) = 1; + TREE_READONLY (if_block) = 0; + + return if_block; } // Return an expression for the comparison operation LEFT OP RIGHT. diff --git a/gcc/rust/rust-gcc.h b/gcc/rust/rust-gcc.h new file mode 100644 index 0000000..085c16d --- /dev/null +++ b/gcc/rust/rust-gcc.h @@ -0,0 +1,58 @@ +// rust-gcc.cc -- Rust frontend to gcc IR. +// Copyright (C) 2011-2022 Free Software Foundation, Inc. +// Contributed by Ian Lance Taylor, Google. +// forked from gccgo + +// This file is part of GCC. + +// 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 +// <http://www.gnu.org/licenses/>. + +#include "rust-system.h" + +// This has to be included outside of extern "C", so we have to +// include it here before tree.h includes it later. +#include <gmp.h> + +#include "tree.h" +#include "rust-location.h" + +// TODO: this will have to be significantly modified to work with Rust + +// Bvariable is a bit more complicated, because of zero-sized types. +// The GNU linker does not permit dynamic variables with zero size. +// When we see such a variable, we generate a version of the type with +// non-zero size. However, when referring to the global variable, we +// want an expression of zero size; otherwise, if, say, the global +// variable is passed to a function, we will be passing a +// non-zero-sized value to a zero-sized value, which can lead to a +// miscompilation. + +class Bvariable +{ +public: + Bvariable (tree t) : t_ (t), orig_type_ (NULL) {} + + Bvariable (tree t, tree orig_type) : t_ (t), orig_type_ (orig_type) {} + + // Get the tree for use as an expression. + tree get_tree (Location) const; + + // Get the actual decl; + tree get_decl () const { return this->t_; } + +private: + tree t_; + tree orig_type_; +}; diff --git a/gcc/rust/typecheck/rust-casts.cc b/gcc/rust/typecheck/rust-casts.cc index 61004df..708880e 100644 --- a/gcc/rust/typecheck/rust-casts.cc +++ b/gcc/rust/typecheck/rust-casts.cc @@ -283,7 +283,7 @@ TypeCastRules::emit_cast_error () const RichLocation r (locus); r.add_range (from.get_locus ()); r.add_range (to.get_locus ()); - rust_error_at (r, "invalid cast %<%s%> to %<%s%>", + rust_error_at (r, ErrorCode ("E0054"), "invalid cast %<%s%> to %<%s%>", from.get_ty ()->get_name ().c_str (), to.get_ty ()->get_name ().c_str ()); } diff --git a/gcc/testsuite/rust/compile/bad_as_bool_char.rs b/gcc/testsuite/rust/compile/bad_as_bool_char.rs index 91a28ee..9652915 100644 --- a/gcc/testsuite/rust/compile/bad_as_bool_char.rs +++ b/gcc/testsuite/rust/compile/bad_as_bool_char.rs @@ -5,13 +5,13 @@ pub fn main () let fone = t as f32; // { dg-error "invalid cast" } let fzero = f as f64; // { dg-error "invalid cast" } - let nb = 0u8 as bool; // { dg-error "invalid cast" } + let nb = 0u8 as bool; // { dg-error "invalid cast .u8. to .bool. \\\[E0054\\\]" } let nc = true as char; // { dg-error "invalid cast" } let a = 'a'; let b = 'b'; let fa = a as f32; // { dg-error "invalid cast" } - let bb = b as bool; // { dg-error "invalid cast" } + let bb = b as bool; // { dg-error "invalid cast .char. to .bool. \\\[E0054\\\]" } let t32: u32 = 33; let ab = t32 as char; // { dg-error "invalid cast" } diff --git a/gcc/testsuite/rust/compile/issue-1031.rs b/gcc/testsuite/rust/compile/issue-1031.rs index 939f0f9..5ba8f7a 100644 --- a/gcc/testsuite/rust/compile/issue-1031.rs +++ b/gcc/testsuite/rust/compile/issue-1031.rs @@ -6,12 +6,10 @@ extern "rust-intrinsic" { #[lang = "const_ptr"] impl<T> *const T { pub const unsafe fn offset(self, count: isize) -> *const T { - // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } unsafe { offset(self, count) } } pub const unsafe fn add(self, count: usize) -> Self { - // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } unsafe { self.offset(count as isize) } } } diff --git a/gcc/testsuite/rust/compile/issue-1289.rs b/gcc/testsuite/rust/compile/issue-1289.rs index 343aaab..eb41af0 100644 --- a/gcc/testsuite/rust/compile/issue-1289.rs +++ b/gcc/testsuite/rust/compile/issue-1289.rs @@ -23,12 +23,10 @@ impl<T> *mut T { #[lang = "const_ptr"] impl<T> *const T { pub const unsafe fn offset(self, count: isize) -> *mut T { - // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } unsafe { intrinsics::offset(self, count) as *mut T } } pub const unsafe fn add(self, count: usize) -> Self { - // { dg-warning "associated function is never used" "" { target *-*-* } .-1 } unsafe { self.offset(count as isize) } } } diff --git a/gcc/testsuite/rust/compile/privacy7.rs b/gcc/testsuite/rust/compile/privacy7.rs new file mode 100644 index 0000000..00fa0ef --- /dev/null +++ b/gcc/testsuite/rust/compile/privacy7.rs @@ -0,0 +1,9 @@ +pub struct Foo(i8); +struct Bar(pub i8); // { dg-warning "struct is never constructed: .Bar." } +pub struct Baz { + a: i32, // { dg-warning "field is never read: .a." } + pub b: i32, +} + +pub fn foo() {} +fn bar() {} // { dg-warning "function is never used: .bar." } diff --git a/gcc/testsuite/rust/compile/test_mod.rs b/gcc/testsuite/rust/compile/test_mod.rs index 4b3c000..6e9c19b 100644 --- a/gcc/testsuite/rust/compile/test_mod.rs +++ b/gcc/testsuite/rust/compile/test_mod.rs @@ -3,4 +3,3 @@ //! foo bar baz cake pizza carbs pub struct Test(pub i32); -// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/torture/raw_identifiers.rs b/gcc/testsuite/rust/compile/torture/raw_identifiers.rs index 8746f33..7e6cd91 100644 --- a/gcc/testsuite/rust/compile/torture/raw_identifiers.rs +++ b/gcc/testsuite/rust/compile/torture/raw_identifiers.rs @@ -1,3 +1,3 @@ -pub fn square(num: i32) -> i32 { /* { dg-warning "used" } */ +pub fn square(num: i32) -> i32 { r#num * num -}
\ No newline at end of file +} diff --git a/gcc/testsuite/rust/compile/torture/raw_identifiers_keywords.rs b/gcc/testsuite/rust/compile/torture/raw_identifiers_keywords.rs index c9aa3cf..3a15223 100644 --- a/gcc/testsuite/rust/compile/torture/raw_identifiers_keywords.rs +++ b/gcc/testsuite/rust/compile/torture/raw_identifiers_keywords.rs @@ -1,3 +1,3 @@ -pub fn plus(r#break: i32, r#unsafe: i32) -> i32 { /* { dg-warning "used" } */ +pub fn plus(r#break: i32, r#unsafe: i32) -> i32 { r#break + r#unsafe -}
\ No newline at end of file +} diff --git a/gcc/testsuite/rust/debug/win64-abi.rs b/gcc/testsuite/rust/debug/win64-abi.rs index b2b08cd..4e02906 100644 --- a/gcc/testsuite/rust/debug/win64-abi.rs +++ b/gcc/testsuite/rust/debug/win64-abi.rs @@ -1,11 +1,11 @@ // { dg-do compile { target { x86_64-*-* } } } // { dg-options "-gdwarf-5 -dA -w -O1 -m64" } -pub extern "win64" fn square(num: i32) -> i32 { - num * num +pub extern "win64" fn id(num: i32) -> i32 { + num } fn main() { // MS ABI dictates that the first argument is ecx instead of edi from the sysv world - // { dg-final { scan-assembler "%ecx, %ecx" } } - square(1); + // { dg-final { scan-assembler "%ecx, %eax" } } + id(1); } diff --git a/gcc/testsuite/rust/compile/torture/macro-issue1426.rs b/gcc/testsuite/rust/execute/torture/macro-issue1426.rs index 1b558cf..4fb6a29 100644 --- a/gcc/testsuite/rust/compile/torture/macro-issue1426.rs +++ b/gcc/testsuite/rust/execute/torture/macro-issue1426.rs @@ -1,5 +1,3 @@ -// { dg-additional-options -fdump-tree-ccp1-raw } - macro_rules! stmt { ($s:stmt) => { $s @@ -22,11 +20,10 @@ pub fn test() -> i32 { let e = 5, let f = b + c + d + e ); + f - // { dg-final { scan-tree-dump-times {gimple_return <14>} 1 ccp1 { target __OPTIMIZE__ } } } } -fn main() { - let _ = test(); +fn main() -> i32 { + test() - 14 } - diff --git a/gcc/testsuite/rust/execute/torture/overflow1.rs b/gcc/testsuite/rust/execute/torture/overflow1.rs new file mode 100644 index 0000000..57a0824 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/overflow1.rs @@ -0,0 +1,20 @@ +// { dg-shouldfail "i8 overflow" } +// { dg-options "-fdump-tree-original" } + +fn five() -> i8 { + 5 +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn main() { + let a = 127i8; + let b = five(); + + // { dg-final { scan-tree-dump ADD_OVERFLOW original } } + let c = a + b; + + unsafe { printf("%d\n\0" as *const str as *const i8, c) } +} |