Skip to content

Commit

Permalink
gccrs: port over readonly_error from c-family for lvalue assignment c…
Browse files Browse the repository at this point in the history
…hecks

Fixes Rust-GCC#2391

gcc/rust/ChangeLog:

	* Make-lang.in: fixup formatting
	* resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): remove old check
	* rust-session-manager.cc (Session::compile_crate): call new lint
	* resolve/rust-ast-verify-assignee.h: Removed.
	* checks/errors/rust-readonly-check.cc: New file.
	* checks/errors/rust-readonly-check.h: New file.

gcc/testsuite/ChangeLog:

	* rust/compile/wrong_lhs_assignment.rs: update error message
	* rust/compile/issue-2391.rs: New test.

Signed-off-by: Philip Herron <herron.philip@googlemail.com>
  • Loading branch information
philberty authored and CohenArthur committed Nov 21, 2023
1 parent ebe9d56 commit e38e7a5
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 107 deletions.
25 changes: 13 additions & 12 deletions gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ GRS_OBJS = \
rust/rust-compile-resolve-path.o \
rust/rust-macro-expand.o \
rust/rust-cfg-strip.o \
rust/rust-expand-visitor.o \
rust/rust-ast-builder.o \
rust/rust-derive.o \
rust/rust-derive-clone.o \
rust/rust-derive-copy.o \
rust/rust-proc-macro.o \
rust/rust-expand-visitor.o \
rust/rust-ast-builder.o \
rust/rust-derive.o \
rust/rust-derive-clone.o \
rust/rust-derive-copy.o \
rust/rust-proc-macro.o \
rust/rust-macro-invoc-lexer.o \
rust/rust-proc-macro-invoc-lexer.o \
rust/rust-macro-substitute-ctx.o \
Expand All @@ -101,19 +101,19 @@ GRS_OBJS = \
rust/rust-attributes.o \
rust/rust-abi.o \
rust/rust-token-converter.o \
rust/rust-macro.o \
rust/rust-macro.o \
rust/rust-ast-lower.o \
rust/rust-ast-lower-base.o \
rust/rust-ast-lower-pattern.o \
rust/rust-ast-lower-item.o \
rust/rust-ast-lower-expr.o \
rust/rust-ast-lower-type.o \
rust/rust-ast-lower-stmt.o \
rust/rust-rib.o \
rust/rust-name-resolution-context.o \
rust/rust-default-resolver.o \
rust/rust-ast-lower-stmt.o \
rust/rust-rib.o \
rust/rust-name-resolution-context.o \
rust/rust-default-resolver.o \
rust/rust-toplevel-name-resolver-2.0.o \
rust/rust-early-name-resolver-2.0.o \
rust/rust-early-name-resolver-2.0.o \
rust/rust-early-name-resolver.o \
rust/rust-name-resolver.o \
rust/rust-ast-resolve.o \
Expand Down Expand Up @@ -160,6 +160,7 @@ GRS_OBJS = \
rust/rust-const-checker.o \
rust/rust-lint-marklive.o \
rust/rust-lint-unused-var.o \
rust/rust-readonly-check.o \
rust/rust-hir-type-check-path.o \
rust/rust-unsafe-checker.o \
rust/rust-compile-intrinsic.o \
Expand Down
164 changes: 164 additions & 0 deletions gcc/rust/checks/errors/rust-readonly-check.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// Copyright (C) 2021-2023 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-readonly-check.h"
#include "rust-tree.h"
#include "rust-gcc.h"

