aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/diagnostic-core.h3
-rw-r--r--gcc/diagnostic.cc15
-rw-r--r--gcc/rust/backend/rust-builtins.h51
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc55
-rw-r--r--gcc/rust/backend/rust-compile-item.cc6
-rw-r--r--gcc/rust/backend/rust-compile-type.cc4
-rw-r--r--gcc/rust/checks/lints/rust-lint-scan-deadcode.h9
-rw-r--r--gcc/rust/rust-backend.h19
-rw-r--r--gcc/rust/rust-diagnostics.cc11
-rw-r--r--gcc/rust/rust-diagnostics.h18
-rw-r--r--gcc/rust/rust-gcc-diagnostics.cc33
-rw-r--r--gcc/rust/rust-gcc.cc170
-rw-r--r--gcc/rust/rust-gcc.h58
-rw-r--r--gcc/rust/typecheck/rust-casts.cc2
-rw-r--r--gcc/testsuite/rust/compile/bad_as_bool_char.rs4
-rw-r--r--gcc/testsuite/rust/compile/issue-1031.rs2
-rw-r--r--gcc/testsuite/rust/compile/issue-1289.rs2
-rw-r--r--gcc/testsuite/rust/compile/privacy7.rs9
-rw-r--r--gcc/testsuite/rust/compile/test_mod.rs1
-rw-r--r--gcc/testsuite/rust/compile/torture/raw_identifiers.rs4
-rw-r--r--gcc/testsuite/rust/compile/torture/raw_identifiers_keywords.rs4
-rw-r--r--gcc/testsuite/rust/debug/win64-abi.rs8
-rw-r--r--gcc/testsuite/rust/execute/torture/macro-issue1426.rs (renamed from gcc/testsuite/rust/compile/torture/macro-issue1426.rs)9
-rw-r--r--gcc/testsuite/rust/execute/torture/overflow1.rs20
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) }
+}