public inbox for gcc-rust@gcc.gnu.org
 help / color / mirror / Atom feed
From: arthur.cohen@embecosm.com
To: gcc-patches@gcc.gnu.org
Cc: gcc-rust@gcc.gnu.org, Arthur Cohen <arthur.cohen@embecosm.com>
Subject: [PATCH Rust front-end v4 32/46] gccrs: Add privacy checks
Date: Tue,  6 Dec 2022 11:14:04 +0100	[thread overview]
Message-ID: <20221206101417.778807-33-arthur.cohen@embecosm.com> (raw)
In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com>

From: Arthur Cohen <arthur.cohen@embecosm.com>

This pass is responsible for resolving the privacy of items and verifying
that access to these items is performed within the limits of that privacy.
By default, items in Rust are private and only public to the current
module and its submodules. However, the user can annotate an item with
various qualifiers such as `pub` to publicly expose an item. Furthermore,
a module path can be given to `pub` to restrict an item's privacy to a
certain module: These paths need to be resolved and later on checked by
the privacy error reporter.
---
 .../errors/privacy/rust-privacy-check.cc      |  63 ++
 .../errors/privacy/rust-privacy-check.h       |  44 +
 .../errors/privacy/rust-privacy-common.h      |  67 ++
 .../checks/errors/privacy/rust-privacy-ctx.cc |  93 +++
 .../checks/errors/privacy/rust-privacy-ctx.h  |  79 ++
 .../errors/privacy/rust-privacy-reporter.cc   | 771 ++++++++++++++++++
 .../errors/privacy/rust-privacy-reporter.h    | 173 ++++
 .../privacy/rust-pub-restricted-visitor.cc    | 182 +++++
 .../privacy/rust-pub-restricted-visitor.h     | 120 +++
 .../errors/privacy/rust-reachability.cc       | 236 ++++++
 .../checks/errors/privacy/rust-reachability.h |  87 ++
 .../privacy/rust-visibility-resolver.cc       | 245 ++++++
 .../errors/privacy/rust-visibility-resolver.h | 103 +++
 13 files changed, 2263 insertions(+)
 create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-check.cc
 create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-check.h
 create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-common.h
 create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-ctx.cc
 create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-ctx.h
 create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
 create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
 create mode 100644 gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.cc
 create mode 100644 gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.h
 create mode 100644 gcc/rust/checks/errors/privacy/rust-reachability.cc
 create mode 100644 gcc/rust/checks/errors/privacy/rust-reachability.h
 create mode 100644 gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc
 create mode 100644 gcc/rust/checks/errors/privacy/rust-visibility-resolver.h

diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-check.cc b/gcc/rust/checks/errors/privacy/rust-privacy-check.cc
new file mode 100644
index 00000000000..9664d62f65c
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-check.cc
@@ -0,0 +1,63 @@
+// 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-privacy-check.h"
+#include "rust-reachability.h"
+#include "rust-hir-type-check.h"
+#include "rust-hir-map.h"
+#include "rust-name-resolver.h"
+#include "rust-visibility-resolver.h"
+#include "rust-pub-restricted-visitor.h"
+#include "rust-privacy-reporter.h"
+
+extern bool
+saw_errors (void);
+
+namespace Rust {
+namespace Privacy {
+
+void
+Resolver::resolve (HIR::Crate &crate)
+{
+  PrivacyContext ctx;
+  auto mappings = Analysis::Mappings::get ();
+  auto resolver = Rust::Resolver::Resolver::get ();
+  auto ty_ctx = ::Rust::Resolver::TypeCheckContext::get ();
+
+  VisibilityResolver (*mappings, *resolver).go (crate);
+  PubRestrictedVisitor (*mappings).go (crate);
+  PrivacyReporter (*mappings, *resolver, *ty_ctx).go (crate);
+
+  auto visitor = ReachabilityVisitor (ctx, *ty_ctx);
+
+  const auto &items = crate.items;
+
+  for (auto &item : items)
+    {
+      if (item->get_hir_kind () == HIR::Node::VIS_ITEM)
+	{
+	  auto vis_item = static_cast<HIR::VisItem *> (item.get ());
+	  vis_item->accept_vis (visitor);
+	}
+    }
+
+  if (saw_errors ())
+    return;
+}
+} // namespace Privacy
+} // namespace Rust
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-check.h b/gcc/rust/checks/errors/privacy/rust-privacy-check.h
new file mode 100644
index 00000000000..290b5eacb6c
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-check.h
@@ -0,0 +1,44 @@
+// 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_PRIVACY_CHECK_H
+#define RUST_PRIVACY_CHECK_H
+
+#include "rust-hir.h"
+#include "rust-hir-expr.h"
+#include "rust-hir-stmt.h"
+#include "rust-hir-item.h"
+#include "rust-hir-type-check.h"
+
+namespace Rust {
+namespace Privacy {
+class Resolver
+{
+public:
+  /**
+   * Perform the full privacy resolving pass on a crate.
+   *
+   * This resolver first computes the reachability of all items in a crate,
+   * before checking for privacy violations.
+   */
+  static void resolve (HIR::Crate &crate);
+};
+} // namespace Privacy
+} // namespace Rust
+
+#endif // !RUST_PRIVACY_CHECK_H
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-common.h b/gcc/rust/checks/errors/privacy/rust-privacy-common.h
new file mode 100644
index 00000000000..ceafe91d886
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-common.h
@@ -0,0 +1,67 @@
+// 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-mapping-common.h"
+
+namespace Rust {
+namespace Privacy {
+
+/**
+ * Visibility class related specifically to DefIds. This class allows defining
+ * the visibility of an item with regard to a specific module.
+ *
+ * Items are either public throughout a crate, or restricted to a specific
+ * module. Private items are simply restricted to the current module.
+ */
+class ModuleVisibility
+{
+public:
+  enum Type
+  {
+    Unknown,
+    Public,
+    Restricted,
+  };
+
+  ModuleVisibility () : kind (Unknown), module_id (UNKNOWN_DEFID) {}
+
+  static ModuleVisibility create_restricted (DefId module_id)
+  {
+    return ModuleVisibility (Type::Restricted, module_id);
+  }
+
+  static ModuleVisibility create_public ()
+  {
+    return ModuleVisibility (Type::Public, UNKNOWN_DEFID);
+  }
+
+  Type get_kind () const { return kind; }
+
+  const DefId &get_module_id () const { return module_id; }
+  DefId &get_module_id () { return module_id; }
+
+private:
+  ModuleVisibility (Type kind, DefId module_id)
+    : kind (kind), module_id (module_id)
+  {}
+
+  Type kind;
+  DefId module_id;
+};
+} // namespace Privacy
+} // namespace Rust
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-ctx.cc b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.cc
new file mode 100644
index 00000000000..9ebc86988e9
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.cc
@@ -0,0 +1,93 @@
+// 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-privacy-ctx.h"
+#include "selftest.h"
+
+namespace Rust {
+namespace Privacy {
+
+static ReachLevel
+insert_if_higher (ReachLevel new_level,
+		  std::unordered_map<DefId, ReachLevel>::iterator &existing)
+{
+  if (new_level > existing->second)
+    existing->second = new_level;
+
+  return existing->second;
+}
+
+ReachLevel
+PrivacyContext::update_reachability (const Analysis::NodeMapping &mapping,
+				     ReachLevel reach)
+{
+  auto def_id = mapping.get_defid ();
+  auto existing_reach = reachability_map.find (def_id);
+  if (existing_reach != reachability_map.end ())
+    return insert_if_higher (reach, existing_reach);
+
+  reachability_map.insert ({def_id, reach});
+  return reach;
+}
+
+const ReachLevel *
+PrivacyContext::lookup_reachability (const Analysis::NodeMapping &mapping)
+{
+  auto existing_reach = reachability_map.find (mapping.get_defid ());
+  if (existing_reach == reachability_map.end ())
+    return nullptr;
+
+  return &existing_reach->second;
+}
+} // namespace Privacy
+} // namespace Rust
+
+#if CHECKING_P
+namespace selftest {
+static void
+update_reachability_test (void)
+{
+  auto ctx = Rust::Privacy::PrivacyContext ();
+  // Bogus values for the mappings
+  auto mapping = Rust::Analysis::NodeMapping (15, 15, 15, 15);
+
+  auto new_level
+    = ctx.update_reachability (mapping, Rust::Privacy::ReachLevel::Unreachable);
+
+  ASSERT_EQ (new_level, Rust::Privacy::ReachLevel::Unreachable);
+
+  ASSERT_TRUE (ctx.lookup_reachability (mapping));
+  ASSERT_EQ (*ctx.lookup_reachability (mapping),
+	     Rust::Privacy::ReachLevel::Unreachable);
+
+  new_level
+    = ctx.update_reachability (mapping, Rust::Privacy::ReachLevel::Reachable);
+
+  ASSERT_EQ (new_level, Rust::Privacy::ReachLevel::Reachable);
+  ASSERT_TRUE (ctx.lookup_reachability (mapping));
+  ASSERT_EQ (*ctx.lookup_reachability (mapping),
+	     Rust::Privacy::ReachLevel::Reachable);
+}
+
+void
+rust_privacy_ctx_test (void)
+{
+  update_reachability_test ();
+}
+} // namespace selftest
+#endif // !CHECKING_P
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h
new file mode 100644
index 00000000000..52d790edf63
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h
@@ -0,0 +1,79 @@
+// 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_PRIVACY_CTX_H
+#define RUST_PRIVACY_CTX_H
+
+#include "rust-hir-map.h"
+#include "rust-privacy-check.h"
+
+namespace Rust {
+namespace Privacy {
+
+/**
+ * Reachability levels of HIR nodes. These levels are computed through the
+ * `ReachabilityVisitor` visitor.
+ */
+enum ReachLevel
+{
+  Unreachable,
+  Reachable,
+};
+
+class PrivacyContext
+{
+public:
+  /**
+   * Insert a new resolved visibility for a given node. If the node is already
+   * present in the reachability map, then its visibility will only be updated
+   * if the given visibility is higher.
+   *
+   * @param mappings Mappings of the node to store the reach level for
+   * @param reach Level of reachability for the given node
+   *
+   * @return The new reachability level for this node. If this was the first
+   * time inserting this node, then return `reach`. Otherwise, return `reach` or
+   * the existing reach level if it was higher.
+   */
+  ReachLevel update_reachability (const Analysis::NodeMapping &mapping,
+				  ReachLevel reach);
+
+  /**
+   * Lookup the visibility of an already declared Node
+   *
+   * @param mapping Mappings of the node to fetch the reach level of
+   *
+   * @return `nullptr` if the reach level for the current node has not been
+   * added, a valid pointer otherwise
+   */
+  const ReachLevel *lookup_reachability (const Analysis::NodeMapping &mapping);
+
+private:
+  std::unordered_map<DefId, ReachLevel> reachability_map;
+};
+} // namespace Privacy
+} // namespace Rust
+
+#if CHECKING_P
+namespace selftest {
+void
+rust_privacy_ctx_test (void);
+}
+#endif // !CHECKING_P
+
+#endif // !RUST_PRIVACY_CTX_H
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
new file mode 100644
index 00000000000..3c9380af732
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
@@ -0,0 +1,771 @@
+// 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-privacy-reporter.h"
+#include "rust-hir-expr.h"
+#include "rust-hir-stmt.h"
+#include "rust-hir-item.h"
+
+namespace Rust {
+namespace Privacy {
+
+PrivacyReporter::PrivacyReporter (
+  Analysis::Mappings &mappings, Resolver::Resolver &resolver,
+  const Rust::Resolver::TypeCheckContext &ty_ctx)
+  : mappings (mappings), resolver (resolver), ty_ctx (ty_ctx),
+    current_module (Optional<NodeId>::none ())
+{}
+
+void
+PrivacyReporter::go (HIR::Crate &crate)
+{
+  for (auto &item : crate.items)
+    item->accept_vis (*this);
+}
+
+static bool
+is_child_module (Analysis::Mappings &mappings, NodeId parent,
+		 NodeId possible_child)
+{
+  auto children = mappings.lookup_module_children (parent);
+
+  if (!children)
+    return false;
+
+  // Visit all toplevel children
+  for (auto &child : *children)
+    if (child == possible_child)
+      return true;
+
+  // Now descend recursively in the child module tree
+  for (auto &child : *children)
+    if (is_child_module (mappings, child, possible_child))
+      return true;
+
+  return false;
+}
+
+// FIXME: This function needs a lot of refactoring
+void
+PrivacyReporter::check_for_privacy_violation (const NodeId &use_id,
+					      const Location &locus)
+{
+  NodeId ref_node_id = UNKNOWN_NODEID;
+
+  // FIXME: Don't assert here - we might be dealing with a type
+  if (!resolver.lookup_resolved_name (use_id, &ref_node_id))
+    resolver.lookup_resolved_type (use_id, &ref_node_id);
+
+  // FIXME: Assert here. For now, we return since this causes issues when
+  // checking inferred types (#1260)
+  // rust_assert (ref_node_id != UNKNOWN_NODEID);
+  if (ref_node_id == UNKNOWN_NODEID)
+    return;
+
+  ModuleVisibility vis;
+
+  // FIXME: Can we really return here if the item has no visibility?
+  if (!mappings.lookup_visibility (ref_node_id, vis))
+    return;
+
+  auto valid = true;
+
+  switch (vis.get_kind ())
+    {
+    case ModuleVisibility::Public:
+      break;
+      case ModuleVisibility::Restricted: {
+	// If we are in the crate, everything is restricted correctly, but we
+	// can't get a module for it
+	if (current_module.is_none ())
+	  return;
+
+	auto module = mappings.lookup_defid (vis.get_module_id ());
+	rust_assert (module != nullptr);
+
+	auto mod_node_id = module->get_mappings ().get_nodeid ();
+
+	// We are in the module referenced by the pub(restricted) visibility.
+	// This is valid
+	if (mod_node_id == current_module.get ())
+	  break;
+
+	// FIXME: This needs a LOT of TLC: hinting about the definition, a
+	// string to say if it's a module, function, type, etc...
+	if (!is_child_module (mappings, mod_node_id, current_module.get ()))
+	  valid = false;
+      }
+      break;
+    case ModuleVisibility::Unknown:
+      rust_unreachable ();
+      break;
+    }
+
+  if (!valid)
+    rust_error_at (locus, "definition is private in this context");
+}
+
+void
+PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings,
+					  const TyTy::BaseType *ty,
+					  const Location &locus)
+{
+  // Avoids repeating commong argument such as `use_id` or `locus` since we're
+  // doing a lot of recursive calls here
+  auto recursive_check
+    = [this, &node_mappings, &locus] (const TyTy::BaseType *ty) {
+	return check_base_type_privacy (node_mappings, ty, locus);
+      };
+
+  switch (ty->get_kind ())
+    {
+      // These "simple" types are our stop condition
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::ADT:
+      case TyTy::STR: {
+	auto ref_id = ty->get_ref ();
+	NodeId lookup_id;
+
+	bool ok = mappings.lookup_hir_to_node (ref_id, &lookup_id);
+	rust_assert (ok);
+
+	return check_for_privacy_violation (lookup_id, locus);
+      }
+    case TyTy::REF:
+      return recursive_check (
+	static_cast<const TyTy::ReferenceType *> (ty)->get_base ());
+    case TyTy::POINTER:
+      return recursive_check (
+	static_cast<const TyTy::PointerType *> (ty)->get_base ());
+    case TyTy::ARRAY:
+      return recursive_check (
+	static_cast<const TyTy::ArrayType *> (ty)->get_element_type ());
+    case TyTy::SLICE:
+      return recursive_check (
+	static_cast<const TyTy::SliceType *> (ty)->get_element_type ());
+    case TyTy::FNPTR:
+      for (auto &param : static_cast<const TyTy::FnPtr *> (ty)->get_params ())
+	recursive_check (param.get_tyty ());
+      return recursive_check (
+	static_cast<const TyTy::FnPtr *> (ty)->get_return_type ());
+    case TyTy::TUPLE:
+      for (auto &param :
+	   static_cast<const TyTy::TupleType *> (ty)->get_fields ())
+	recursive_check (param.get_tyty ());
+      return;
+    case TyTy::PLACEHOLDER:
+      return recursive_check (
+	// FIXME: Can we use `resolve` here? Is that what we should do?
+	static_cast<const TyTy::PlaceholderType *> (ty)->resolve ());
+    case TyTy::PROJECTION:
+      return recursive_check (
+	static_cast<const TyTy::ProjectionType *> (ty)->get ());
+    case TyTy::CLOSURE:
+      rust_sorry_at (locus, "privacy pass for closures is not handled yet");
+      break;
+
+      // If we're dealing with a generic param, there's nothing we should be
+      // doing here
+    case TyTy::PARAM:
+      // We are dealing with a function definition that has been assigned
+      // somewhere else. Nothing to resolve privacy-wise other than the actual
+      // function, which is resolved as an expression
+    case TyTy::FNDEF:
+      // FIXME: Can we really not resolve Dynamic types here? Shouldn't we have
+      // a look at the path and perform proper privacy analysis?
+    case TyTy::DYNAMIC:
+      // The never type is builtin and always available
+    case TyTy::NEVER:
+      // We shouldn't have inference types here, ever
+    case TyTy::INFER:
+      return;
+    case TyTy::ERROR:
+      rust_unreachable ();
+    }
+}
+
+void
+PrivacyReporter::check_type_privacy (const HIR::Type *type)
+{
+  rust_assert (type);
+
+  TyTy::BaseType *lookup = nullptr;
+  rust_assert (
+    ty_ctx.lookup_type (type->get_mappings ().get_hirid (), &lookup));
+
+  auto node_mappings = type->get_mappings ();
+  return check_base_type_privacy (node_mappings, lookup, type->get_locus ());
+}
+
+void
+PrivacyReporter::visit (HIR::PathInExpression &path)
+{
+  check_for_privacy_violation (path.get_mappings ().get_nodeid (),
+			       path.get_locus ());
+}
+
+void
+PrivacyReporter::visit (HIR::TypePathSegmentFunction &segment)
+{
+  // FIXME: Do we need to do anything for this?
+}
+
+void
+PrivacyReporter::visit (HIR::TypePath &path)
+{
+  check_for_privacy_violation (path.get_mappings ().get_nodeid (),
+			       path.get_locus ());
+}
+
+void
+PrivacyReporter::visit (HIR::QualifiedPathInExpression &path)
+{
+  check_for_privacy_violation (path.get_mappings ().get_nodeid (),
+			       path.get_locus ());
+}
+
+void
+PrivacyReporter::visit (HIR::QualifiedPathInType &path)
+{
+  check_for_privacy_violation (path.get_mappings ().get_nodeid (),
+			       path.get_locus ());
+}
+
+void
+PrivacyReporter::visit (HIR::LiteralExpr &expr)
+{
+  // Literals cannot contain any sort of privacy violation
+}
+
+void
+PrivacyReporter::visit (HIR::BorrowExpr &expr)
+{
+  expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::DereferenceExpr &expr)
+{
+  expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::ErrorPropagationExpr &expr)
+{
+  expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::NegationExpr &expr)
+{
+  expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::ArithmeticOrLogicalExpr &expr)
+{
+  expr.get_lhs ()->accept_vis (*this);
+  expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::ComparisonExpr &expr)
+{
+  expr.get_lhs ()->accept_vis (*this);
+  expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::LazyBooleanExpr &expr)
+{
+  expr.get_lhs ()->accept_vis (*this);
+  expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::TypeCastExpr &expr)
+{
+  expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::AssignmentExpr &expr)
+{
+  expr.get_lhs ()->accept_vis (*this);
+  expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::CompoundAssignmentExpr &expr)
+{
+  expr.get_left_expr ()->accept_vis (*this);
+  expr.get_right_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::GroupedExpr &expr)
+{
+  expr.get_expr_in_parens ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::ArrayExpr &expr)
+{
+  HIR::ArrayElems &elements = *expr.get_internal_elements ();
+  switch (elements.get_array_expr_type ())
+    {
+      case HIR::ArrayElems::ArrayExprType::VALUES: {
+	HIR::ArrayElemsValues &elems
+	  = static_cast<HIR::ArrayElemsValues &> (elements);
+	for (auto &value : elems.get_values ())
+	  value->accept_vis (*this);
+      }
+      return;
+
+    case HIR::ArrayElems::ArrayExprType::COPIED:
+      HIR::ArrayElemsCopied &elems
+	= static_cast<HIR::ArrayElemsCopied &> (elements);
+      elems.get_elem_to_copy ()->accept_vis (*this);
+    }
+}
+
+void
+PrivacyReporter::visit (HIR::ArrayIndexExpr &expr)
+{
+  expr.get_array_expr ()->accept_vis (*this);
+  expr.get_index_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::TupleExpr &expr)
+{
+  for (auto &value : expr.get_tuple_elems ())
+    value->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::TupleIndexExpr &expr)
+{
+  expr.get_tuple_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::StructExprStruct &expr)
+{
+  // FIXME: We need to check the visibility of the type it refers to here
+}
+
+void
+PrivacyReporter::visit (HIR::StructExprFieldIdentifier &field)
+{}
+
+void
+PrivacyReporter::visit (HIR::StructExprFieldIdentifierValue &field)
+{
+  field.get_value ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::StructExprFieldIndexValue &field)
+{
+  field.get_value ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::StructExprStructFields &expr)
+{
+  for (auto &field : expr.get_fields ())
+    field->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::CallExpr &expr)
+{
+  expr.get_fnexpr ()->accept_vis (*this);
+
+  for (auto &param : expr.get_arguments ())
+    param->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::MethodCallExpr &expr)
+{
+  expr.get_receiver ()->accept_vis (*this);
+
+  for (auto &param : expr.get_arguments ())
+    param->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::FieldAccessExpr &expr)
+{
+  expr.get_receiver_expr ()->accept_vis (*this);
+
+  // FIXME: We should also check if the field is public?
+}
+
+void
+PrivacyReporter::visit (HIR::ClosureExprInner &expr)
+{
+  // Not handled yet
+}
+
+void
+PrivacyReporter::visit (HIR::BlockExpr &expr)
+{
+  for (auto &stmt : expr.get_statements ())
+    stmt->accept_vis (*this);
+
+  auto &last_expr = expr.get_final_expr ();
+  if (last_expr)
+    last_expr->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::ClosureExprInnerTyped &expr)
+{
+  // Not handled yet
+}
+
+void
+PrivacyReporter::visit (HIR::ContinueExpr &expr)
+{}
+
+void
+PrivacyReporter::visit (HIR::BreakExpr &expr)
+{
+  auto &break_expr = expr.get_expr ();
+  if (break_expr)
+    break_expr->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::RangeFromToExpr &expr)
+{
+  expr.get_from_expr ()->accept_vis (*this);
+  expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::RangeFromExpr &expr)
+{
+  expr.get_from_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::RangeToExpr &expr)
+{
+  expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::RangeFullExpr &expr)
+{}
+
+void
+PrivacyReporter::visit (HIR::RangeFromToInclExpr &expr)
+{
+  expr.get_from_expr ()->accept_vis (*this);
+  expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::RangeToInclExpr &expr)
+{
+  // Not handled yet
+}
+
+void
+PrivacyReporter::visit (HIR::ReturnExpr &expr)
+{
+  auto return_expr = expr.get_expr ();
+  if (return_expr)
+    return_expr->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::UnsafeBlockExpr &expr)
+{
+  expr.get_block_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::LoopExpr &expr)
+{
+  expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::WhileLoopExpr &expr)
+{
+  expr.get_predicate_expr ()->accept_vis (*this);
+  expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::WhileLetLoopExpr &expr)
+{
+  expr.get_cond ()->accept_vis (*this);
+  expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::ForLoopExpr &expr)
+{
+  expr.get_iterator_expr ()->accept_vis (*this);
+  expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::IfExpr &expr)
+{
+  expr.get_if_condition ()->accept_vis (*this);
+  expr.get_if_block ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::IfExprConseqElse &expr)
+{
+  expr.get_if_condition ()->accept_vis (*this);
+  expr.get_if_block ()->accept_vis (*this);
+  expr.get_else_block ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::IfExprConseqIf &expr)
+{
+  expr.get_if_condition ()->accept_vis (*this);
+  expr.get_if_block ()->accept_vis (*this);
+  expr.get_conseq_if_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::IfExprConseqIfLet &expr)
+{
+  expr.get_if_condition ()->accept_vis (*this);
+  expr.get_if_block ()->accept_vis (*this);
+
+  // TODO: We need to visit the if_let_expr as well
+}
+
+void
+PrivacyReporter::visit (HIR::IfLetExpr &expr)
+{
+  // TODO: We need to visit the if_let_expr
+  // TODO: We need to visit the block as well
+}
+
+void
+PrivacyReporter::visit (HIR::IfLetExprConseqElse &expr)
+{
+  // TODO: We need to visit the if_let_expr
+  // TODO: We need to visit the if_block as well
+  // TODO: We need to visit the else_block as well
+}
+
+void
+PrivacyReporter::visit (HIR::IfLetExprConseqIf &expr)
+{
+  // TODO: We need to visit the if_let_expr
+  // TODO: We need to visit the if_block as well
+  // TODO: We need to visit the else_block as well
+}
+
+void
+PrivacyReporter::visit (HIR::IfLetExprConseqIfLet &expr)
+{
+  // TODO: We need to visit the if_let_expr
+  // TODO: We need to visit the if_block as well
+  // TODO: We need to visit the else_block as well
+}
+
+void
+PrivacyReporter::visit (HIR::MatchExpr &expr)
+{
+  expr.get_scrutinee_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::AwaitExpr &expr)
+{
+  // Not handled yet
+}
+
+void
+PrivacyReporter::visit (HIR::AsyncBlockExpr &expr)
+{
+  // Not handled yet
+}
+
+void
+PrivacyReporter::visit (HIR::Module &module)
+{
+  // FIXME: We also need to think about module privacy
+
+  auto old_module = current_module;
+  current_module
+    = Optional<NodeId>::some (module.get_mappings ().get_nodeid ());
+
+  for (auto &item : module.get_items ())
+    item->accept_vis (*this);
+
+  current_module = old_module;
+}
+
+void
+PrivacyReporter::visit (HIR::ExternCrate &crate)
+{}
+
+void
+PrivacyReporter::visit (HIR::UseDeclaration &use_decl)
+{
+  // FIXME: Is there anything we need to do here?
+}
+
+void
+PrivacyReporter::visit (HIR::Function &function)
+{
+  for (auto &param : function.get_function_params ())
+    check_type_privacy (param.get_type ());
+
+  function.get_definition ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::TypeAlias &type_alias)
+{
+  // TODO: Check the type here
+}
+
+void
+PrivacyReporter::visit (HIR::StructStruct &struct_item)
+{
+  // TODO: Check the type of all fields
+}
+
+void
+PrivacyReporter::visit (HIR::TupleStruct &tuple_struct)
+{
+  // TODO: Check the type of all fields
+}
+
+void
+PrivacyReporter::visit (HIR::EnumItem &item)
+{
+  // TODO: Check the type of all variants
+}
+
+void
+PrivacyReporter::visit (HIR::EnumItemTuple &item)
+{
+  // TODO: Check the type
+}
+
+void
+PrivacyReporter::visit (HIR::EnumItemStruct &item)
+{
+  // TODO: Check the type
+}
+
+void
+PrivacyReporter::visit (HIR::EnumItemDiscriminant &item)
+{}
+
+void
+PrivacyReporter::visit (HIR::Enum &enum_item)
+{}
+
+void
+PrivacyReporter::visit (HIR::Union &union_item)
+{
+  // TODO: Check the type
+}
+
+void
+PrivacyReporter::visit (HIR::ConstantItem &const_item)
+{
+  // TODO: We need to visit the type
+  const_item.get_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::StaticItem &static_item)
+{
+  // TODO: We need to visit the type
+  static_item.get_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::Trait &trait)
+{
+  // FIXME: We need to be an ItemVisitor as well
+  // for (auto &item : trait.get_trait_items ())
+  //   item->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::ImplBlock &impl)
+{
+  for (auto &item : impl.get_impl_items ())
+    item->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::ExternBlock &block)
+{
+  // FIXME: We need to be an ItemVisitor as well
+  // for (auto &item : block.get_extern_items ())
+  //   item->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::EmptyStmt &stmt)
+{}
+
+void
+PrivacyReporter::visit (HIR::LetStmt &stmt)
+{
+  auto type = stmt.get_type ();
+  if (type)
+    check_type_privacy (type);
+
+  auto init_expr = stmt.get_init_expr ();
+  if (init_expr)
+    init_expr->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::ExprStmtWithoutBlock &stmt)
+{
+  stmt.get_expr ()->accept_vis (*this);
+}
+
+void
+PrivacyReporter::visit (HIR::ExprStmtWithBlock &stmt)
+{
+  stmt.get_expr ()->accept_vis (*this);
+}
+
+} // namespace Privacy
+} // namespace Rust
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
new file mode 100644
index 00000000000..546b108f36d
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
@@ -0,0 +1,173 @@
+// 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_PRIVACY_REPORTER_H
+#define RUST_PRIVACY_REPORTER_H
+
+#include "rust-hir-map.h"
+#include "rust-hir-visitor.h"
+#include "rust-mapping-common.h"
+#include "rust-name-resolver.h"
+
+namespace Rust {
+namespace Privacy {
+
+/**
+ * This visitor visits all items and expressions of a crate and reports privacy
+ * violations. It should be started after using the `VisibilityResolver` visitor
+ * which resolves the visibilities of all items of a crate.
+ */
+class PrivacyReporter : public HIR::HIRExpressionVisitor,
+			public HIR::HIRStmtVisitor
+{
+public:
+  PrivacyReporter (Analysis::Mappings &mappings,
+		   Rust::Resolver::Resolver &resolver,
+		   const Rust::Resolver::TypeCheckContext &ty_ctx);
+
+  /**
+   * Perform privacy error reporting on an entire crate
+   */
+  void go (HIR::Crate &crate);
+
+private:
+  /**
+   * Check if a given item's visibility is accessible from the current module.
+   *
+   * This function reports the errors it finds.
+   *
+   * @param use_id NodeId of the expression/statement referencing an item with
+   * 		a visibility
+   * @param locus Location of said expression/statement
+   */
+  void check_for_privacy_violation (const NodeId &use_id,
+				    const Location &locus);
+
+  /**
+   * Internal function used by `check_type_privacy` when dealing with complex
+types
+   * such as references or arrays
+   */
+  void check_base_type_privacy (Analysis::NodeMapping &node_mappings,
+				const TyTy::BaseType *ty,
+				const Location &locus);
+
+  /**
+   * Check the privacy of an explicit type.
+   *
+   * This function reports the errors it finds.
+   *
+   * @param type Reference to an explicit type used in a statement, expression
+   * 		or parameter
+   */
+  void check_type_privacy (const HIR::Type *type);
+
+  virtual void visit (HIR::StructExprFieldIdentifier &field);
+  virtual void visit (HIR::StructExprFieldIdentifierValue &field);
+  virtual void visit (HIR::StructExprFieldIndexValue &field);
+
+  virtual void visit (HIR::QualifiedPathInExpression &expr);
+  virtual void visit (HIR::PathInExpression &expr);
+  virtual void visit (HIR::ClosureExprInnerTyped &);
+  virtual void visit (HIR::ClosureExprInner &expr);
+  virtual void visit (HIR::StructExprStructFields &);
+  virtual void visit (HIR::StructExprStruct &);
+  virtual void visit (HIR::LiteralExpr &expr);
+  virtual void visit (HIR::BorrowExpr &expr);
+  virtual void visit (HIR::DereferenceExpr &expr);
+  virtual void visit (HIR::ErrorPropagationExpr &expr);
+  virtual void visit (HIR::NegationExpr &expr);
+  virtual void visit (HIR::ArithmeticOrLogicalExpr &expr);
+  virtual void visit (HIR::ComparisonExpr &expr);
+  virtual void visit (HIR::LazyBooleanExpr &expr);
+  virtual void visit (HIR::TypeCastExpr &expr);
+  virtual void visit (HIR::AssignmentExpr &expr);
+  virtual void visit (HIR::CompoundAssignmentExpr &expr);
+  virtual void visit (HIR::GroupedExpr &expr);
+  virtual void visit (HIR::ArrayExpr &expr);
+  virtual void visit (HIR::ArrayIndexExpr &expr);
+  virtual void visit (HIR::TupleExpr &expr);
+  virtual void visit (HIR::TupleIndexExpr &expr);
+  virtual void visit (HIR::CallExpr &expr);
+  virtual void visit (HIR::MethodCallExpr &expr);
+  virtual void visit (HIR::FieldAccessExpr &expr);
+  virtual void visit (HIR::BlockExpr &expr);
+  virtual void visit (HIR::ContinueExpr &expr);
+  virtual void visit (HIR::BreakExpr &expr);
+  virtual void visit (HIR::RangeFromToExpr &expr);
+  virtual void visit (HIR::RangeFromExpr &expr);
+  virtual void visit (HIR::RangeToExpr &expr);
+  virtual void visit (HIR::RangeFullExpr &expr);
+  virtual void visit (HIR::RangeFromToInclExpr &expr);
+  virtual void visit (HIR::RangeToInclExpr &expr);
+  virtual void visit (HIR::ReturnExpr &expr);
+  virtual void visit (HIR::UnsafeBlockExpr &expr);
+  virtual void visit (HIR::LoopExpr &expr);
+  virtual void visit (HIR::WhileLoopExpr &expr);
+  virtual void visit (HIR::WhileLetLoopExpr &expr);
+  virtual void visit (HIR::ForLoopExpr &expr);
+  virtual void visit (HIR::IfExpr &expr);
+  virtual void visit (HIR::IfExprConseqElse &expr);
+  virtual void visit (HIR::IfExprConseqIf &expr);
+  virtual void visit (HIR::IfExprConseqIfLet &expr);
+  virtual void visit (HIR::IfLetExpr &expr);
+  virtual void visit (HIR::IfLetExprConseqElse &expr);
+  virtual void visit (HIR::IfLetExprConseqIf &expr);
+  virtual void visit (HIR::IfLetExprConseqIfLet &expr);
+  virtual void visit (HIR::MatchExpr &expr);
+  virtual void visit (HIR::AwaitExpr &expr);
+  virtual void visit (HIR::AsyncBlockExpr &expr);
+
+  virtual void visit (HIR::EnumItemTuple &);
+  virtual void visit (HIR::EnumItemStruct &);
+  virtual void visit (HIR::EnumItem &item);
+  virtual void visit (HIR::TupleStruct &tuple_struct);
+  virtual void visit (HIR::EnumItemDiscriminant &);
+  virtual void visit (HIR::TypePathSegmentFunction &segment);
+  virtual void visit (HIR::TypePath &path);
+  virtual void visit (HIR::QualifiedPathInType &path);
+  virtual void visit (HIR::Module &module);
+  virtual void visit (HIR::ExternCrate &crate);
+  virtual void visit (HIR::UseDeclaration &use_decl);
+  virtual void visit (HIR::Function &function);
+  virtual void visit (HIR::TypeAlias &type_alias);
+  virtual void visit (HIR::StructStruct &struct_item);
+  virtual void visit (HIR::Enum &enum_item);
+  virtual void visit (HIR::Union &union_item);
+  virtual void visit (HIR::ConstantItem &const_item);
+  virtual void visit (HIR::StaticItem &static_item);
+  virtual void visit (HIR::Trait &trait);
+  virtual void visit (HIR::ImplBlock &impl);
+  virtual void visit (HIR::ExternBlock &block);
+  virtual void visit (HIR::EmptyStmt &stmt);
+  virtual void visit (HIR::LetStmt &stmt);
+  virtual void visit (HIR::ExprStmtWithoutBlock &stmt);
+  virtual void visit (HIR::ExprStmtWithBlock &stmt);
+
+  Analysis::Mappings &mappings;
+  Rust::Resolver::Resolver &resolver;
+  const Rust::Resolver::TypeCheckContext &ty_ctx;
+
+  // `None` means we're in the root module - the crate
+  Optional<NodeId> current_module;
+};
+
+} // namespace Privacy
+} // namespace Rust
+
+#endif // !RUST_PRIVACY_REPORTER_H
diff --git a/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.cc b/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.cc
new file mode 100644
index 00000000000..e391653ea26
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.cc
@@ -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/>.
+
+#include "rust-pub-restricted-visitor.h"
+#include "rust-hir.h"
+#include "rust-hir-item.h"
+
+namespace Rust {
+namespace Privacy {
+
+bool
+PubRestrictedVisitor::is_restriction_valid (NodeId item_id,
+					    const Location &locus)
+{
+  ModuleVisibility visibility;
+
+  // If there is no visibility in the mappings, then the item is private and
+  // does not contain any restriction
+  // FIXME: Is that correct?
+  if (!mappings.lookup_visibility (item_id, visibility))
+    return true;
+
+  for (auto mod = module_stack.rbegin (); mod != module_stack.rend (); mod++)
+    if (*mod == visibility.get_module_id ())
+      return true;
+
+  rust_error_at (locus, "restricted path is not an ancestor of the "
+			"current module");
+  return false;
+}
+
+PubRestrictedVisitor::PubRestrictedVisitor (Analysis::Mappings &mappings)
+  : mappings (mappings)
+{}
+
+void
+PubRestrictedVisitor::go (HIR::Crate &crate)
+{
+  // The `crate` module will always be present
+  module_stack.emplace_back (crate.get_mappings ().get_defid ());
+
+  // FIXME: When do we insert `super`? `self`?
+  // We need wrapper function for these
+
+  for (auto &item : crate.items)
+    {
+      if (item->get_hir_kind () == HIR::Node::VIS_ITEM)
+	{
+	  auto vis_item = static_cast<HIR::VisItem *> (item.get ());
+	  vis_item->accept_vis (*this);
+	}
+    }
+}
+
+void
+PubRestrictedVisitor::visit (HIR::Module &mod)
+{
+  // FIXME: We need to update `super` and `self` here
+  module_stack.push_back (mod.get_mappings ().get_defid ());
+
+  is_restriction_valid (mod.get_mappings ().get_nodeid (), mod.get_locus ());
+
+  for (auto &item : mod.get_items ())
+    {
+      if (item->get_hir_kind () == HIR::Node::VIS_ITEM)
+	{
+	  auto vis_item = static_cast<HIR::VisItem *> (item.get ());
+	  vis_item->accept_vis (*this);
+	}
+    }
+
+  module_stack.pop_back ();
+}
+
+void
+PubRestrictedVisitor::visit (HIR::ExternCrate &crate)
+{
+  is_restriction_valid (crate.get_mappings ().get_nodeid (),
+			crate.get_locus ());
+}
+
+void
+PubRestrictedVisitor::visit (HIR::UseDeclaration &use_decl)
+{
+  is_restriction_valid (use_decl.get_mappings ().get_nodeid (),
+			use_decl.get_locus ());
+}
+
+void
+PubRestrictedVisitor::visit (HIR::Function &func)
+{
+  is_restriction_valid (func.get_mappings ().get_nodeid (), func.get_locus ());
+}
+
+void
+PubRestrictedVisitor::visit (HIR::TypeAlias &type_alias)
+{
+  is_restriction_valid (type_alias.get_mappings ().get_nodeid (),
+			type_alias.get_locus ());
+}
+
+void
+PubRestrictedVisitor::visit (HIR::StructStruct &struct_item)
+{
+  is_restriction_valid (struct_item.get_mappings ().get_nodeid (),
+			struct_item.get_locus ());
+  // FIXME: Check fields here as well
+}
+
+void
+PubRestrictedVisitor::visit (HIR::TupleStruct &tuple_struct)
+{
+  is_restriction_valid (tuple_struct.get_mappings ().get_nodeid (),
+			tuple_struct.get_locus ());
+  // FIXME: Check fields here as well
+}
+
+void
+PubRestrictedVisitor::visit (HIR::Enum &enum_item)
+{
+  is_restriction_valid (enum_item.get_mappings ().get_nodeid (),
+			enum_item.get_locus ());
+}
+
+void
+PubRestrictedVisitor::visit (HIR::Union &union_item)
+{
+  is_restriction_valid (union_item.get_mappings ().get_nodeid (),
+			union_item.get_locus ());
+}
+
+void
+PubRestrictedVisitor::visit (HIR::ConstantItem &const_item)
+{
+  is_restriction_valid (const_item.get_mappings ().get_nodeid (),
+			const_item.get_locus ());
+}
+
+void
+PubRestrictedVisitor::visit (HIR::StaticItem &static_item)
+{
+  is_restriction_valid (static_item.get_mappings ().get_nodeid (),
+			static_item.get_locus ());
+}
+
+void
+PubRestrictedVisitor::visit (HIR::Trait &trait)
+{
+  is_restriction_valid (trait.get_mappings ().get_nodeid (),
+			trait.get_locus ());
+}
+
+void
+PubRestrictedVisitor::visit (HIR::ImplBlock &impl)
+{
+  is_restriction_valid (impl.get_mappings ().get_nodeid (), impl.get_locus ());
+}
+
+void
+PubRestrictedVisitor::visit (HIR::ExternBlock &block)
+{
+  is_restriction_valid (block.get_mappings ().get_nodeid (),
+			block.get_locus ());
+}
+
+} // namespace Privacy
+} // namespace Rust
diff --git a/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.h b/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.h
new file mode 100644
index 00000000000..2685f3d1488
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.h
@@ -0,0 +1,120 @@
+// 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_PUB_RESTRICTED_VISITOR_H
+#define RUST_PUB_RESTRICTED_VISITOR_H
+
+#include "rust-hir-visitor.h"
+#include "rust-hir.h"
+#include "rust-hir-expr.h"
+#include "rust-hir-stmt.h"
+#include "rust-hir-item.h"
+#include "rust-hir-map.h"
+
+namespace Rust {
+namespace Privacy {
+
+/**
+ * This visitor takes care of reporting `pub(restricted)` violations:
+ * A `pub(restricted)` violation is defined as the usage of a path restriction
+ * on an item which does not restrict the item's visibility to one of its parent
+ * modules. What this means is that an user is allowed to specify that an item
+ * should be public for any of its parent modules, going all the way to the
+ * `crate` module, but not for any of its children module.
+ *
+ * ```rust
+ * mod a {
+ * 	mod b {
+ * 		pub (in a) struct A0;
+ *
+ * 		mod c {
+ * 			mod d {
+ * 				pub (in a) struct A1;
+ * 			}
+ * 		}
+ *
+ * 		pub (in c::d) struct A2;
+ * 	}
+ * }
+ * ```
+ *
+ * The above `A0`'s visibility is valid: It is restricted to a path, `a`,
+ * which is a parent of the current module, `b`.
+ * Likewise, `A1` is also defined properly: `a` is a parent of `d`, albeit
+ * a great-great-great-grandparant of it.
+ *
+ * `A2` visibility, however, is invalid: Where the struct is defined, the
+ * current module is `b`. `c::d` (which refers to the `d` module) is a child of
+ * `b`, and not one of its ancestors.
+ *
+ * Note that these resolution rules are also the ones of the 2015 rust edition:
+ * All the `pub(restricted)` visibilities above would be invalid in the 2018
+ * edition, as the paths there must be absolute and not relative (`c::d` would
+ * become `crate::a::b::c::d` etc). Nonetheless, the logic stays the same.
+ */
+class PubRestrictedVisitor : public HIR::HIRVisItemVisitor
+{
+public:
+  PubRestrictedVisitor (Analysis::Mappings &mappings);
+
+  void go (HIR::Crate &crate);
+
+  /**
+   * Check if an item's restricted visibility (`pub (crate)`, `pub (self)`,
+   * `pub(super)`, `pub (in <path>)`) is valid in the current context.
+   * `pub restricted` visibilities are only allowed when the restriction path
+   * is a parent module of the item being visited.
+   *
+   * In case of error, this function will emit the errors and return.
+   *
+   * @param item_id NodeId of the item to check the restriction of
+   * @param locus Location of the item being checked
+   *
+   * @return true if the visibility restriction is valid, false otherwise.
+   */
+  bool is_restriction_valid (NodeId item_id, const Location &locus);
+
+  virtual void visit (HIR::Module &mod);
+  virtual void visit (HIR::ExternCrate &crate);
+  virtual void visit (HIR::UseDeclaration &use_decl);
+  virtual void visit (HIR::Function &func);
+  virtual void visit (HIR::TypeAlias &type_alias);
+  virtual void visit (HIR::StructStruct &struct_item);
+  virtual void visit (HIR::TupleStruct &tuple_struct);
+  virtual void visit (HIR::Enum &enum_item);
+  virtual void visit (HIR::Union &union_item);
+  virtual void visit (HIR::ConstantItem &const_item);
+  virtual void visit (HIR::StaticItem &static_item);
+  virtual void visit (HIR::Trait &trait);
+  virtual void visit (HIR::ImplBlock &impl);
+  virtual void visit (HIR::ExternBlock &block);
+
+private:
+  /* Stack of ancestor modules visited by this visitor */
+  std::vector<DefId> module_stack;
+
+  // FIXME: Do we have to handle `self` and `super` as part of the name
+  // resolution pass?
+
+  Analysis::Mappings &mappings;
+};
+
+} // namespace Privacy
+} // namespace Rust
+
+#endif // !RUST_PUB_RESTRICTED_VISITOR_H
diff --git a/gcc/rust/checks/errors/privacy/rust-reachability.cc b/gcc/rust/checks/errors/privacy/rust-reachability.cc
new file mode 100644
index 00000000000..b322e29bfc3
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-reachability.cc
@@ -0,0 +1,236 @@
+// 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-reachability.h"
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Privacy {
+
+static HIR::VisItem *
+maybe_get_vis_item (std::unique_ptr<HIR::Item> &item)
+{
+  if (item->get_hir_kind () != HIR::Node::VIS_ITEM)
+    return nullptr;
+
+  return static_cast<HIR::VisItem *> (item.get ());
+}
+
+ReachLevel
+ReachabilityVisitor::get_reachability_level (
+  const HIR::Visibility &item_visibility)
+{
+  return item_visibility.is_public () ? current_level : ReachLevel::Unreachable;
+}
+
+void
+ReachabilityVisitor::visit_generic_predicates (
+  const std::vector<std::unique_ptr<HIR::GenericParam>> &generics,
+  ReachLevel item_reach)
+{
+  if (item_reach == ReachLevel::Unreachable)
+    return;
+
+  for (const auto &generic : generics)
+    {
+      if (generic->get_kind () == HIR::GenericParam::GenericKind::TYPE)
+	{
+	  TyTy::BaseType *generic_ty = nullptr;
+	  auto ok = ty_ctx.lookup_type (generic->get_mappings ().get_hirid (),
+					&generic_ty);
+	  rust_assert (ok);
+	  rust_assert (generic_ty->get_kind () == TyTy::PARAM);
+
+	  auto generic_param = static_cast<TyTy::ParamType *> (generic_ty);
+	  for (const auto &bound : generic_param->get_specified_bounds ())
+	    {
+	      const auto trait = bound.get ()->get_hir_trait_ref ();
+	      ctx.update_reachability (trait->get_mappings (), item_reach);
+	    }
+	}
+    }
+}
+
+void
+ReachabilityVisitor::visit (HIR::Module &mod)
+{
+  auto reach = get_reachability_level (mod.get_visibility ());
+  reach = ctx.update_reachability (mod.get_mappings (), reach);
+
+  for (auto &item : mod.get_items ())
+    {
+      // FIXME: Is that what we want to do? Yes? Only visit the items with
+      // visibility?
+      //
+      // Imagine if we had `maybe_get_vis_item(item)?->accept_vis(*this)` ;)
+      auto vis_item = maybe_get_vis_item (item);
+      if (vis_item)
+	vis_item->accept_vis (*this);
+    }
+}
+
+void
+ReachabilityVisitor::visit (HIR::ExternCrate &crate)
+{
+  auto reach = get_reachability_level (crate.get_visibility ());
+  reach = ctx.update_reachability (crate.get_mappings (), reach);
+}
+
+void
+ReachabilityVisitor::visit (HIR::UseDeclaration &use_decl)
+{
+  auto reach = get_reachability_level (use_decl.get_visibility ());
+  reach = ctx.update_reachability (use_decl.get_mappings (), reach);
+}
+
+void
+ReachabilityVisitor::visit (HIR::Function &func)
+{
+  auto fn_reach = get_reachability_level (func.get_visibility ());
+
+  fn_reach = ctx.update_reachability (func.get_mappings (), fn_reach);
+  visit_generic_predicates (func.get_generic_params (), fn_reach);
+}
+
+void
+ReachabilityVisitor::visit (HIR::TypeAlias &type_alias)
+{
+  auto type_reach = get_reachability_level (type_alias.get_visibility ());
+
+  visit_generic_predicates (type_alias.get_generic_params (), type_reach);
+}
+
+void
+ReachabilityVisitor::visit (HIR::StructStruct &struct_item)
+{
+  auto struct_reach = get_reachability_level (struct_item.get_visibility ());
+
+  struct_reach
+    = ctx.update_reachability (struct_item.get_mappings (), struct_reach);
+
+  auto old_level = current_level;
+  current_level = struct_reach;
+
+  visit_generic_predicates (struct_item.get_generic_params (), struct_reach);
+
+  if (struct_reach != ReachLevel::Unreachable)
+    {
+      for (auto &field : struct_item.get_fields ())
+	if (field.get_visibility ().is_public ())
+	  ctx.update_reachability (field.get_field_type ()->get_mappings (),
+				   struct_reach);
+    }
+
+  current_level = old_level;
+}
+
+void
+ReachabilityVisitor::visit (HIR::TupleStruct &tuple_struct)
+{}
+
+void
+ReachabilityVisitor::visit (HIR::Enum &enum_item)
+{
+  auto enum_reach = get_reachability_level (enum_item.get_visibility ());
+
+  enum_reach = ctx.update_reachability (enum_item.get_mappings (), enum_reach);
+  visit_generic_predicates (enum_item.get_generic_params (), enum_reach);
+
+  for (const auto &variant : enum_item.get_variants ())
+    {
+      auto variant_reach
+	= ctx.update_reachability (variant->get_mappings (), enum_reach);
+
+      switch (variant->get_enum_item_kind ())
+	{
+	  case HIR::EnumItem::Tuple: {
+	    // Should we update the fields only if they are public? Similarly to
+	    // what we do in the ReachabilityVisitor for HIR::TupleStruct?
+	    auto tuple_variant
+	      = static_cast<HIR::EnumItemTuple *> (variant.get ());
+	    for (const auto &field : tuple_variant->get_tuple_fields ())
+	      ctx.update_reachability (field.get_mappings (), variant_reach);
+	    break;
+	  }
+	  case HIR::EnumItem::Struct: {
+	    // Should we update the fields only if they are public? Similarly to
+	    // what we do in the ReachabilityVisitor for HIR::StructStruct?
+	    auto struct_variant
+	      = static_cast<HIR::EnumItemStruct *> (variant.get ());
+	    for (const auto &field : struct_variant->get_struct_fields ())
+	      ctx.update_reachability (field.get_mappings (), variant_reach);
+	    break;
+	  }
+	// Nothing nested to visit in that case
+	case HIR::EnumItem::Named:
+	case HIR::EnumItem::Discriminant:
+	  break;
+	}
+    }
+}
+
+void
+ReachabilityVisitor::visit (HIR::Union &union_item)
+{
+  auto union_reach = get_reachability_level (union_item.get_visibility ());
+
+  union_reach
+    = ctx.update_reachability (union_item.get_mappings (), union_reach);
+  visit_generic_predicates (union_item.get_generic_params (), union_reach);
+}
+
+void
+ReachabilityVisitor::visit (HIR::ConstantItem &const_item)
+{
+  auto reach = get_reachability_level (const_item.get_visibility ());
+  reach = ctx.update_reachability (const_item.get_mappings (), reach);
+}
+
+void
+ReachabilityVisitor::visit (HIR::StaticItem &static_item)
+{
+  auto reach = get_reachability_level (static_item.get_visibility ());
+  reach = ctx.update_reachability (static_item.get_mappings (), reach);
+}
+
+void
+ReachabilityVisitor::visit (HIR::Trait &trait)
+{
+  auto trait_reach = get_reachability_level (trait.get_visibility ());
+
+  trait_reach = ctx.update_reachability (trait.get_mappings (), trait_reach);
+  visit_generic_predicates (trait.get_generic_params (), trait_reach);
+}
+
+void
+ReachabilityVisitor::visit (HIR::ImplBlock &impl)
+{
+  auto impl_reach = get_reachability_level (impl.get_visibility ());
+
+  impl_reach = ctx.update_reachability (impl.get_mappings (), impl_reach);
+  visit_generic_predicates (impl.get_generic_params (), impl_reach);
+}
+
+void
+ReachabilityVisitor::visit (HIR::ExternBlock &block)
+{}
+
+// FIXME: How can we visit Blocks in the current configuration? Have a full
+// visitor?
+} // namespace Privacy
+} // namespace Rust
diff --git a/gcc/rust/checks/errors/privacy/rust-reachability.h b/gcc/rust/checks/errors/privacy/rust-reachability.h
new file mode 100644
index 00000000000..e0bc4f5f0b8
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-reachability.h
@@ -0,0 +1,87 @@
+// 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_REACHABILITY_H
+#define RUST_REACHABILITY_H
+
+#include "rust-privacy-ctx.h"
+#include "rust-hir-visitor.h"
+#include "rust-hir.h"
+#include "rust-hir-expr.h"
+#include "rust-hir-stmt.h"
+#include "rust-hir-item.h"
+#include "rust-hir-type-check.h"
+
+namespace Rust {
+namespace Privacy {
+
+// FIXME: The EmbargoVisitor from rustc is a fixed-point visitor which tries
+// to reach more and more nodes until nothing has changed anymore.
+// Do we need to reproduce this behavior? How long does it take to do this?
+
+/**
+ * The ReachabilityVisitor tries to reach all items possible in the crate,
+ * according to their privacy level.
+ */
+class ReachabilityVisitor : public HIR::HIRVisItemVisitor
+{
+public:
+  ReachabilityVisitor (PrivacyContext &ctx,
+		       const ::Rust::Resolver::TypeCheckContext &ty_ctx)
+    : current_level (ReachLevel::Reachable), ctx (ctx), ty_ctx (ty_ctx)
+  {}
+
+  // FIXME: Add `go` method which takes an `HIR::Crate &` as argument
+
+  /**
+   * Visit all the predicates of all the generic types of a given item, marking
+   * them as reachable or not.
+   */
+  void visit_generic_predicates (
+    const std::vector<std::unique_ptr<HIR::GenericParam>> &generics,
+    ReachLevel item_reach);
+
+  /**
+   * Get the initial reach level for an item based on its visibility.
+   */
+  ReachLevel get_reachability_level (const HIR::Visibility &item_visibility);
+
+  virtual void visit (HIR::Module &mod);
+  virtual void visit (HIR::ExternCrate &crate);
+  virtual void visit (HIR::UseDeclaration &use_decl);
+  virtual void visit (HIR::Function &func);
+  virtual void visit (HIR::TypeAlias &type_alias);
+  virtual void visit (HIR::StructStruct &struct_item);
+  virtual void visit (HIR::TupleStruct &tuple_struct);
+  virtual void visit (HIR::Enum &enum_item);
+  virtual void visit (HIR::Union &union_item);
+  virtual void visit (HIR::ConstantItem &const_item);
+  virtual void visit (HIR::StaticItem &static_item);
+  virtual void visit (HIR::Trait &trait);
+  virtual void visit (HIR::ImplBlock &impl);
+  virtual void visit (HIR::ExternBlock &block);
+
+private:
+  ReachLevel current_level;
+  PrivacyContext &ctx;
+  const ::Rust::Resolver::TypeCheckContext &ty_ctx;
+};
+} // namespace Privacy
+} // namespace Rust
+
+#endif // !RUST_REACHABILITY_H
diff --git a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc
new file mode 100644
index 00000000000..301182754a4
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc
@@ -0,0 +1,245 @@
+// 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-visibility-resolver.h"
+#include "rust-ast.h"
+#include "rust-hir.h"
+#include "rust-hir-item.h"
+
+namespace Rust {
+namespace Privacy {
+
+VisibilityResolver::VisibilityResolver (Analysis::Mappings &mappings,
+					Resolver::Resolver &resolver)
+  : mappings (mappings), resolver (resolver)
+{}
+
+void
+VisibilityResolver::go (HIR::Crate &crate)
+{
+  mappings.insert_visibility (crate.get_mappings ().get_nodeid (),
+			      ModuleVisibility::create_public ());
+
+  current_module = crate.get_mappings ().get_defid ();
+
+  for (auto &item : crate.items)
+    {
+      if (item->get_hir_kind () == HIR::Node::VIS_ITEM)
+	{
+	  auto vis_item = static_cast<HIR::VisItem *> (item.get ());
+	  vis_item->accept_vis (*this);
+	}
+    }
+}
+
+bool
+VisibilityResolver::resolve_module_path (const HIR::SimplePath &restriction,
+					 DefId &id)
+{
+  // We need, from the restriction, to figure out the actual Module it
+  // belongs to.
+
+  NodeId ast_node_id = restriction.get_mappings ().get_nodeid ();
+
+  auto invalid_path
+    = Error (restriction.get_locus (),
+	     "cannot use non-module path as privacy restrictor");
+
+  NodeId ref_node_id = UNKNOWN_NODEID;
+  if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
+    {
+      invalid_path.emit_error ();
+      return false;
+    }
+  // FIXME: Add a hint here if we can find the path in another scope, such as
+  // a type or something else
+  // TODO: For the hint, can we point to the original item's definition if
+  // present?
+
+  HirId ref;
+  rust_assert (mappings.lookup_node_to_hir (ref_node_id, &ref));
+
+  auto module = mappings.lookup_module (ref);
+  if (!module)
+    {
+      invalid_path.emit_error ();
+      return false;
+    }
+
+  // Fill in the resolved `DefId`
+  id = module->get_mappings ().get_defid ();
+
+  return true;
+}
+
+bool
+VisibilityResolver::resolve_visibility (const HIR::Visibility &visibility,
+					ModuleVisibility &to_resolve)
+{
+  switch (visibility.get_vis_type ())
+    {
+    case HIR::Visibility::PRIVATE:
+      to_resolve = ModuleVisibility::create_restricted (current_module);
+      return true;
+    case HIR::Visibility::PUBLIC:
+      to_resolve = ModuleVisibility::create_public ();
+      return true;
+      case HIR::Visibility::RESTRICTED: {
+	// FIXME: We also need to handle 2015 vs 2018 edition conflicts
+	auto id = UNKNOWN_DEFID;
+	auto result = resolve_module_path (visibility.get_path (), id);
+	to_resolve = ModuleVisibility::create_restricted (id);
+	return result;
+      }
+    default:
+      gcc_unreachable ();
+      return false;
+    }
+}
+
+void
+VisibilityResolver::resolve_and_update (const HIR::VisItem *item)
+{
+  ModuleVisibility module_vis;
+  if (!resolve_visibility (item->get_visibility (), module_vis))
+    return; // we will already have emitted errors
+
+  mappings.insert_visibility (item->get_mappings ().get_nodeid (), module_vis);
+}
+
+void
+VisibilityResolver::visit (HIR::Module &mod)
+{
+  auto old_module = current_module;
+  current_module = mod.get_mappings ().get_defid ();
+
+  for (auto &item : mod.get_items ())
+    {
+      if (item->get_hir_kind () == HIR::Node::VIS_ITEM)
+	{
+	  auto vis_item = static_cast<HIR::VisItem *> (item.get ());
+	  vis_item->accept_vis (*this);
+	}
+    }
+
+  current_module = old_module;
+}
+
+void
+VisibilityResolver::visit (HIR::ExternCrate &crate)
+{}
+
+void
+VisibilityResolver::visit (HIR::UseDeclaration &use_decl)
+{}
+
+void
+VisibilityResolver::visit (HIR::Function &func)
+{
+  resolve_and_update (&func);
+}
+
+void
+VisibilityResolver::visit (HIR::TypeAlias &type_alias)
+{
+  resolve_and_update (&type_alias);
+}
+
+void
+VisibilityResolver::visit (HIR::StructStruct &struct_item)
+{
+  resolve_and_update (&struct_item);
+}
+
+void
+VisibilityResolver::visit (HIR::TupleStruct &tuple_struct)
+{
+  resolve_and_update (&tuple_struct);
+}
+
+void
+VisibilityResolver::visit (HIR::Enum &enum_item)
+{
+  ModuleVisibility vis;
+  if (!resolve_visibility (enum_item.get_visibility (), vis))
+    return;
+
+  mappings.insert_visibility (enum_item.get_mappings ().get_nodeid (), vis);
+  for (auto &variant : enum_item.get_variants ())
+    mappings.insert_visibility (variant->get_mappings ().get_nodeid (), vis);
+}
+
+void
+VisibilityResolver::visit (HIR::Union &union_item)
+{}
+
+void
+VisibilityResolver::visit (HIR::ConstantItem &const_item)
+{
+  resolve_and_update (&const_item);
+}
+
+void
+VisibilityResolver::visit (HIR::StaticItem &static_item)
+{
+  resolve_and_update (&static_item);
+}
+
+void
+VisibilityResolver::visit (HIR::Trait &trait)
+{
+  ModuleVisibility vis;
+  if (!resolve_visibility (trait.get_visibility (), vis))
+    return;
+
+  mappings.insert_visibility (trait.get_mappings ().get_nodeid (), vis);
+  for (auto &item : trait.get_trait_items ())
+    mappings.insert_visibility (item->get_mappings ().get_nodeid (), vis);
+}
+
+void
+VisibilityResolver::visit (HIR::ImplBlock &impl)
+{
+  for (auto &item : impl.get_impl_items ())
+    {
+      HIR::VisItem *vis_item;
+      switch (item->get_impl_item_type ())
+	{
+	case HIR::ImplItem::FUNCTION:
+	  vis_item = static_cast<HIR::Function *> (item.get ());
+	  break;
+	case HIR::ImplItem::TYPE_ALIAS:
+	  vis_item = static_cast<HIR::TypeAlias *> (item.get ());
+	  break;
+	case HIR::ImplItem::CONSTANT:
+	  vis_item = static_cast<HIR::ConstantItem *> (item.get ());
+	  break;
+	default:
+	  gcc_unreachable ();
+	  return;
+	}
+      vis_item->accept_vis (*this);
+    }
+}
+
+void
+VisibilityResolver::visit (HIR::ExternBlock &block)
+{}
+
+} // namespace Privacy
+} // namespace Rust
diff --git a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.h b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.h
new file mode 100644
index 00000000000..20a581c16d4
--- /dev/null
+++ b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.h
@@ -0,0 +1,103 @@
+// 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_VISIBILITY_H
+#define RUST_VISIBILITY_H
+
+#include "rust-hir.h"
+#include "rust-hir-expr.h"
+#include "rust-hir-stmt.h"
+#include "rust-hir-item.h"
+#include "rust-hir-map.h"
+#include "rust-name-resolver.h"
+#include "rust-hir-visitor.h"
+
+namespace Rust {
+namespace Privacy {
+
+class VisibilityResolver : public HIR::HIRVisItemVisitor
+{
+public:
+  VisibilityResolver (Analysis::Mappings &mappings,
+		      Rust::Resolver::Resolver &resolver);
+
+  /**
+   * Perform visibility resolving on an entire crate
+   */
+  void go (HIR::Crate &crate);
+
+  /**
+   * Resolve a path to the module it refers
+   */
+  bool resolve_module_path (const HIR::SimplePath &restriction,
+			    DefId &to_resolve);
+
+  /**
+   * Resolve the visibility of an item to its ModuleVisibility. This function
+   * emits errors if necessary. The contents of the to_resolve parameter will be
+   * overwritten on success.
+   *
+   * @param visibility Visibility of the item to resolve
+   * @param to_resolve ModuleVisibility reference to fill on success.
+   *
+   * @return false on error, true if the resolving was successful.
+   */
+  bool resolve_visibility (const HIR::Visibility &visibility,
+			   ModuleVisibility &to_resolve);
+
+  /**
+   * Resolve the visibility of an item and updates it. This is useful for
+   * vis-items who need to be resolved but do not care about their module
+   * visibility - const items, static items, etc. For items with an impact on
+   * their children (enums, traits), this cannot be used
+   */
+  void resolve_and_update (const HIR::VisItem *item);
+
+  /**
+   * Get the DefId of the parent module we are currently visiting.
+   *
+   * @return UNKNOWN_DEFID if the module stack is empty, a valid `DefId`
+   * otherwise
+   */
+  DefId peek_module ();
+
+  virtual void visit (HIR::Module &mod);
+  virtual void visit (HIR::ExternCrate &crate);
+  virtual void visit (HIR::UseDeclaration &use_decl);
+  virtual void visit (HIR::Function &func);
+  virtual void visit (HIR::TypeAlias &type_alias);
+  virtual void visit (HIR::StructStruct &struct_item);
+  virtual void visit (HIR::TupleStruct &tuple_struct);
+  virtual void visit (HIR::Enum &enum_item);
+  virtual void visit (HIR::Union &union_item);
+  virtual void visit (HIR::ConstantItem &const_item);
+  virtual void visit (HIR::StaticItem &static_item);
+  virtual void visit (HIR::Trait &trait);
+  virtual void visit (HIR::ImplBlock &impl);
+  virtual void visit (HIR::ExternBlock &block);
+
+private:
+  Analysis::Mappings &mappings;
+  Rust::Resolver::Resolver &resolver;
+  DefId current_module;
+};
+
+} // namespace Privacy
+} // namespace Rust
+
+#endif // !RUST_VISIBILITY_H
-- 
2.38.1


  parent reply	other threads:[~2022-12-06 10:12 UTC|newest]

