aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/resolve
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-01-25 17:03:36 +0000
committerPhilip Herron <herron.philip@googlemail.com>2021-01-27 10:42:25 +0000
commit8578c61be5061fab91fe679a15fd68ab5fad987c (patch)
treef09524d5f8bf17fab00618ef7e8e98fd905a557e /gcc/rust/resolve
parent854aad3b58e747cad3e46b522c9ef765bdfadca4 (diff)
downloadgcc-8578c61be5061fab91fe679a15fd68ab5fad987c.zip
gcc-8578c61be5061fab91fe679a15fd68ab5fad987c.tar.gz
gcc-8578c61be5061fab91fe679a15fd68ab5fad987c.tar.bz2
Add mutablity checks and left hand size assignee checker
In order to assign to a name we must ensure the LHS is a valid expression to assign to. This leads onto actually checking if this is a mutable declaration or not. Once these checks pass the name resolver we can in GIMPLE create immutable types for these declarations to help with optimization. Fixes #77
Diffstat (limited to 'gcc/rust/resolve')
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h7
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.h15
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-pattern.h2
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-stmt.h8
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-toplevel.h1
-rw-r--r--gcc/rust/resolve/rust-ast-verify-assignee.h83
-rw-r--r--gcc/rust/resolve/rust-name-resolver.h36
7 files changed, 151 insertions, 1 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
index 229b26a..9366818 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -22,6 +22,7 @@
#include "rust-ast-resolve-base.h"
#include "rust-ast-full.h"
#include "rust-ast-resolve-struct-expr-field.h"
+#include "rust-ast-verify-assignee.h"
namespace Rust {
namespace Resolver {
@@ -94,6 +95,9 @@ public:
{
ResolveExpr::go (expr.get_left_expr ().get (), expr.get_node_id ());
ResolveExpr::go (expr.get_right_expr ().get (), expr.get_node_id ());
+
+ // need to verify the assignee
+ VerifyAsignee::go (expr.get_left_expr ().get (), expr.get_node_id ());
}
void visit (AST::IdentifierExpr &expr)
@@ -120,6 +124,9 @@ public:
{
ResolveExpr::go (expr.get_left_expr ().get (), expr.get_node_id ());
ResolveExpr::go (expr.get_right_expr ().get (), expr.get_node_id ());
+
+ // need to verify the assignee
+ VerifyAsignee::go (expr.get_left_expr ().get (), expr.get_node_id ());
}
void visit (AST::ComparisonExpr &expr)
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index 02d6dfa..0f45ba0 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -62,12 +62,22 @@ public:
{
ResolveType::go (var.get_type ().get (), var.get_node_id ());
ResolveExpr::go (var.get_expr ().get (), var.get_node_id ());
+
+ // the mutability checker needs to verify for immutable decls the number
+ // of assignments are <1. This marks an implicit assignment
+ resolver->mark_assignment_to_decl (var.get_node_id (), var.get_node_id ());
}
void visit (AST::ConstantItem &constant)
{
ResolveType::go (constant.get_type ().get (), constant.get_node_id ());
ResolveExpr::go (constant.get_expr ().get (), constant.get_node_id ());
+
+ // the mutability checker needs to verify for immutable decls the number
+ // of assignments are <1. This marks an implicit assignment
+ resolver->mark_decl_mutability (constant.get_node_id (), false);
+ resolver->mark_assignment_to_decl (constant.get_node_id (),
+ constant.get_node_id ());
}
void visit (AST::Function &function)
@@ -89,6 +99,11 @@ public:
ResolveType::go (param.get_type ().get (), param.get_node_id ());
PatternDeclaration::go (param.get_pattern ().get (),
param.get_node_id ());
+
+ // the mutability checker needs to verify for immutable decls the number
+ // of assignments are <1. This marks an implicit assignment
+ resolver->mark_assignment_to_decl (param.get_pattern ()->get_node_id (),
+ param.get_node_id ());
}
// resolve the function body
diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h
index c79f7d3..f7618ab 100644
--- a/gcc/rust/resolve/rust-ast-resolve-pattern.h
+++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h
@@ -86,6 +86,8 @@ public:
resolver->insert_new_definition (pattern.get_node_id (),
Definition{pattern.get_node_id (),
parent});
+ resolver->mark_decl_mutability (pattern.get_node_id (),
+ pattern.get_is_mut ());
}
private:
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h
index 6d751e6..8904ce9 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.h
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
@@ -52,7 +52,13 @@ public:
void visit (AST::LetStmt &stmt)
{
if (stmt.has_init_expr ())
- ResolveExpr::go (stmt.get_init_expr ().get (), stmt.get_node_id ());
+ {
+ ResolveExpr::go (stmt.get_init_expr ().get (), stmt.get_node_id ());
+
+ // mark the assignment
+ resolver->mark_assignment_to_decl (stmt.get_pattern ()->get_node_id (),
+ stmt.get_node_id ());
+ }
PatternDeclaration::go (stmt.get_pattern ().get (), stmt.get_node_id ());
if (stmt.has_type ())
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
index 47435a7..90f9cd6 100644
--- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -57,6 +57,7 @@ public:
resolver->insert_new_definition (var.get_node_id (),
Definition{var.get_node_id (),
var.get_node_id ()});
+ resolver->mark_decl_mutability (var.get_node_id (), var.is_mutable ());
}
void visit (AST::ConstantItem &constant)
diff --git a/gcc/rust/resolve/rust-ast-verify-assignee.h b/gcc/rust/resolve/rust-ast-verify-assignee.h
new file mode 100644
index 0000000..6cfe2c2
--- /dev/null
+++ b/gcc/rust/resolve/rust-ast-verify-assignee.h
@@ -0,0 +1,83 @@
+// Copyright (C) 2020 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_AST_VERIFY_ASSIGNEE
+#define RUST_AST_VERIFY_ASSIGNEE
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class VerifyAsignee : public ResolverBase
+{
+public:
+ static bool go (AST::Expr *assignee, NodeId parent)
+ {
+ VerifyAsignee checker (parent);
+ assignee->accept_vis (checker);
+ if (!checker.ok)
+ rust_error_at (assignee->get_locus_slow (),
+ "invalid left-hand side of assignment");
+ return checker.ok;
+ }
+
+ void visit (AST::ArrayIndexExpr &expr)
+ {
+ expr.get_array_expr ()->accept_vis (*this);
+ }
+
+ void visit (AST::FieldAccessExpr &expr)
+ {
+ expr.get_receiver_expr ()->accept_vis (*this);
+ }
+
+ void visit (AST::TupleIndexExpr &expr)
+ {
+ expr.get_tuple_expr ()->accept_vis (*this);
+ }
+
+ void visit (AST::IdentifierExpr &expr)
+ {
+ if (!resolver->get_name_scope ().lookup (expr.as_string (), &resolved_node))
+ return;
+
+ ok = true;
+ // mark the assignment to the name
+ resolver->mark_assignment_to_decl (resolved_node, parent);
+
+ // check is mutable
+ if (!resolver->decl_is_mutable (resolved_node))
+ {
+ // we only allow a single assignment to immutable decls
+ if (resolver->get_num_assignments_to_decl (resolved_node) > 1)
+ rust_error_at (expr.get_locus (), "cannot assign to immutable");
+ }
+ }
+
+private:
+ VerifyAsignee (NodeId parent) : ResolverBase (parent), ok (false) {}
+
+ bool ok;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_VERIFY_ASSIGNEE
diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h
index 4d98e7f..5bc6aba 100644
--- a/gcc/rust/resolve/rust-name-resolver.h
+++ b/gcc/rust/resolve/rust-name-resolver.h
@@ -235,6 +235,37 @@ public:
void set_unit_type_node_id (NodeId id) { unit_ty_node_id = id; }
NodeId get_unit_type_node_id () { return unit_ty_node_id; }
+ void mark_decl_mutability (NodeId id, bool mut)
+ {
+ rust_assert (decl_mutability.find (id) == decl_mutability.end ());
+ decl_mutability[id] = mut;
+ }
+
+ bool decl_is_mutable (NodeId id) const
+ {
+ auto it = decl_mutability.find (id);
+ rust_assert (it != decl_mutability.end ());
+ return it->second;
+ }
+
+ void mark_assignment_to_decl (NodeId id, NodeId assignment)
+ {
+ auto it = assignment_to_decl.find (id);
+ if (it == assignment_to_decl.end ())
+ assignment_to_decl[id] = {};
+
+ assignment_to_decl[id].insert (assignment);
+ }
+
+ size_t get_num_assignments_to_decl (NodeId id) const
+ {
+ auto it = assignment_to_decl.find (id);
+ if (it == assignment_to_decl.end ())
+ return 0;
+
+ return it->second.size ();
+ }
+
private:
Resolver ();
@@ -269,6 +300,11 @@ private:
// we need two namespaces one for names and ones for types
std::map<NodeId, NodeId> resolved_names;
std::map<NodeId, NodeId> resolved_types;
+
+ // map of resolved names mutability flag
+ std::map<NodeId, bool> decl_mutability;
+ // map of resolved names and set of assignments to the decl
+ std::map<NodeId, std::set<NodeId> > assignment_to_decl;
};
} // namespace Resolver