namespace Rust {
namespace Analysis {

// ported over from c-family/c-warn.cc
void
readonly_error (location_t loc, tree arg, enum lvalue_use use)
{
gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
|| use == lv_asm);
STRIP_ANY_LOCATION_WRAPPER (arg);
/* Using this macro rather than (for example) arrays of messages
ensures that all the format strings are checked at compile
time. */
#define READONLY_MSG(A, I, D, AS) \
(use == lv_assign \
? (A) \
: (use == lv_increment ? (I) : (use == lv_decrement ? (D) : (AS))))
if (TREE_CODE (arg) == COMPONENT_REF)
{
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
error_at (loc,
READONLY_MSG (G_ ("assignment of member "
"%qD in read-only object"),
G_ ("increment of member "
"%qD in read-only object"),
G_ ("decrement of member "
"%qD in read-only object"),
G_ ("member %qD in read-only object "
"used as %<asm%> output")),
TREE_OPERAND (arg, 1));
else
error_at (
loc,
READONLY_MSG (G_ ("assignment of read-only member %qD"),
G_ ("increment of read-only member %qD"),
G_ ("decrement of read-only member %qD"),
G_ ("read-only member %qD used as %<asm%> output")),
TREE_OPERAND (arg, 1));
}
else if (VAR_P (arg))
error_at (loc,
READONLY_MSG (G_ ("assignment of read-only variable %qD"),
G_ ("increment of read-only variable %qD"),
G_ ("decrement of read-only variable %qD"),
G_ (
"read-only variable %qD used as %<asm%> output")),
arg);
else if (TREE_CODE (arg) == PARM_DECL)
error_at (loc,
READONLY_MSG (G_ ("assignment of read-only parameter %qD"),
G_ ("increment of read-only parameter %qD"),
G_ ("decrement of read-only parameter %qD"),
G_ (
"read-only parameter %qD use as %<asm%> output")),
arg);
else if (TREE_CODE (arg) == RESULT_DECL)
{
error_at (loc,
READONLY_MSG (G_ ("assignment of "
"read-only named return value %qD"),
G_ ("increment of "
"read-only named return value %qD"),
G_ ("decrement of "
"read-only named return value %qD"),
G_ ("read-only named return value %qD "
"used as %<asm%>output")),
arg);
}
else if (TREE_CODE (arg) == FUNCTION_DECL)
error_at (loc,
READONLY_MSG (G_ ("assignment of function %qD"),
G_ ("increment of function %qD"),
G_ ("decrement of function %qD"),
G_ ("function %qD used as %<asm%> output")),
arg);
else
error_at (loc,
READONLY_MSG (G_ ("assignment of read-only location %qE"),
G_ ("increment of read-only location %qE"),
G_ ("decrement of read-only location %qE"),
G_ (
"read-only location %qE used as %<asm%> output")),
arg);
}

static void
check_decl (tree *t)
{
if (TREE_CODE (*t) == MODIFY_EXPR)
{
tree lhs = TREE_OPERAND (*t, 0);
if (TREE_READONLY (lhs) || TREE_CONSTANT (lhs))
{
readonly_error (EXPR_LOCATION (*t), lhs, lv_assign);
TREE_OPERAND (*t, 0) = error_mark_node;
}
}
}

static tree
readonly_walk_fn (tree *t, int *, void *)
{
switch (TREE_CODE (*t))
{
case MODIFY_EXPR:
check_decl (t);
break;

default:
break;
}
return NULL_TREE;
}

void
ReadonlyCheck::Lint (Compile::Context &ctx)
{
for (auto &fndecl : ctx.get_func_decls ())
{
for (tree p = DECL_ARGUMENTS (fndecl); p != NULL_TREE; p = DECL_CHAIN (p))
{
check_decl (&p);
}

walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
&readonly_walk_fn, &ctx);
}

for (auto &var : ctx.get_var_decls ())
{
tree decl = var->get_decl ();
check_decl (&decl);
}

for (auto &const_decl : ctx.get_const_decls ())
{
check_decl (&const_decl);
}
}

} // namespace Analysis
} // namespace Rust
36 changes: 36 additions & 0 deletions gcc/rust/checks/errors/rust-readonly-check.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (C) 2021-2023 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_READONLY_CHECK
#define RUST_READONLY_CHECK

#include "rust-compile-context.h"

namespace Rust {
namespace Analysis {

class ReadonlyCheck
{
public:
static void Lint (Compile::Context &ctx);
};

} // namespace Analysis
} // namespace Rust

#endif // RUST_READONLY_CHECK
7 changes: 0 additions & 7 deletions gcc/rust/resolve/rust-ast-resolve-expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include "rust-ast-resolve-expr.h"
#include "rust-ast-resolve-stmt.h"
#include "rust-ast-resolve-struct-expr-field.h"
#include "rust-ast-verify-assignee.h"
#include "rust-ast-resolve-type.h"
#include "rust-ast-resolve-pattern.h"
#include "rust-ast-resolve-path.h"
Expand Down Expand Up @@ -101,9 +100,6 @@ ResolveExpr::visit (AST::AssignmentExpr &expr)
{
ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);

// need to verify the assignee
VerifyAsignee::go (expr.get_left_expr ().get ());
}

/* The "break rust" Easter egg.
Expand Down Expand Up @@ -191,9 +187,6 @@ ResolveExpr::visit (AST::CompoundAssignmentExpr &expr)
{
ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);

// need to verify the assignee
VerifyAsignee::go (expr.get_left_expr ().get ());
}

void
Expand Down
84 changes: 0 additions & 84 deletions gcc/rust/resolve/rust-ast-verify-assignee.h

This file was deleted.

4 changes: 2 additions & 2 deletions gcc/rust/rust-session-manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
#include "rust-cfg-parser.h"
#include "rust-lint-scan-deadcode.h"
#include "rust-lint-unused-var.h"
#include "rust-readonly-check.h"
#include "rust-hir-dump.h"
#include "rust-ast-dump.h"
#include "rust-ast-collector.h"
#include "rust-export-metadata.h"
#include "rust-imports.h"
#include "rust-extern-crate.h"
Expand All @@ -47,7 +47,6 @@
#include "rust-unicode.h"
#include "rust-attribute-values.h"

#include "diagnostic.h"
#include "input.h"
#include "selftest.h"
#include "tm.h"
Expand Down Expand Up @@ -676,6 +675,7 @@ Session::compile_crate (const char *filename)
// lints
Analysis::ScanDeadcode::Scan (hir);
Analysis::UnusedVariables::Lint (ctx);
Analysis::ReadonlyCheck::Lint (ctx);

// metadata
bool specified_emit_metadata
Expand Down
Loading

0 comments on commit e38e7a5

Please sign in to comment.