Thread overview: 81+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-06 10:13 Rust front-end patches v4 arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 01/46] Use DW_ATE_UTF for the Rust 'char' type arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 02/46] gccrs: Add necessary hooks for a Rust front-end testsuite arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 03/46] gccrs: Add Debug info testsuite arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 04/46] gccrs: Add link cases testsuite arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 05/46] gccrs: Add general compilation test cases arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 06/46] gccrs: Add execution " arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 07/46] gccrs: Add gcc-check-target check-rust arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 08/46] gccrs: Add Rust front-end base AST data structures arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 09/46] gccrs: Add definitions of Rust Items in " arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 10/46] gccrs: Add full definitions of Rust " arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 11/46] gccrs: Add Rust AST visitors arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 12/46] gccrs: Add Lexer for Rust front-end arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 13/46] gccrs: Add Parser for Rust front-end pt.1 arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 14/46] gccrs: Add Parser for Rust front-end pt.2 arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 15/46] gccrs: Add expansion pass for the Rust front-end arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 16/46] gccrs: Add name resolution pass to " arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 17/46] gccrs: Add declarations for Rust HIR arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 18/46] gccrs: Add HIR definitions and visitor framework arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 19/46] gccrs: Add AST to HIR lowering pass arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 20/46] gccrs: Add wrapper for make_unique arthur.cohen
2022-12-07  8:50   ` Arsen Arsenović
2022-12-07  9:14     ` Thomas Schwinge
2022-12-06 10:13 ` [PATCH Rust front-end v4 21/46] gccrs: Add port of FNV hash used during legacy symbol mangling arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 22/46] gccrs: Add Rust ABI enum helpers arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 23/46] gccrs: Add Base62 implementation arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 24/46] gccrs: Add implementation of Optional arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 25/46] gccrs: Add attributes checker arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 26/46] gccrs: Add helpers mappings canonical path and lang items arthur.cohen
2022-12-06 10:13 ` [PATCH Rust front-end v4 27/46] gccrs: Add type resolution and trait solving pass arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 28/46] gccrs: Add Rust type information arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 29/46] gccrs: Add remaining type system transformations arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 30/46] gccrs: Add unsafe checks for Rust arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 31/46] gccrs: Add const checker arthur.cohen
2022-12-06 10:14 ` arthur.cohen [this message]
2022-12-06 10:14 ` [PATCH Rust front-end v4 33/46] gccrs: Add dead code scan on HIR arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 34/46] gccrs: Add unused variable scan arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 35/46] gccrs: Add metadata output pass arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 36/46] gccrs: Add base for HIR to GCC GENERIC lowering arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 37/46] gccrs: Add HIR to GCC GENERIC lowering for all nodes arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 38/46] gccrs: Add HIR to GCC GENERIC lowering entry point arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 39/46] gccrs: These are wrappers ported from reusing gccgo arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 40/46] gccrs: Add GCC Rust front-end Make-lang.in arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 41/46] gccrs: Add config-lang.in arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 42/46] gccrs: Add lang-spec.h arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 43/46] gccrs: Add lang.opt arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 44/46] gccrs: Add compiler driver arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 45/46] gccrs: Compiler proper interface kicks off the pipeline arthur.cohen
2022-12-06 10:14 ` [PATCH Rust front-end v4 46/46] gccrs: Add README, CONTRIBUTING and compiler logo arthur.cohen
2022-12-09 10:18   ` Martin Liška
2022-12-13  1:43     ` Joseph Myers
2022-12-13 12:59       ` Martin Liška
2022-12-13 18:46         ` Joseph Myers
2022-12-06 11:03 ` Rust front-end patches v4 Richard Biener
2022-12-06 11:09   ` John Paul Adrian Glaubitz
2022-12-06 11:40     ` Arthur Cohen
2022-12-06 11:57       ` John Paul Adrian Glaubitz
2022-12-06 12:40         ` Mark Wielaard
2022-12-06 11:41   ` Iain Buclaw
2022-12-10  6:39   ` Prepare 'contrib/gcc-changelog/git_commit.py' for GCC/Rust (was: Rust front-end patches v4) Thomas Schwinge
2022-12-10  7:37     ` Add stub 'gcc/rust/ChangeLog' (was: Prepare 'contrib/gcc-changelog/git_commit.py' for GCC/Rust) Thomas Schwinge
2022-12-13 13:26   ` Rust front-end patches v4 Arthur Cohen
2022-12-13 13:30     ` Martin Liška
2022-12-13 13:53       ` Arthur Cohen
2022-12-13 13:40     ` Arthur Cohen
2022-12-14 22:58       ` Make '-frust-incomplete-and-experimental-compiler-do-not-use' a 'Common' option (was: Rust front-end patches v4) Thomas Schwinge
2022-12-15  7:53         ` Richard Biener
2022-12-15 10:14           ` Thomas Schwinge
2022-12-15 11:16             ` Jakub Jelinek
2022-12-15 11:39               ` Iain Buclaw
2022-12-15 11:50                 ` Jakub Jelinek
2022-12-15 15:01                   ` Thomas Schwinge
2022-12-15 15:17                     ` Jakub Jelinek
2022-12-16 14:10                       ` Add '-Wno-complain-wrong-lang', and use it in 'gcc/testsuite/lib/target-supports.exp:check_compile' and elsewhere (was: Make '-frust-incomplete-and-experimental-compiler-do-not-use' a 'Common' option) Thomas Schwinge
2022-12-16 21:24                         ` Iain Buclaw
2023-01-11 11:41                         ` [PING] Add '-Wno-complain-wrong-lang', and use it in 'gcc/testsuite/lib/target-supports.exp:check_compile' and elsewhere Thomas Schwinge
2023-01-11 12:31                           ` Jakub Jelinek
2023-02-21 10:21                             ` [PING, v2] " Thomas Schwinge
2023-02-21 23:20                               ` Joseph Myers
2022-12-09 13:24 ` Rust front-end patches v4 Martin Liška
2022-12-10 21:44   ` Thomas Schwinge

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221206101417.778807-33-arthur.cohen@embecosm.com \
    --to=arthur.cohen@embecosm.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=gcc-rust@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).