aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/backend')
-rw-r--r--gcc/rust/backend/rust-compile-base.cc43
-rw-r--r--gcc/rust/backend/rust-compile-base.h3
-rw-r--r--gcc/rust/backend/rust-compile-context.h2
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc15
-rw-r--r--gcc/rust/backend/rust-compile-expr.h30
-rw-r--r--gcc/rust/backend/rust-compile-stmt.h5
-rw-r--r--gcc/rust/backend/rust-compile.cc14
-rw-r--r--gcc/rust/backend/rust-constexpr.cc47
-rw-r--r--gcc/rust/backend/rust-tree.cc659
-rw-r--r--gcc/rust/backend/rust-tree.h182
10 files changed, 904 insertions, 96 deletions
diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc
index 33e4c26..a705da7 100644
--- a/gcc/rust/backend/rust-compile-base.cc
+++ b/gcc/rust/backend/rust-compile-base.cc
@@ -22,6 +22,8 @@
#include "rust-compile-fnparam.h"
#include "rust-compile-var-decl.h"
+#include "rust-expr.h" // for AST::AttrInputLiteral
+
#include "fold-const.h"
#include "stringpool.h"
@@ -52,10 +54,16 @@ HIRCompileBase::setup_attributes_on_fndecl (
for (const auto &attr : attrs)
{
bool is_inline = attr.get_path ().as_string ().compare ("inline") == 0;
+ bool is_must_use
+ = attr.get_path ().as_string ().compare ("must_use") == 0;
if (is_inline)
{
handle_inline_attribute_on_fndecl (fndecl, attr);
}
+ else if (is_must_use)
+ {
+ handle_must_use_attribute_on_fndecl (fndecl, attr);
+ }
}
}
@@ -108,6 +116,30 @@ HIRCompileBase::handle_inline_attribute_on_fndecl (tree fndecl,
}
void
+HIRCompileBase::handle_must_use_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr)
+{
+ tree nodiscard = get_identifier ("nodiscard");
+ tree value = NULL_TREE;
+
+ if (attr.has_attr_input ())
+ {
+ rust_assert (attr.get_attr_input ().get_attr_input_type ()
+ == AST::AttrInput::AttrInputType::LITERAL);
+
+ auto &literal
+ = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
+ const auto &msg_str = literal.get_literal ().as_string ();
+ tree message = build_string (msg_str.size (), msg_str.c_str ());
+
+ value = tree_cons (nodiscard, message, NULL_TREE);
+ }
+
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (nodiscard, value, DECL_ATTRIBUTES (fndecl));
+}
+
+void
HIRCompileBase::setup_abi_options (tree fndecl, ABI abi)
{
switch (abi)
@@ -262,9 +294,8 @@ HIRCompileBase::compile_function_body (Context *ctx, tree fndecl,
auto compiled_expr = CompileStmt::Compile (s.get (), ctx);
if (compiled_expr != nullptr)
{
- tree compiled_stmt
- = ctx->get_backend ()->expression_statement (fndecl, compiled_expr);
- ctx->add_statement (compiled_stmt);
+ tree s = convert_to_void (compiled_expr, ICV_STATEMENT);
+ ctx->add_statement (s);
}
}
@@ -289,10 +320,8 @@ HIRCompileBase::compile_function_body (Context *ctx, tree fndecl,
}
else
{
- tree final_stmt
- = ctx->get_backend ()->expression_statement (fndecl,
- compiled_expr);
- ctx->add_statement (final_stmt);
+ // FIXME can this actually happen?
+ ctx->add_statement (compiled_expr);
}
}
}
diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h
index b434168..c30aa4d 100644
--- a/gcc/rust/backend/rust-compile-base.h
+++ b/gcc/rust/backend/rust-compile-base.h
@@ -79,6 +79,9 @@ protected:
static void handle_inline_attribute_on_fndecl (tree fndecl,
const AST::Attribute &attr);
+ static void handle_must_use_attribute_on_fndecl (tree fndecl,
+ const AST::Attribute &attr);
+
static void setup_abi_options (tree fndecl, ABI abi);
static tree address_expression (tree, Location);
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index 46f88b3..3fefd8d 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -25,9 +25,9 @@
#include "rust-hir-type-check.h"
#include "rust-backend.h"
#include "rust-compile-tyty.h"
-#include "rust-ast-full.h"
#include "rust-hir-full.h"
#include "rust-mangle.h"
+#include "rust-tree.h"
namespace Rust {
namespace Compile {
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index bf47661..6d50c3f 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -63,8 +63,6 @@ CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
void
CompileExpr::visit (HIR::CompoundAssignmentExpr &expr)
{
- fncontext fn = ctx->peek_fn ();
-
auto op = expr.get_expr_type ();
auto lhs = CompileExpr::Compile (expr.get_left_expr ().get (), ctx);
auto rhs = CompileExpr::Compile (expr.get_right_expr ().get (), ctx);
@@ -82,10 +80,7 @@ CompileExpr::visit (HIR::CompoundAssignmentExpr &expr)
= resolve_operator_overload (lang_item_type, expr, lhs, rhs,
expr.get_left_expr ().get (),
expr.get_right_expr ().get ());
- auto assignment
- = ctx->get_backend ()->expression_statement (fn.fndecl,
- compound_assignment);
- ctx->add_statement (assignment);
+ ctx->add_statement (compound_assignment);
return;
}
@@ -94,7 +89,7 @@ CompileExpr::visit (HIR::CompoundAssignmentExpr &expr)
= ctx->get_backend ()->arithmetic_or_logical_expression (op, lhs, rhs,
expr.get_locus ());
tree assignment
- = ctx->get_backend ()->assignment_statement (fn.fndecl, lhs, operator_expr,
+ = ctx->get_backend ()->assignment_statement (lhs, operator_expr,
expr.get_locus ());
ctx->add_statement (assignment);
}
@@ -304,8 +299,10 @@ CompileExpr::visit (HIR::MatchExpr &expr)
{
tree result_reference
= ctx->get_backend ()->var_expression (tmp, arm_locus);
- tree assignment = ctx->get_backend ()->assignment_statement (
- fnctx.fndecl, result_reference, kase_expr_tree, arm_locus);
+ tree assignment
+ = ctx->get_backend ()->assignment_statement (result_reference,
+ kase_expr_tree,
+ arm_locus);
ctx->add_statement (assignment);
}
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h
index 3cc51d4..8aeb703 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -169,7 +169,6 @@ public:
void visit (HIR::AssignmentExpr &expr) override
{
- fncontext fn = ctx->peek_fn ();
auto lvalue = CompileExpr::Compile (expr.get_lhs (), ctx);
auto rvalue = CompileExpr::Compile (expr.get_rhs (), ctx);
@@ -191,7 +190,7 @@ public:
expr.get_rhs ()->get_locus ());
tree assignment
- = ctx->get_backend ()->assignment_statement (fn.fndecl, lvalue, rvalue,
+ = ctx->get_backend ()->assignment_statement (lvalue, rvalue,
expr.get_locus ());
ctx->add_statement (assignment);
@@ -594,9 +593,7 @@ public:
= CompileBlock::compile (expr.get_loop_block ().get (), ctx, nullptr);
tree loop_expr
= ctx->get_backend ()->loop_expression (code_block, expr.get_locus ());
- tree loop_stmt
- = ctx->get_backend ()->expression_statement (fnctx.fndecl, loop_expr);
- ctx->add_statement (loop_stmt);
+ ctx->add_statement (loop_expr);
if (tmp != NULL)
{
@@ -645,9 +642,7 @@ public:
= CompileExpr::Compile (expr.get_predicate_expr ().get (), ctx);
tree exit_expr
= ctx->get_backend ()->exit_expression (condition, expr.get_locus ());
- tree break_stmt
- = ctx->get_backend ()->expression_statement (fnctx.fndecl, exit_expr);
- ctx->add_statement (break_stmt);
+ ctx->add_statement (exit_expr);
tree code_block_stmt
= CompileBlock::compile (expr.get_loop_block ().get (), ctx, nullptr);
@@ -659,14 +654,11 @@ public:
tree loop_expr
= ctx->get_backend ()->loop_expression (loop_block, expr.get_locus ());
- tree loop_stmt
- = ctx->get_backend ()->expression_statement (fnctx.fndecl, loop_expr);
- ctx->add_statement (loop_stmt);
+ ctx->add_statement (loop_expr);
}
void visit (HIR::BreakExpr &expr) override
{
- fncontext fnctx = ctx->peek_fn ();
if (expr.has_break_expr ())
{
tree compiled_expr
@@ -676,8 +668,10 @@ public:
tree result_reference = ctx->get_backend ()->var_expression (
loop_result_holder, expr.get_expr ()->get_locus ());
- tree assignment = ctx->get_backend ()->assignment_statement (
- fnctx.fndecl, result_reference, compiled_expr, expr.get_locus ());
+ tree assignment
+ = ctx->get_backend ()->assignment_statement (result_reference,
+ compiled_expr,
+ expr.get_locus ());
ctx->add_statement (assignment);
}
@@ -721,9 +715,7 @@ public:
tree exit_expr = ctx->get_backend ()->exit_expression (
ctx->get_backend ()->boolean_constant_expression (true),
expr.get_locus ());
- tree break_stmt
- = ctx->get_backend ()->expression_statement (fnctx.fndecl, exit_expr);
- ctx->add_statement (break_stmt);
+ ctx->add_statement (exit_expr);
}
}
@@ -761,9 +753,7 @@ public:
}
}
- tree goto_label
- = ctx->get_backend ()->goto_statement (label, expr.get_locus ());
- ctx->add_statement (goto_label);
+ translated = ctx->get_backend ()->goto_statement (label, expr.get_locus ());
}
void visit (HIR::BorrowExpr &expr) override;
diff --git a/gcc/rust/backend/rust-compile-stmt.h b/gcc/rust/backend/rust-compile-stmt.h
index 2dfb520..0f69fb0 100644
--- a/gcc/rust/backend/rust-compile-stmt.h
+++ b/gcc/rust/backend/rust-compile-stmt.h
@@ -90,9 +90,8 @@ public:
auto fnctx = ctx->peek_fn ();
if (ty->is_unit ())
{
- tree expr_stmt
- = ctx->get_backend ()->expression_statement (fnctx.fndecl, init);
- ctx->add_statement (expr_stmt);
+ // FIXME this feels wrong
+ ctx->add_statement (init);
}
else
{
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index fcbfc05..9e2c5b3 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -82,10 +82,8 @@ CompileBlock::visit (HIR::BlockExpr &expr)
auto compiled_expr = CompileStmt::Compile (s.get (), ctx);
if (compiled_expr != nullptr)
{
- tree compiled_stmt
- = ctx->get_backend ()->expression_statement (fnctx.fndecl,
- compiled_expr);
- ctx->add_statement (compiled_stmt);
+ tree s = convert_to_void (compiled_expr, ICV_STATEMENT);
+ ctx->add_statement (s);
}
}
@@ -98,10 +96,7 @@ CompileBlock::visit (HIR::BlockExpr &expr)
{
if (result == nullptr)
{
- tree final_stmt
- = ctx->get_backend ()->expression_statement (fnctx.fndecl,
- compiled_expr);
- ctx->add_statement (final_stmt);
+ ctx->add_statement (compiled_expr);
}
else
{
@@ -109,8 +104,7 @@ CompileBlock::visit (HIR::BlockExpr &expr)
result, expr.get_final_expr ()->get_locus ());
tree assignment
- = ctx->get_backend ()->assignment_statement (fnctx.fndecl,
- result_reference,
+ = ctx->get_backend ()->assignment_statement (result_reference,
compiled_expr,
expr.get_locus ());
ctx->add_statement (assignment);
diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index f1f969c..1b0515e 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -17,6 +17,7 @@
#include "rust-constexpr.h"
#include "rust-location.h"
#include "rust-diagnostics.h"
+#include "rust-tree.h"
#include "fold-const.h"
#include "realmpfr.h"
@@ -25,52 +26,6 @@
#include "gimplify.h"
#include "tree-iterator.h"
-/* Returns true if NODE is a pointer. */
-#define TYPE_PTR_P(NODE) (TREE_CODE (NODE) == POINTER_TYPE)
-
-/* Returns true if NODE is a reference. */
-#define TYPE_REF_P(NODE) (TREE_CODE (NODE) == REFERENCE_TYPE)
-
-/* Returns true if NODE is a pointer or a reference. */
-#define INDIRECT_TYPE_P(NODE) (TYPE_PTR_P (NODE) || TYPE_REF_P (NODE))
-
-/* [basic.fundamental]
-
- Types bool, char, wchar_t, and the signed and unsigned integer types
- are collectively called integral types.
-
- Note that INTEGRAL_TYPE_P, as defined in tree.h, allows enumeration
- types as well, which is incorrect in C++. Keep these checks in
- ascending code order. */
-#define RS_INTEGRAL_TYPE_P(TYPE) \
- (TREE_CODE (TYPE) == BOOLEAN_TYPE || TREE_CODE (TYPE) == INTEGER_TYPE)
-
-/* [basic.fundamental]
-
- Integral and floating types are collectively called arithmetic
- types.
-
- As a GNU extension, we also accept complex types.
-
- Keep these checks in ascending code order. */
-#define ARITHMETIC_TYPE_P(TYPE) \
- (RS_INTEGRAL_TYPE_P (TYPE) || TREE_CODE (TYPE) == REAL_TYPE \
- || TREE_CODE (TYPE) == COMPLEX_TYPE)
-
-/* True iff TYPE is cv decltype(nullptr). */
-#define NULLPTR_TYPE_P(TYPE) (TREE_CODE (TYPE) == NULLPTR_TYPE)
-
-/* [basic.types]
-
- Arithmetic types, enumeration types, pointer types,
- pointer-to-member types, and std::nullptr_t are collectively called
- scalar types.
-
- Keep these checks in ascending code order. */
-#define SCALAR_TYPE_P(TYPE) \
- (TREE_CODE (TYPE) == ENUMERAL_TYPE || ARITHMETIC_TYPE_P (TYPE) \
- || TYPE_PTR_P (TYPE) || NULLPTR_TYPE_P (TYPE))
-
namespace Rust {
namespace Compile {
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
new file mode 100644
index 0000000..8e39408
--- /dev/null
+++ b/gcc/rust/backend/rust-tree.cc
@@ -0,0 +1,659 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// 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-tree.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "escaped_string.h"
+
+namespace Rust {
+
+void
+mark_exp_read (tree exp)
+{
+ if (exp == NULL)
+ return;
+
+ switch (TREE_CODE (exp))
+ {
+ case VAR_DECL:
+ gcc_fallthrough ();
+ case PARM_DECL:
+ DECL_READ_P (exp) = 1;
+ break;
+ case ARRAY_REF:
+ case COMPONENT_REF:
+ case MODIFY_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ CASE_CONVERT:
+ case ADDR_EXPR:
+ case INDIRECT_REF:
+ case FLOAT_EXPR:
+ case NON_DEPENDENT_EXPR:
+ case VIEW_CONVERT_EXPR:
+ mark_exp_read (TREE_OPERAND (exp, 0));
+ break;
+ case COMPOUND_EXPR:
+ mark_exp_read (TREE_OPERAND (exp, 1));
+ break;
+ case COND_EXPR:
+ if (TREE_OPERAND (exp, 1))
+ mark_exp_read (TREE_OPERAND (exp, 1));
+ if (TREE_OPERAND (exp, 2))
+ mark_exp_read (TREE_OPERAND (exp, 2));
+ break;
+ default:
+ break;
+ }
+}
+
+tree
+convert_from_reference (tree val)
+{
+ if (TREE_TYPE (val) && TYPE_REF_P (TREE_TYPE (val)))
+ {
+ tree t = TREE_TYPE (TREE_TYPE (val));
+ tree ref = build1 (INDIRECT_REF, t, val);
+
+ mark_exp_read (val);
+
+ TREE_SIDE_EFFECTS (ref)
+ = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (val));
+ val = ref;
+ }
+
+ return val;
+}
+
+tree
+mark_use (tree expr, bool rvalue_p, bool read_p,
+ location_t loc /* = UNKNOWN_LOCATION */,
+ bool reject_builtin /* = true */)
+{
+#define RECUR(t) mark_use ((t), rvalue_p, read_p, loc, reject_builtin)
+
+ if (expr == NULL_TREE || error_operand_p (expr))
+ return expr;
+
+ if (reject_builtin)
+ return error_mark_node;
+
+ if (read_p)
+ mark_exp_read (expr);
+
+ bool recurse_op[3] = {false, false, false};
+ switch (TREE_CODE (expr))
+ {
+ case COMPONENT_REF:
+ case NON_DEPENDENT_EXPR:
+ recurse_op[0] = true;
+ break;
+ case COMPOUND_EXPR:
+ recurse_op[1] = true;
+ break;
+ case COND_EXPR:
+ recurse_op[2] = true;
+ if (TREE_OPERAND (expr, 1))
+ recurse_op[1] = true;
+ break;
+ case INDIRECT_REF:
+ if (REFERENCE_REF_P (expr))
+ {
+ /* Try to look through the reference. */
+ tree ref = TREE_OPERAND (expr, 0);
+ tree r = mark_rvalue_use (ref, loc, reject_builtin);
+ if (r != ref)
+ expr = convert_from_reference (r);
+ }
+ break;
+
+ case VIEW_CONVERT_EXPR:
+ if (location_wrapper_p (expr))
+ {
+ loc = EXPR_LOCATION (expr);
+ tree op = TREE_OPERAND (expr, 0);
+ tree nop = RECUR (op);
+ if (nop == error_mark_node)
+ return error_mark_node;
+ else if (op == nop)
+ /* No change. */;
+ else if (DECL_P (nop) || CONSTANT_CLASS_P (nop))
+ {
+ /* Reuse the location wrapper. */
+ TREE_OPERAND (expr, 0) = nop;
+ /* If we're replacing a DECL with a constant, we also need to
+ change the TREE_CODE of the location wrapper. */
+ if (rvalue_p)
+ TREE_SET_CODE (expr, NON_LVALUE_EXPR);
+ }
+ else
+ {
+ /* Drop the location wrapper. */
+ expr = nop;
+ protected_set_expr_location (expr, loc);
+ }
+ return expr;
+ }
+ gcc_fallthrough ();
+ CASE_CONVERT:
+ recurse_op[0] = true;
+ break;
+
+ default:
+ break;
+ }
+
+ for (int i = 0; i < 3; ++i)
+ if (recurse_op[i])
+ {
+ tree op = TREE_OPERAND (expr, i);
+ op = RECUR (op);
+ if (op == error_mark_node)
+ return error_mark_node;
+ TREE_OPERAND (expr, i) = op;
+ }
+
+ return expr;
+#undef RECUR
+}
+
+tree
+mark_rvalue_use (tree e, location_t loc /* = UNKNOWN_LOCATION */,
+ bool reject_builtin /* = true */)
+{
+ return mark_use (e, true, true, loc, reject_builtin);
+}
+
+tree
+mark_lvalue_use (tree expr)
+{
+ return mark_use (expr, false, true, input_location, false);
+}
+
+tree
+mark_lvalue_use_nonread (tree expr)
+{
+ return mark_use (expr, false, false, input_location, false);
+}
+
+tree
+mark_discarded_use (tree expr)
+{
+ if (expr == NULL_TREE)
+ return expr;
+
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
+ switch (TREE_CODE (expr))
+ {
+ case COND_EXPR:
+ TREE_OPERAND (expr, 2) = mark_discarded_use (TREE_OPERAND (expr, 2));
+ gcc_fallthrough ();
+ case COMPOUND_EXPR:
+ TREE_OPERAND (expr, 1) = mark_discarded_use (TREE_OPERAND (expr, 1));
+ return expr;
+
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ case INDIRECT_REF:
+ case MEMBER_REF:
+ break;
+ default:
+ if (DECL_P (expr))
+ break;
+ else
+ return expr;
+ }
+
+ return mark_use (expr, true, true, input_location, false);
+}
+
+tree
+convert_to_void (tree expr, impl_conv_void implicit)
+{
+ location_t loc = expr_loc_or_input_loc (expr);
+ if (expr == error_mark_node || TREE_TYPE (expr) == error_mark_node)
+ return error_mark_node;
+
+ expr = mark_discarded_use (expr);
+ if (implicit == ICV_CAST)
+ /* An explicit cast to void avoids all -Wunused-but-set* warnings. */
+ mark_exp_read (expr);
+
+ if (!TREE_TYPE (expr))
+ return expr;
+
+ if (VOID_TYPE_P (TREE_TYPE (expr)))
+ return expr;
+ switch (TREE_CODE (expr))
+ {
+ case COND_EXPR: {
+ /* The two parts of a cond expr might be separate lvalues. */
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree op2 = TREE_OPERAND (expr, 2);
+ bool side_effects
+ = ((op1 && TREE_SIDE_EFFECTS (op1)) || TREE_SIDE_EFFECTS (op2));
+ tree new_op1, new_op2;
+ new_op1 = NULL_TREE;
+ if (implicit != ICV_CAST && !side_effects)
+ {
+ if (op1)
+ new_op1 = convert_to_void (op1, ICV_SECOND_OF_COND);
+ new_op2 = convert_to_void (op2, ICV_THIRD_OF_COND);
+ }
+ else
+ {
+ if (op1)
+ new_op1 = convert_to_void (op1, ICV_CAST);
+ new_op2 = convert_to_void (op2, ICV_CAST);
+ }
+
+ expr = build3_loc (loc, COND_EXPR, TREE_TYPE (new_op2),
+ TREE_OPERAND (expr, 0), new_op1, new_op2);
+ break;
+ }
+
+ case COMPOUND_EXPR: {
+ /* The second part of a compound expr contains the value. */
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree new_op1;
+ if (implicit != ICV_CAST
+ && !warning_suppressed_p (expr /* What warning? */))
+ new_op1 = convert_to_void (op1, ICV_RIGHT_OF_COMMA);
+ else
+ new_op1 = convert_to_void (op1, ICV_CAST);
+
+ if (new_op1 != op1)
+ {
+ tree t = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (new_op1),
+ TREE_OPERAND (expr, 0), new_op1);
+ expr = t;
+ }
+
+ break;
+ }
+
+ case NON_LVALUE_EXPR:
+ case NOP_EXPR:
+ /* These have already decayed to rvalue. */
+ break;
+
+ case CALL_EXPR:
+ maybe_warn_nodiscard (expr, implicit);
+ break;
+
+ case INDIRECT_REF: {
+ tree type = TREE_TYPE (expr);
+ int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
+ int is_volatile = TYPE_VOLATILE (type);
+ int is_complete = COMPLETE_TYPE_P (type);
+
+ /* Can't load the value if we don't know the type. */
+ if (is_volatile && !is_complete)
+ {
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0,
+ "conversion to void will not access "
+ "object of incomplete type %qT",
+ type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in second operand "
+ "of conditional expression",
+ type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in third operand "
+ "of conditional expression",
+ type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in right operand of "
+ "comma operator",
+ type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in left operand of "
+ "comma operator",
+ type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in statement",
+ type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "incomplete type %qT in for increment "
+ "expression",
+ type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ /* Don't load the value if this is an implicit dereference, or if
+ the type needs to be handled by ctors/dtors. */
+ else if (is_volatile && is_reference)
+ {
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0,
+ "conversion to void will not access "
+ "object of type %qT",
+ type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in second operand of "
+ "conditional expression",
+ type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in third operand of "
+ "conditional expression",
+ type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in right operand of "
+ "comma operator",
+ type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in left operand of comma "
+ "operator",
+ type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in statement",
+ type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0,
+ "implicit dereference will not access "
+ "object of type %qT in for increment expression",
+ type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else if (is_volatile && TREE_ADDRESSABLE (type))
+ {
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0,
+ "conversion to void will not access "
+ "object of non-trivially-copyable type %qT",
+ type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in second "
+ "operand of conditional expression",
+ type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in third "
+ "operand of conditional expression",
+ type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in right "
+ "operand of comma operator",
+ type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in left "
+ "operand of comma operator",
+ type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in statement",
+ type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0,
+ "indirection will not access object of "
+ "non-trivially-copyable type %qT in for "
+ "increment expression",
+ type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ if (is_reference || !is_volatile || !is_complete
+ || TREE_ADDRESSABLE (type))
+ {
+ /* Emit a warning (if enabled) when the "effect-less" INDIRECT_REF
+ operation is stripped off. Note that we don't warn about
+ - an expression with TREE_NO_WARNING set. (For an example of
+ such expressions, see build_over_call in call.cc.)
+ - automatic dereferencing of references, since the user cannot
+ control it. (See also warn_if_unused_value() in c-common.cc.)
+ */
+ if (warn_unused_value && implicit != ICV_CAST
+ && !warning_suppressed_p (expr, OPT_Wunused_value)
+ && !is_reference)
+ warning_at (loc, OPT_Wunused_value, "value computed is not used");
+ expr = TREE_OPERAND (expr, 0);
+ if (TREE_CODE (expr) == CALL_EXPR)
+ maybe_warn_nodiscard (expr, implicit);
+ }
+
+ break;
+ }
+
+ case VAR_DECL: {
+ /* External variables might be incomplete. */
+ tree type = TREE_TYPE (expr);
+ int is_complete = COMPLETE_TYPE_P (type);
+
+ if (TYPE_VOLATILE (type) && !is_complete)
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0,
+ "conversion to void will not access "
+ "object %qE of incomplete type %qT",
+ expr, type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in second operand of "
+ "conditional expression",
+ expr, type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in third operand of "
+ "conditional expression",
+ expr, type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in right operand of comma operator",
+ expr, type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in left operand of comma operator",
+ expr, type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in statement",
+ expr, type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0,
+ "variable %qE of incomplete type %qT will "
+ "not be accessed in for increment expression",
+ expr, type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ break;
+ }
+
+ default:;
+ }
+
+ if (!TREE_SIDE_EFFECTS (expr))
+ expr = void_node;
+
+ return expr;
+}
+
+void
+maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
+{
+ tree call = expr;
+ if (TREE_CODE (expr) == TARGET_EXPR)
+ call = TARGET_EXPR_INITIAL (expr);
+
+ location_t loc = expr_loc_or_input_loc (call);
+ tree callee = CALL_EXPR_FN (call);
+ if (!callee)
+ return;
+
+ tree type = TREE_TYPE (callee);
+ if (INDIRECT_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ tree rettype = TREE_TYPE (type);
+ tree fn = get_fndecl_from_callee (callee);
+ tree attr;
+ if (implicit != ICV_CAST && fn
+ && (attr = lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn))))
+ {
+ escaped_string msg;
+ tree args = TREE_VALUE (attr);
+ if (args)
+ msg.escape (TREE_STRING_POINTER (TREE_VALUE (args)));
+ const char *format
+ = (msg ? G_ ("ignoring return value of %qD, that must be used: %<%s%>")
+ : G_ ("ignoring return value of %qD, that must be used"));
+ const char *raw_msg = msg ? (const char *) msg : "";
+ auto_diagnostic_group d;
+ if (warning_at (loc, OPT_Wunused_result, format, fn, raw_msg))
+ inform (DECL_SOURCE_LOCATION (fn), "declared here");
+ }
+ else if (implicit != ICV_CAST
+ && (attr
+ = lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype))))
+ {
+ escaped_string msg;
+ tree args = TREE_VALUE (attr);
+ if (args)
+ msg.escape (TREE_STRING_POINTER (TREE_VALUE (args)));
+ const char *format
+ = (msg ? G_ (
+ "ignoring returned value of type %qT, that must be used: %<%s%>")
+ : G_ ("ignoring returned value of type %qT, that must be used"));
+ const char *raw_msg = msg ? (const char *) msg : "";
+ auto_diagnostic_group d;
+ if (warning_at (loc, OPT_Wunused_result, format, rettype, raw_msg))
+ {
+ if (fn)
+ inform (DECL_SOURCE_LOCATION (fn), "in call to %qD, declared here",
+ fn);
+ inform (DECL_SOURCE_LOCATION (TYPE_NAME (rettype)),
+ "%qT declared here", rettype);
+ }
+ }
+}
+
+location_t
+expr_loc_or_loc (const_tree t, location_t or_loc)
+{
+ location_t loc = EXPR_LOCATION (t);
+ if (loc == UNKNOWN_LOCATION)
+ loc = or_loc;
+ return loc;
+}
+
+location_t
+expr_loc_or_input_loc (const_tree t)
+{
+ return expr_loc_or_loc (t, input_location);
+}
+
+// FN is the callee of a CALL_EXPR or AGGR_INIT_EXPR; return the FUNCTION_DECL
+// if we can.
+tree
+get_fndecl_from_callee (tree fn)
+{
+ if (fn == NULL_TREE)
+ return fn;
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ return fn;
+ tree type = TREE_TYPE (fn);
+ if (type == NULL_TREE || !INDIRECT_TYPE_P (type))
+ return NULL_TREE;
+
+ STRIP_NOPS (fn);
+ if (TREE_CODE (fn) == ADDR_EXPR || TREE_CODE (fn) == FDESC_EXPR)
+ fn = TREE_OPERAND (fn, 0);
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ return fn;
+ return NULL_TREE;
+}
+
+} // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
new file mode 100644
index 0000000..c21bf4b
--- /dev/null
+++ b/gcc/rust/backend/rust-tree.h
@@ -0,0 +1,182 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// 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/>.
+
+#ifndef RUST_TREE
+#define RUST_TREE
+
+#include "rust-system.h"
+#include "coretypes.h"
+#include "tree.h"
+
+/* Returns true if NODE is a pointer. */
+#define TYPE_PTR_P(NODE) (TREE_CODE (NODE) == POINTER_TYPE)
+
+/* Returns true if NODE is a reference. */
+#define TYPE_REF_P(NODE) (TREE_CODE (NODE) == REFERENCE_TYPE)
+
+/* Returns true if NODE is a pointer or a reference. */
+#define INDIRECT_TYPE_P(NODE) (TYPE_PTR_P (NODE) || TYPE_REF_P (NODE))
+
+/* [basic.fundamental]
+
+ Types bool, char, wchar_t, and the signed and unsigned integer types
+ are collectively called integral types.
+
+ Note that INTEGRAL_TYPE_P, as defined in tree.h, allows enumeration
+ types as well, which is incorrect in C++. Keep these checks in
+ ascending code order. */
+#define RS_INTEGRAL_TYPE_P(TYPE) \
+ (TREE_CODE (TYPE) == BOOLEAN_TYPE || TREE_CODE (TYPE) == INTEGER_TYPE)
+
+/* [basic.fundamental]
+
+ Integral and floating types are collectively called arithmetic
+ types.
+
+ As a GNU extension, we also accept complex types.
+
+ Keep these checks in ascending code order. */
+#define ARITHMETIC_TYPE_P(TYPE) \
+ (RS_INTEGRAL_TYPE_P (TYPE) || TREE_CODE (TYPE) == REAL_TYPE \
+ || TREE_CODE (TYPE) == COMPLEX_TYPE)
+
+/* True iff TYPE is cv decltype(nullptr). */
+#define NULLPTR_TYPE_P(TYPE) (TREE_CODE (TYPE) == NULLPTR_TYPE)
+
+/* [basic.types]
+
+ Arithmetic types, enumeration types, pointer types,
+ pointer-to-member types, and std::nullptr_t are collectively called
+ scalar types.
+
+ Keep these checks in ascending code order. */
+#define SCALAR_TYPE_P(TYPE) \
+ (TREE_CODE (TYPE) == ENUMERAL_TYPE || ARITHMETIC_TYPE_P (TYPE) \
+ || TYPE_PTR_P (TYPE) || NULLPTR_TYPE_P (TYPE))
+
+/* True if NODE is an implicit INDIRECT_REF from convert_from_reference. */
+#define REFERENCE_REF_P(NODE) \
+ (INDIRECT_REF_P (NODE) && TREE_TYPE (TREE_OPERAND (NODE, 0)) \
+ && TYPE_REF_P (TREE_TYPE (TREE_OPERAND ((NODE), 0))))
+
+namespace Rust {
+
+// forked from gcc/cp/cvt.cc convert_to_void
+//
+// When an expression is used in a void context, its value is discarded and
+// no lvalue-rvalue and similar conversions happen [expr.static.cast/4,
+// stmt.expr/1, expr.comma/1]. This permits dereferencing an incomplete type
+// in a void context. The C++ standard does not define what an `access' to an
+// object is, but there is reason to believe that it is the lvalue to rvalue
+// conversion -- if it were not, `*&*p = 1' would violate [expr]/4 in that it
+// accesses `*p' not to calculate the value to be stored. But, dcl.type.cv/8
+// indicates that volatile semantics should be the same between C and C++
+// where ever possible. C leaves it implementation defined as to what
+// constitutes an access to a volatile. So, we interpret `*vp' as a read of
+// the volatile object `vp' points to, unless that is an incomplete type. For
+// volatile references we do not do this interpretation, because that would
+// make it impossible to ignore the reference return value from functions. We
+// issue warnings in the confusing cases.
+//
+// The IMPLICIT is ICV_CAST when the user is explicitly converting an
+// expression to void via a cast. If an expression is being implicitly
+// converted, IMPLICIT indicates the context of the implicit conversion.
+
+/* Possible cases of implicit or explicit bad conversions to void. */
+enum impl_conv_void
+{
+ ICV_CAST, /* (explicit) conversion to void */
+ ICV_SECOND_OF_COND, /* second operand of conditional expression */
+ ICV_THIRD_OF_COND, /* third operand of conditional expression */
+ ICV_RIGHT_OF_COMMA, /* right operand of comma operator */
+ ICV_LEFT_OF_COMMA, /* left operand of comma operator */
+ ICV_STATEMENT, /* statement */
+ ICV_THIRD_IN_FOR /* for increment expression */
+};
+
+extern tree
+convert_to_void (tree expr, impl_conv_void implicit);
+
+// The lvalue-to-rvalue conversion (7.1) is applied if and only if the
+// expression is a glvalue of volatile-qualified type and it is one of the
+// following:
+// * ( expression ), where expression is one of these expressions,
+// * id-expression (8.1.4),
+// * subscripting (8.2.1),
+// * class member access (8.2.5),
+// * indirection (8.3.1),
+// * pointer-to-member operation (8.5),
+// * conditional expression (8.16) where both the second and the third
+// operands are one of these expressions, or
+// * comma expression (8.19) where the right operand is one of these
+// expressions.
+extern tree
+mark_discarded_use (tree expr);
+
+// Mark EXP as read, not just set, for set but not used -Wunused warning
+// purposes.
+extern void
+mark_exp_read (tree exp);
+
+// We've seen an actual use of EXPR. Possibly replace an outer variable
+// reference inside with its constant value or a lambda capture.
+extern tree
+mark_use (tree expr, bool rvalue_p, bool read_p, location_t loc,
+ bool reject_builtin);
+
+// Called whenever the expression EXPR is used in an rvalue context.
+// When REJECT_BUILTIN is true the expression is checked to make sure
+// it doesn't make it possible to obtain the address of a GCC built-in
+// function with no library fallback (or any of its bits, such as in
+// a conversion to bool).
+extern tree
+mark_rvalue_use (tree e, location_t loc /* = UNKNOWN_LOCATION */,
+ bool reject_builtin /* = true */);
+
+// Called whenever an expression is used in an lvalue context.
+extern tree
+mark_lvalue_use (tree expr);
+
+// As above, but don't consider this use a read.
+extern tree
+mark_lvalue_use_nonread (tree expr);
+
+// We are using a reference VAL for its value. Bash that reference all the way
+// down to its lowest form.
+extern tree
+convert_from_reference (tree val);
+
+// Subroutine of convert_to_void. Warn if we're discarding something with
+// attribute [[nodiscard]].
+extern void
+maybe_warn_nodiscard (tree expr, impl_conv_void implicit);
+
+extern location_t
+expr_loc_or_loc (const_tree t, location_t or_loc);
+
+extern location_t
+expr_loc_or_input_loc (const_tree t);
+
+// FN is the callee of a CALL_EXPR or AGGR_INIT_EXPR; return the FUNCTION_DECL
+// if we can.
+extern tree
+get_fndecl_from_callee (tree fn);
+
+} // namespace Rust
+
+#endif // RUST_TREE