diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc
new file mode 100644
index 00000000000..a67461791d7
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-base.cc
@@ -0,0 +1,1078 @@
+// 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-ast-lower-base.h"
+#include "rust-ast-lower-type.h"
+#include "rust-ast-lower-pattern.h"
+#include "rust-ast-lower-extern.h"
+
+namespace Rust {
+namespace HIR {
+
+void
+ASTLoweringBase::visit (AST::Token &tok)
+{}
+void
+ASTLoweringBase::visit (AST::DelimTokenTree &delim_tok_tree)
+{}
+void
+ASTLoweringBase::visit (AST::AttrInputMetaItemContainer &input)
+{}
+//  void ASTLoweringBase::visit(MetaItem& meta_item) {}
+//  void vsit(Stmt& stmt) {}
+//  void ASTLoweringBase::visit(Expr& expr) {}
+void
+ASTLoweringBase::visit (AST::IdentifierExpr &ident_expr)
+{}
+//  void ASTLoweringBase::visit(Pattern& pattern) {}
+//  void ASTLoweringBase::visit(Type& type) {}
+//  void ASTLoweringBase::visit(TypeParamBound& type_param_bound) {}
+void
+ASTLoweringBase::visit (AST::Lifetime &lifetime)
+{}
+//  void ASTLoweringBase::visit(GenericParam& generic_param) {}
+void
+ASTLoweringBase::visit (AST::LifetimeParam &lifetime_param)
+{}
+void
+ASTLoweringBase::visit (AST::ConstGenericParam &const_param)
+{}
+//  void ASTLoweringBase::visit(TraitItem& trait_item) {}
+//  void ASTLoweringBase::visit(InherentImplItem& inherent_impl_item) {}
+//  void ASTLoweringBase::visit(TraitImplItem& trait_impl_item) {}
+
+// rust-path.h
+void
+ASTLoweringBase::visit (AST::PathInExpression &path)
+{}
+void
+ASTLoweringBase::visit (AST::TypePathSegment &segment)
+{}
+void
+ASTLoweringBase::visit (AST::TypePathSegmentGeneric &segment)
+{}
+void
+ASTLoweringBase::visit (AST::TypePathSegmentFunction &segment)
+{}
+void
+ASTLoweringBase::visit (AST::TypePath &path)
+{}
+void
+ASTLoweringBase::visit (AST::QualifiedPathInExpression &path)
+{}
+void
+ASTLoweringBase::visit (AST::QualifiedPathInType &path)
+{}
+
+// rust-expr.h
+void
+ASTLoweringBase::visit (AST::LiteralExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::AttrInputLiteral &attr_input)
+{}
+void
+ASTLoweringBase::visit (AST::MetaItemLitExpr &meta_item)
+{}
+void
+ASTLoweringBase::visit (AST::MetaItemPathLit &meta_item)
+{}
+void
+ASTLoweringBase::visit (AST::BorrowExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::DereferenceExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::ErrorPropagationExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::NegationExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::ArithmeticOrLogicalExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::ComparisonExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::LazyBooleanExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::TypeCastExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::AssignmentExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::CompoundAssignmentExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::GroupedExpr &expr)
+{}
+//  void ASTLoweringBase::visit(ArrayElems& elems) {}
+void
+ASTLoweringBase::visit (AST::ArrayElemsValues &elems)
+{}
+void
+ASTLoweringBase::visit (AST::ArrayElemsCopied &elems)
+{}
+void
+ASTLoweringBase::visit (AST::ArrayExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::ArrayIndexExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::TupleExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::TupleIndexExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::StructExprStruct &expr)
+{}
+//  void ASTLoweringBase::visit(StructExprField& field) {}
+void
+ASTLoweringBase::visit (AST::StructExprFieldIdentifier &field)
+{}
+void
+ASTLoweringBase::visit (AST::StructExprFieldIdentifierValue &field)
+{}
+void
+ASTLoweringBase::visit (AST::StructExprFieldIndexValue &field)
+{}
+void
+ASTLoweringBase::visit (AST::StructExprStructFields &expr)
+{}
+void
+ASTLoweringBase::visit (AST::StructExprStructBase &expr)
+{}
+void
+ASTLoweringBase::visit (AST::CallExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::MethodCallExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::FieldAccessExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::ClosureExprInner &expr)
+{}
+void
+ASTLoweringBase::visit (AST::BlockExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::ClosureExprInnerTyped &expr)
+{}
+void
+ASTLoweringBase::visit (AST::ContinueExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::BreakExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::RangeFromToExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::RangeFromExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::RangeToExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::RangeFullExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::RangeFromToInclExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::RangeToInclExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::ReturnExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::UnsafeBlockExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::LoopExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::WhileLoopExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::WhileLetLoopExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::ForLoopExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::IfExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::IfExprConseqElse &expr)
+{}
+void
+ASTLoweringBase::visit (AST::IfExprConseqIf &expr)
+{}
+void
+ASTLoweringBase::visit (AST::IfExprConseqIfLet &expr)
+{}
+void
+ASTLoweringBase::visit (AST::IfLetExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::IfLetExprConseqElse &expr)
+{}
+void
+ASTLoweringBase::visit (AST::IfLetExprConseqIf &expr)
+{}
+void
+ASTLoweringBase::visit (AST::IfLetExprConseqIfLet &expr)
+{}
+//  void ASTLoweringBase::visit(MatchCase& match_case) {}
+// void ASTLoweringBase:: (AST::MatchCaseBlockExpr &match_case) {}
+// void ASTLoweringBase:: (AST::MatchCaseExpr &match_case) {}
+void
+ASTLoweringBase::visit (AST::MatchExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::AwaitExpr &expr)
+{}
+void
+ASTLoweringBase::visit (AST::AsyncBlockExpr &expr)
+{}
+
+// rust-item.h
+void
+ASTLoweringBase::visit (AST::TypeParam &param)
+{}
+//  void ASTLoweringBase::visit(WhereClauseItem& item) {}
+void
+ASTLoweringBase::visit (AST::LifetimeWhereClauseItem &item)
+{}
+void
+ASTLoweringBase::visit (AST::TypeBoundWhereClauseItem &item)
+{}
+void
+ASTLoweringBase::visit (AST::Method &method)
+{}
+void
+ASTLoweringBase::visit (AST::Module &module)
+{}
+void
+ASTLoweringBase::visit (AST::ExternCrate &crate)
+{}
+//  void ASTLoweringBase::visit(UseTree& use_tree) {}
+void
+ASTLoweringBase::visit (AST::UseTreeGlob &use_tree)
+{}
+void
+ASTLoweringBase::visit (AST::UseTreeList &use_tree)
+{}
+void
+ASTLoweringBase::visit (AST::UseTreeRebind &use_tree)
+{}
+void
+ASTLoweringBase::visit (AST::UseDeclaration &use_decl)
+{}
+void
+ASTLoweringBase::visit (AST::Function &function)
+{}
+void
+ASTLoweringBase::visit (AST::TypeAlias &type_alias)
+{}
+void
+ASTLoweringBase::visit (AST::StructStruct &struct_item)
+{}
+void
+ASTLoweringBase::visit (AST::TupleStruct &tuple_struct)
+{}
+void
+ASTLoweringBase::visit (AST::EnumItem &item)
+{}
+void
+ASTLoweringBase::visit (AST::EnumItemTuple &item)
+{}
+void
+ASTLoweringBase::visit (AST::EnumItemStruct &item)
+{}
+void
+ASTLoweringBase::visit (AST::EnumItemDiscriminant &item)
+{}
+void
+ASTLoweringBase::visit (AST::Enum &enum_item)
+{}
+void
+ASTLoweringBase::visit (AST::Union &union_item)
+{}
+void
+ASTLoweringBase::visit (AST::ConstantItem &const_item)
+{}
+void
+ASTLoweringBase::visit (AST::StaticItem &static_item)
+{}
+void
+ASTLoweringBase::visit (AST::TraitItemFunc &item)
+{}
+void
+ASTLoweringBase::visit (AST::TraitItemMethod &item)
+{}
+void
+ASTLoweringBase::visit (AST::TraitItemConst &item)
+{}
+void
+ASTLoweringBase::visit (AST::TraitItemType &item)
+{}
+void
+ASTLoweringBase::visit (AST::Trait &trait)
+{}
+void
+ASTLoweringBase::visit (AST::InherentImpl &impl)
+{}
+void
+ASTLoweringBase::visit (AST::TraitImpl &impl)
+{}
+//  void ASTLoweringBase::visit(ExternalItem& item) {}
+void
+ASTLoweringBase::visit (AST::ExternalStaticItem &item)
+{}
+void
+ASTLoweringBase::visit (AST::ExternalFunctionItem &item)
+{}
+void
+ASTLoweringBase::visit (AST::ExternBlock &block)
+{}
+
+// rust-macro.h
+void
+ASTLoweringBase::visit (AST::MacroMatchFragment &match)
+{}
+void
+ASTLoweringBase::visit (AST::MacroMatchRepetition &match)
+{}
+void
+ASTLoweringBase::visit (AST::MacroMatcher &matcher)
+{}
+void
+ASTLoweringBase::visit (AST::MacroRulesDefinition &rules_def)
+{}
+void
+ASTLoweringBase::visit (AST::MacroInvocation &macro_invoc)
+{}
+void
+ASTLoweringBase::visit (AST::MetaItemPath &meta_item)
+{}
+void
+ASTLoweringBase::visit (AST::MetaItemSeq &meta_item)
+{}
+void
+ASTLoweringBase::visit (AST::MetaWord &meta_item)
+{}
+void
+ASTLoweringBase::visit (AST::MetaNameValueStr &meta_item)
+{}
+void
+ASTLoweringBase::visit (AST::MetaListPaths &meta_item)
+{}
+void
+ASTLoweringBase::visit (AST::MetaListNameValueStr &meta_item)
+{}
+
+// rust-pattern.h
+void
+ASTLoweringBase::visit (AST::LiteralPattern &pattern)
+{}
+void
+ASTLoweringBase::visit (AST::IdentifierPattern &pattern)
+{}
+void
+ASTLoweringBase::visit (AST::WildcardPattern &pattern)
+{}
+//  void ASTLoweringBase::visit(RangePatternBound& bound) {}
+void
+ASTLoweringBase::visit (AST::RangePatternBoundLiteral &bound)
+{}
+void
+ASTLoweringBase::visit (AST::RangePatternBoundPath &bound)
+{}
+void
+ASTLoweringBase::visit (AST::RangePatternBoundQualPath &bound)
+{}
+void
+ASTLoweringBase::visit (AST::RangePattern &pattern)
+{}
+void
+ASTLoweringBase::visit (AST::ReferencePattern &pattern)
+{}
+//  void ASTLoweringBase::visit(StructPatternField& field) {}
+void
+ASTLoweringBase::visit (AST::StructPatternFieldTuplePat &field)
+{}
+void
+ASTLoweringBase::visit (AST::StructPatternFieldIdentPat &field)
+{}
+void
+ASTLoweringBase::visit (AST::StructPatternFieldIdent &field)
+{}
+void
+ASTLoweringBase::visit (AST::StructPattern &pattern)
+{}
+//  void ASTLoweringBase::visit(TupleStructItems& tuple_items) {}
+void
+ASTLoweringBase::visit (AST::TupleStructItemsNoRange &tuple_items)
+{}
+void
+ASTLoweringBase::visit (AST::TupleStructItemsRange &tuple_items)
+{}
+void
+ASTLoweringBase::visit (AST::TupleStructPattern &pattern)
+{}
+//  void ASTLoweringBase::visit(TuplePatternItems& tuple_items) {}
+void
+ASTLoweringBase::visit (AST::TuplePatternItemsMultiple &tuple_items)
+{}
+void
+ASTLoweringBase::visit (AST::TuplePatternItemsRanged &tuple_items)
+{}
+void
+ASTLoweringBase::visit (AST::TuplePattern &pattern)
+{}
+void
+ASTLoweringBase::visit (AST::GroupedPattern &pattern)
+{}
+void
+ASTLoweringBase::visit (AST::SlicePattern &pattern)
+{}
+
+// rust-stmt.h
+void
+ASTLoweringBase::visit (AST::EmptyStmt &stmt)
+{}
+void
+ASTLoweringBase::visit (AST::LetStmt &stmt)
+{}
+void
+ASTLoweringBase::visit (AST::ExprStmtWithoutBlock &stmt)
+{}
+void
+ASTLoweringBase::visit (AST::ExprStmtWithBlock &stmt)
+{}
+
+// rust-type.h
+void
+ASTLoweringBase::visit (AST::TraitBound &bound)
+{}
+void
+ASTLoweringBase::visit (AST::ImplTraitType &type)
+{}
+void
+ASTLoweringBase::visit (AST::TraitObjectType &type)
+{}
+void
+ASTLoweringBase::visit (AST::ParenthesisedType &type)
+{}
+void
+ASTLoweringBase::visit (AST::ImplTraitTypeOneBound &type)
+{}
+void
+ASTLoweringBase::visit (AST::TraitObjectTypeOneBound &type)
+{}
+void
+ASTLoweringBase::visit (AST::TupleType &type)
+{}
+void
+ASTLoweringBase::visit (AST::NeverType &type)
+{}
+void
+ASTLoweringBase::visit (AST::RawPointerType &type)
+{}
+void
+ASTLoweringBase::visit (AST::ReferenceType &type)
+{}
+void
+ASTLoweringBase::visit (AST::ArrayType &type)
+{}
+void
+ASTLoweringBase::visit (AST::SliceType &type)
+{}
+void
+ASTLoweringBase::visit (AST::InferredType &type)
+{}
+void
+ASTLoweringBase::visit (AST::BareFunctionType &type)
+{}
+
+HIR::Lifetime
+ASTLoweringBase::lower_lifetime (AST::Lifetime &lifetime)
+{
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, lifetime.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+  mappings->insert_node_to_hir (mapping.get_nodeid (), mapping.get_hirid ());
+
+  return HIR::Lifetime (mapping, lifetime.get_lifetime_type (),
+			lifetime.get_lifetime_name (), lifetime.get_locus ());
+}
+
+HIR::LoopLabel
+ASTLoweringBase::lower_loop_label (AST::LoopLabel &loop_label)
+{
+  HIR::Lifetime life = lower_lifetime (loop_label.get_lifetime ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, loop_label.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+  mappings->insert_node_to_hir (mapping.get_nodeid (), mapping.get_hirid ());
+
+  return HIR::LoopLabel (mapping, std::move (life), loop_label.get_locus ());
+}
+
+std::vector<std::unique_ptr<HIR::GenericParam>>
+ASTLoweringBase::lower_generic_params (
+  std::vector<std::unique_ptr<AST::GenericParam>> &params)
+{
+  std::vector<std::unique_ptr<HIR::GenericParam>> lowered;
+  for (auto &ast_param : params)
+    {
+      auto hir_param = ASTLowerGenericParam::translate (ast_param.get ());
+      lowered.push_back (std::unique_ptr<HIR::GenericParam> (hir_param));
+    }
+
+  return lowered;
+}
+
+HIR::PathExprSegment
+ASTLoweringBase::lower_path_expr_seg (AST::PathExprSegment &s)
+{
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, s.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  return HIR::PathExprSegment (
+    std::move (mapping),
+    HIR::PathIdentSegment (s.get_ident_segment ().as_string ()), s.get_locus (),
+    s.has_generic_args () ? lower_generic_args (s.get_generic_args ())
+			  : HIR::GenericArgs::create_empty ());
+}
+
+HIR::GenericArgsBinding
+ASTLoweringBase::lower_binding (AST::GenericArgsBinding &binding)
+{
+  HIR::Type *lowered_type
+    = ASTLoweringType::translate (binding.get_type ().get ());
+  return HIR::GenericArgsBinding (binding.get_identifier (),
+				  std::unique_ptr<HIR::Type> (lowered_type),
+				  binding.get_locus ());
+}
+
+HIR::GenericArgs
+ASTLoweringBase::lower_generic_args (AST::GenericArgs &args)
+{
+  std::vector<HIR::GenericArgsBinding> binding_args;
+  for (auto &binding : args.get_binding_args ())
+    {
+      HIR::GenericArgsBinding b = lower_binding (binding);
+      binding_args.push_back (std::move (b));
+    }
+
+  std::vector<HIR::Lifetime> lifetime_args;
+  for (auto &lifetime : args.get_lifetime_args ())
+    {
+      HIR::Lifetime l = lower_lifetime (lifetime);
+      lifetime_args.push_back (std::move (l));
+    }
+
+  std::vector<std::unique_ptr<HIR::Type>> type_args;
+  std::vector<HIR::ConstGenericArg> const_args;
+
+  for (auto &arg : args.get_generic_args ())
+    {
+      switch (arg.get_kind ())
+	{
+	  case AST::GenericArg::Kind::Type: {
+	    auto type = ASTLoweringType::translate (arg.get_type ().get ());
+	    type_args.emplace_back (std::unique_ptr<HIR::Type> (type));
+	    break;
+	  }
+	  case AST::GenericArg::Kind::Const: {
+	    auto expr
+	      = ASTLoweringExpr::translate (arg.get_expression ().get ());
+	    const_args.emplace_back (
+	      HIR::ConstGenericArg (std::unique_ptr<HIR::Expr> (expr),
+				    expr->get_locus ()));
+	    break;
+	  }
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
+  return HIR::GenericArgs (std::move (lifetime_args), std::move (type_args),
+			   std::move (binding_args), std::move (const_args),
+			   args.get_locus ());
+}
+
+HIR::SelfParam
+ASTLoweringBase::lower_self (AST::SelfParam &self)
+{
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, self.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  if (self.has_type ())
+    {
+      HIR::Type *type = ASTLoweringType::translate (self.get_type ().get ());
+      return HIR::SelfParam (mapping, std::unique_ptr<HIR::Type> (type),
+			     self.get_is_mut (), self.get_locus ());
+    }
+  else if (!self.get_has_ref ())
+    {
+      return HIR::SelfParam (mapping, std::unique_ptr<HIR::Type> (nullptr),
+			     self.get_is_mut (), self.get_locus ());
+    }
+
+  AST::Lifetime l = self.get_lifetime ();
+  return HIR::SelfParam (mapping, lower_lifetime (l), self.get_is_mut (),
+			 self.get_locus ());
+}
+
+void
+ASTLowerTypePath::visit (AST::TypePathSegmentGeneric &segment)
+{
+  std::vector<HIR::GenericArgsBinding> binding_args; // TODO
+
+  std::string segment_name = segment.get_ident_segment ().as_string ();
+  bool has_separating_scope_resolution
+    = segment.get_separating_scope_resolution ();
+
+  auto generic_args = lower_generic_args (segment.get_generic_args ());
+
+  auto crate_num = mappings->get_current_crate ();
+  auto hirid = mappings->get_next_hir_id (crate_num);
+  Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid,
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated_segment
+    = new HIR::TypePathSegmentGeneric (std::move (mapping), segment_name,
+				       has_separating_scope_resolution,
+				       generic_args, segment.get_locus ());
+}
+
+void
+ASTLowerQualifiedPathInType::visit (AST::QualifiedPathInType &path)
+{
+  auto crate_num = mappings->get_current_crate ();
+  auto hirid = mappings->get_next_hir_id (crate_num);
+  Analysis::NodeMapping qual_mappings (
+    crate_num, path.get_qualified_path_type ().get_node_id (), hirid,
+    UNKNOWN_LOCAL_DEFID);
+
+  HIR::Type *qual_type = ASTLoweringType::translate (
+    path.get_qualified_path_type ().get_type ().get ());
+  HIR::TypePath *qual_trait = ASTLowerTypePath::translate (
+    path.get_qualified_path_type ().get_as_type_path ());
+
+  HIR::QualifiedPathType qual_path_type (
+    qual_mappings, std::unique_ptr<HIR::Type> (qual_type),
+    std::unique_ptr<HIR::TypePath> (qual_trait),
+    path.get_qualified_path_type ().get_locus ());
+
+  translated_segment = nullptr;
+  path.get_associated_segment ()->accept_vis (*this);
+  if (translated_segment == nullptr)
+    {
+      rust_fatal_error (path.get_associated_segment ()->get_locus (),
+			"failed to translate AST TypePathSegment");
+      return;
+    }
+  std::unique_ptr<HIR::TypePathSegment> associated_segment (translated_segment);
+
+  std::vector<std::unique_ptr<HIR::TypePathSegment>> translated_segments;
+  for (auto &seg : path.get_segments ())
+    {
+      translated_segment = nullptr;
+      seg->accept_vis (*this);
+      if (translated_segment == nullptr)
+	{
+	  rust_fatal_error (seg->get_locus (),
+			    "failed to translte AST TypePathSegment");
+	}
+      translated_segments.push_back (
+	std::unique_ptr<HIR::TypePathSegment> (translated_segment));
+    }
+
+  Analysis::NodeMapping mapping (crate_num, path.get_node_id (), hirid,
+				 mappings->get_next_localdef_id (crate_num));
+  translated = new HIR::QualifiedPathInType (std::move (mapping),
+					     std::move (qual_path_type),
+					     std::move (associated_segment),
+					     std::move (translated_segments),
+					     path.get_locus ());
+}
+
+void
+ASTLoweringType::visit (AST::TraitObjectTypeOneBound &type)
+{
+  std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds;
+  HIR::TypeParamBound *translated_bound
+    = ASTLoweringTypeBounds::translate (&type.get_trait_bound ());
+  bounds.push_back (std::unique_ptr<HIR::TypeParamBound> (translated_bound));
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated = new HIR::TraitObjectType (mapping, std::move (bounds),
+					 type.get_locus (), type.is_dyn ());
+}
+
+void
+ASTLoweringType::visit (AST::TraitObjectType &type)
+{
+  std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds;
+
+  for (auto &bound : type.get_type_param_bounds ())
+    {
+      HIR::TypeParamBound *translated_bound
+	= ASTLoweringTypeBounds::translate (bound.get ());
+      bounds.push_back (
+	std::unique_ptr<HIR::TypeParamBound> (translated_bound));
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated = new HIR::TraitObjectType (mapping, std::move (bounds),
+					 type.get_locus (), type.is_dyn ());
+}
+
+HIR::Type *
+ASTLoweringBase::lower_type_no_bounds (AST::TypeNoBounds *type)
+{
+  return ASTLoweringType::translate (type);
+}
+
+HIR::TypeParamBound *
+ASTLoweringBase::lower_bound (AST::TypeParamBound *bound)
+{
+  return ASTLoweringTypeBounds::translate (bound);
+}
+
+/* Checks whether the name of a field already exists.  Returns true
+   and produces an error if so.  */
+bool
+struct_field_name_exists (std::vector<HIR::StructField> &fields,
+			  HIR::StructField &new_field)
+{
+  for (auto &field : fields)
+    {
+      if (field.get_field_name ().compare (new_field.get_field_name ()) == 0)
+	{
+	  RichLocation r (new_field.get_locus ());
+	  r.add_range (field.get_locus ());
+	  rust_error_at (r, "duplicate field name %qs",
+			 field.get_field_name ().c_str ());
+	  return true;
+	}
+    }
+  return false;
+}
+
+HIR::FunctionQualifiers
+ASTLoweringBase::lower_qualifiers (const AST::FunctionQualifiers &qualifiers)
+{
+  Unsafety unsafety
+    = qualifiers.is_unsafe () ? Unsafety::Unsafe : Unsafety::Normal;
+  bool has_extern = qualifiers.is_extern ();
+
+  ABI abi = ABI::RUST;
+  if (qualifiers.has_abi ())
+    {
+      const std::string &extern_abi = qualifiers.get_extern_abi ();
+      abi = get_abi_from_string (extern_abi);
+      if (has_extern && abi == ABI::UNKNOWN)
+	rust_error_at (qualifiers.get_locus (), "unknown ABI option");
+    }
+
+  return HIR::FunctionQualifiers (qualifiers.get_const_status (), unsafety,
+				  has_extern, abi);
+}
+
+void
+ASTLoweringBase::handle_outer_attributes (const HIR::Item &item)
+{
+  for (const auto &attr : item.get_outer_attrs ())
+    {
+      const auto &str_path = attr.get_path ().as_string ();
+      if (!is_known_attribute (str_path))
+	{
+	  rust_error_at (attr.get_locus (), "unknown attribute");
+	  continue;
+	}
+
+      bool is_lang_item = str_path.compare ("lang") == 0
+			  && attr.has_attr_input ()
+			  && attr.get_attr_input ().get_attr_input_type ()
+			       == AST::AttrInput::AttrInputType::LITERAL;
+
+      bool is_doc_item = str_path.compare ("doc") == 0;
+
+      if (is_doc_item)
+	handle_doc_item_attribute (item, attr);
+      else if (is_lang_item)
+	handle_lang_item_attribute (item, attr);
+      else if (!attribute_handled_in_another_pass (str_path))
+	{
+	  rust_error_at (attr.get_locus (), "unhandled attribute: [%s]",
+			 attr.get_path ().as_string ().c_str ());
+	}
+    }
+}
+
+void
+ASTLoweringBase::handle_doc_item_attribute (const HIR::Item &item,
+					    const AST::Attribute &attr)
+{
+  auto simple_doc_comment = attr.has_attr_input ()
+			    && attr.get_attr_input ().get_attr_input_type ()
+				 == AST::AttrInput::AttrInputType::LITERAL;
+  if (simple_doc_comment)
+    return;
+
+  const AST::AttrInput &input = attr.get_attr_input ();
+  bool is_token_tree
+    = input.get_attr_input_type () == AST::AttrInput::AttrInputType::TOKEN_TREE;
+  rust_assert (is_token_tree);
+  const auto &option = static_cast<const AST::DelimTokenTree &> (input);
+  AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item ();
+
+  // TODO: add actual and complete checks for the doc attributes
+  //
+  // FIXME: Move this to the AttributeChecker visitor
+  rust_assert (meta_item);
+}
+
+void
+ASTLoweringBase::handle_lang_item_attribute (const HIR::Item &item,
+					     const AST::Attribute &attr)
+{
+  auto &literal = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
+  const auto &lang_item_type_str = literal.get_literal ().as_string ();
+  auto lang_item_type = Analysis::RustLangItem::Parse (lang_item_type_str);
+  if (lang_item_type == Analysis::RustLangItem::ItemType::UNKNOWN)
+    {
+      rust_error_at (attr.get_locus (), "unknown lang item");
+      return;
+    }
+  mappings->insert_lang_item (lang_item_type,
+			      item.get_mappings ().get_defid ());
+}
+
+bool
+ASTLoweringBase::is_known_attribute (const std::string &attribute_path) const
+{
+  const auto &lookup = attr_mappings->lookup_builtin (attribute_path);
+  return !lookup.is_error ();
+}
+
+bool
+ASTLoweringBase::attribute_handled_in_another_pass (
+  const std::string &attribute_path) const
+{
+  const auto &lookup = attr_mappings->lookup_builtin (attribute_path);
+  if (lookup.is_error ())
+    return false;
+
+  if (lookup.handler == Analysis::CompilerPass::UNKNOWN)
+    return false;
+
+  return lookup.handler != Analysis::CompilerPass::HIR_LOWERING;
+}
+
+std::unique_ptr<HIR::TuplePatternItems>
+ASTLoweringBase::lower_tuple_pattern_multiple (
+  AST::TuplePatternItemsMultiple &pattern)
+{
+  std::vector<std::unique_ptr<HIR::Pattern>> patterns;
+  for (auto &p : pattern.get_patterns ())
+    {
+      HIR::Pattern *translated = ASTLoweringPattern::translate (p.get ());
+      patterns.push_back (std::unique_ptr<HIR::Pattern> (translated));
+    }
+
+  return std::unique_ptr<HIR::TuplePatternItems> (
+    new HIR::TuplePatternItemsMultiple (std::move (patterns)));
+}
+
+std::unique_ptr<TuplePatternItems>
+ASTLoweringBase::lower_tuple_pattern_ranged (
+  AST::TuplePatternItemsRanged &pattern)
+{
+  std::vector<std::unique_ptr<HIR::Pattern>> lower_patterns;
+  std::vector<std::unique_ptr<HIR::Pattern>> upper_patterns;
+
+  for (auto &p : pattern.get_lower_patterns ())
+    {
+      HIR::Pattern *translated = ASTLoweringPattern::translate (p.get ());
+      lower_patterns.push_back (std::unique_ptr<HIR::Pattern> (translated));
+    }
+
+  for (auto &p : pattern.get_upper_patterns ())
+    {
+      HIR::Pattern *translated = ASTLoweringPattern::translate (p.get ());
+      upper_patterns.push_back (std::unique_ptr<HIR::Pattern> (translated));
+    }
+
+  return std::unique_ptr<HIR::TuplePatternItems> (
+    new HIR::TuplePatternItemsRanged (std::move (lower_patterns),
+				      std::move (upper_patterns)));
+}
+
+std::unique_ptr<HIR::RangePatternBound>
+ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound *bound)
+{
+  std::unique_ptr<HIR::RangePatternBound> hir_bound = nullptr;
+  switch (bound->get_bound_type ())
+    {
+      case AST::RangePatternBound::RangePatternBoundType::LITERAL: {
+	AST::RangePatternBoundLiteral &ref
+	  = *static_cast<AST::RangePatternBoundLiteral *> (bound);
+
+	HIR::Literal literal = lower_literal (ref.get_literal ());
+
+	hir_bound = std::unique_ptr<HIR::RangePatternBound> (
+	  new HIR::RangePatternBoundLiteral (literal, ref.get_locus (),
+					     ref.get_has_minus ()));
+      }
+      break;
+      case AST::RangePatternBound::RangePatternBoundType::PATH: {
+	AST::RangePatternBoundPath &ref
+	  = *static_cast<AST::RangePatternBoundPath *> (bound);
+
+	HIR::PathInExpression *path
+	  = ASTLowerPathInExpression::translate (&ref.get_path ());
+
+	hir_bound = std::unique_ptr<HIR::RangePatternBound> (
+	  new HIR::RangePatternBoundPath (*path));
+      }
+      break;
+      case AST::RangePatternBound::RangePatternBoundType::QUALPATH: {
+	AST::RangePatternBoundQualPath &ref
+	  = *static_cast<AST::RangePatternBoundQualPath *> (bound);
+
+	HIR::QualifiedPathInExpression *qualpath
+	  = ASTLowerQualPathInExpression::translate (
+	    &ref.get_qualified_path ());
+
+	hir_bound = std::unique_ptr<HIR::RangePatternBound> (
+	  new HIR::RangePatternBoundQualPath (*qualpath));
+      }
+      break;
+    }
+
+  return hir_bound;
+}
+
+HIR::Literal
+ASTLoweringBase::lower_literal (const AST::Literal &literal)
+{
+  HIR::Literal::LitType type = HIR::Literal::LitType::CHAR;
+  switch (literal.get_lit_type ())
+    {
+    case AST::Literal::LitType::CHAR:
+      type = HIR::Literal::LitType::CHAR;
+      break;
+    case AST::Literal::LitType::STRING:
+      type = HIR::Literal::LitType::STRING;
+      break;
+    case AST::Literal::LitType::BYTE:
+      type = HIR::Literal::LitType::BYTE;
+      break;
+    case AST::Literal::LitType::BYTE_STRING:
+      type = HIR::Literal::LitType::BYTE_STRING;
+      break;
+    case AST::Literal::LitType::INT:
+      type = HIR::Literal::LitType::INT;
+      break;
+    case AST::Literal::LitType::FLOAT:
+      type = HIR::Literal::LitType::FLOAT;
+      break;
+    case AST::Literal::LitType::BOOL:
+      type = HIR::Literal::LitType::BOOL;
+      break;
+    case AST::Literal::LitType::ERROR:
+      gcc_unreachable ();
+      break;
+    }
+
+  return HIR::Literal (literal.as_string (), type, literal.get_type_hint ());
+}
+
+HIR::ExternBlock *
+ASTLoweringBase::lower_extern_block (AST::ExternBlock &extern_block)
+{
+  HIR::Visibility vis = translate_visibility (extern_block.get_visibility ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, extern_block.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  std::vector<std::unique_ptr<HIR::ExternalItem>> extern_items;
+  for (auto &item : extern_block.get_extern_items ())
+    {
+      if (item->is_marked_for_strip ())
+	continue;
+
+      HIR::ExternalItem *lowered
+	= ASTLoweringExternItem::translate (item.get (), mapping.get_hirid ());
+      extern_items.push_back (std::unique_ptr<HIR::ExternalItem> (lowered));
+    }
+
+  ABI abi = ABI::RUST;
+  if (extern_block.has_abi ())
+    {
+      const std::string &extern_abi = extern_block.get_abi ();
+      abi = get_abi_from_string (extern_abi);
+      if (abi == ABI::UNKNOWN)
+	rust_error_at (extern_block.get_locus (), "unknown ABI option");
+    }
+
+  HIR::ExternBlock *hir_extern_block
+    = new HIR::ExternBlock (mapping, abi, std::move (extern_items),
+			    std::move (vis), extern_block.get_inner_attrs (),
+			    extern_block.get_outer_attrs (),
+			    extern_block.get_locus ());
+
+  mappings->insert_hir_extern_block (hir_extern_block);
+
+  return hir_extern_block;
+}
+
+} // namespace HIR
+} // namespace Rust
diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h
new file mode 100644
index 00000000000..68c57e0c02b
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-base.h
@@ -0,0 +1,297 @@
+// 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_AST_LOWER_BASE
+#define RUST_AST_LOWER_BASE
+
+#include "rust-system.h"
+#include "rust-ast-full.h"
+#include "rust-ast-visitor.h"
+#include "rust-hir-map.h"
+#include "rust-hir-full.h"
+#include "rust-attributes.h"
+
+namespace Rust {
+namespace HIR {
+
+// base class to allow derivatives to overload as needed
+class ASTLoweringBase : public AST::ASTVisitor
+{
+public:
+  virtual ~ASTLoweringBase () {}
+
+  // visitor impl
+  // rust-ast.h
+  //  virtual void visit(AttrInput& attr_input);
+  //  virtual void visit(TokenTree& token_tree);
+  //  virtual void visit(MacroMatch& macro_match);
+  virtual void visit (AST::Token &tok);
+  virtual void visit (AST::DelimTokenTree &delim_tok_tree);
+  virtual void visit (AST::AttrInputMetaItemContainer &input);
+  //  virtual void visit(MetaItem& meta_item);
+  //  void vsit(Stmt& stmt);
+  //  virtual void visit(Expr& expr);
+  virtual void visit (AST::IdentifierExpr &ident_expr);
+  //  virtual void visit(Pattern& pattern);
+  //  virtual void visit(Type& type);
+  //  virtual void visit(TypeParamBound& type_param_bound);
+  virtual void visit (AST::Lifetime &lifetime);
+  //  virtual void visit(GenericParam& generic_param);
+  virtual void visit (AST::LifetimeParam &lifetime_param);
+  virtual void visit (AST::ConstGenericParam &const_param);
+  //  virtual void visit(TraitItem& trait_item);
+  //  virtual void visit(InherentImplItem& inherent_impl_item);
+  //  virtual void visit(TraitImplItem& trait_impl_item);
+
+  // rust-path.h
+  virtual void visit (AST::PathInExpression &path);
+  virtual void visit (AST::TypePathSegment &segment);
+  virtual void visit (AST::TypePathSegmentGeneric &segment);
+  virtual void visit (AST::TypePathSegmentFunction &segment);
+  virtual void visit (AST::TypePath &path);
+  virtual void visit (AST::QualifiedPathInExpression &path);
+  virtual void visit (AST::QualifiedPathInType &path);
+
+  // rust-expr.h
+  virtual void visit (AST::LiteralExpr &expr);
+  virtual void visit (AST::AttrInputLiteral &attr_input);
+  virtual void visit (AST::MetaItemLitExpr &meta_item);
+  virtual void visit (AST::MetaItemPathLit &meta_item);
+  virtual void visit (AST::BorrowExpr &expr);
+  virtual void visit (AST::DereferenceExpr &expr);
+  virtual void visit (AST::ErrorPropagationExpr &expr);
+  virtual void visit (AST::NegationExpr &expr);
+  virtual void visit (AST::ArithmeticOrLogicalExpr &expr);
+  virtual void visit (AST::ComparisonExpr &expr);
+  virtual void visit (AST::LazyBooleanExpr &expr);
+  virtual void visit (AST::TypeCastExpr &expr);
+  virtual void visit (AST::AssignmentExpr &expr);
+  virtual void visit (AST::CompoundAssignmentExpr &expr);
+  virtual void visit (AST::GroupedExpr &expr);
+  //  virtual void visit(ArrayElems& elems);
+  virtual void visit (AST::ArrayElemsValues &elems);
+  virtual void visit (AST::ArrayElemsCopied &elems);
+  virtual void visit (AST::ArrayExpr &expr);
+  virtual void visit (AST::ArrayIndexExpr &expr);
+  virtual void visit (AST::TupleExpr &expr);
+  virtual void visit (AST::TupleIndexExpr &expr);
+  virtual void visit (AST::StructExprStruct &expr);
+  //  virtual void visit(StructExprField& field);
+  virtual void visit (AST::StructExprFieldIdentifier &field);
+  virtual void visit (AST::StructExprFieldIdentifierValue &field);
+  virtual void visit (AST::StructExprFieldIndexValue &field);
+  virtual void visit (AST::StructExprStructFields &expr);
+  virtual void visit (AST::StructExprStructBase &expr);
+  virtual void visit (AST::CallExpr &expr);
+  virtual void visit (AST::MethodCallExpr &expr);
+  virtual void visit (AST::FieldAccessExpr &expr);
+  virtual void visit (AST::ClosureExprInner &expr);
+  virtual void visit (AST::BlockExpr &expr);
+  virtual void visit (AST::ClosureExprInnerTyped &expr);
+  virtual void visit (AST::ContinueExpr &expr);
+  virtual void visit (AST::BreakExpr &expr);
+  virtual void visit (AST::RangeFromToExpr &expr);
+  virtual void visit (AST::RangeFromExpr &expr);
+  virtual void visit (AST::RangeToExpr &expr);
+  virtual void visit (AST::RangeFullExpr &expr);
+  virtual void visit (AST::RangeFromToInclExpr &expr);
+  virtual void visit (AST::RangeToInclExpr &expr);
+  virtual void visit (AST::ReturnExpr &expr);
+  virtual void visit (AST::UnsafeBlockExpr &expr);
+  virtual void visit (AST::LoopExpr &expr);
+  virtual void visit (AST::WhileLoopExpr &expr);
+  virtual void visit (AST::WhileLetLoopExpr &expr);
+  virtual void visit (AST::ForLoopExpr &expr);
+  virtual void visit (AST::IfExpr &expr);
+  virtual void visit (AST::IfExprConseqElse &expr);
+  virtual void visit (AST::IfExprConseqIf &expr);
+  virtual void visit (AST::IfExprConseqIfLet &expr);
+  virtual void visit (AST::IfLetExpr &expr);
+  virtual void visit (AST::IfLetExprConseqElse &expr);
+  virtual void visit (AST::IfLetExprConseqIf &expr);
+  virtual void visit (AST::IfLetExprConseqIfLet &expr);
+  //  virtual void visit(MatchCase& match_case);
+  // virtual void visit (AST::MatchCaseBlockExpr &match_case);
+  // virtual void visit (AST::MatchCaseExpr &match_case);
+  virtual void visit (AST::MatchExpr &expr);
+  virtual void visit (AST::AwaitExpr &expr);
+  virtual void visit (AST::AsyncBlockExpr &expr);
+
+  // rust-item.h
+  virtual void visit (AST::TypeParam &param);
+  //  virtual void visit(WhereClauseItem& item);
+  virtual void visit (AST::LifetimeWhereClauseItem &item);
+  virtual void visit (AST::TypeBoundWhereClauseItem &item);
+  virtual void visit (AST::Method &method);
+  virtual void visit (AST::Module &module);
+  virtual void visit (AST::ExternCrate &crate);
+  //  virtual void visit(UseTree& use_tree);
+  virtual void visit (AST::UseTreeGlob &use_tree);
+  virtual void visit (AST::UseTreeList &use_tree);
+  virtual void visit (AST::UseTreeRebind &use_tree);
+  virtual void visit (AST::UseDeclaration &use_decl);
+  virtual void visit (AST::Function &function);
+  virtual void visit (AST::TypeAlias &type_alias);
+  virtual void visit (AST::StructStruct &struct_item);
+  virtual void visit (AST::TupleStruct &tuple_struct);
+  virtual void visit (AST::EnumItem &item);
+  virtual void visit (AST::EnumItemTuple &item);
+  virtual void visit (AST::EnumItemStruct &item);
+  virtual void visit (AST::EnumItemDiscriminant &item);
+  virtual void visit (AST::Enum &enum_item);
+  virtual void visit (AST::Union &union_item);
+  virtual void visit (AST::ConstantItem &const_item);
+  virtual void visit (AST::StaticItem &static_item);
+  virtual void visit (AST::TraitItemFunc &item);
+  virtual void visit (AST::TraitItemMethod &item);
+  virtual void visit (AST::TraitItemConst &item);
+  virtual void visit (AST::TraitItemType &item);
+  virtual void visit (AST::Trait &trait);
+  virtual void visit (AST::InherentImpl &impl);
+  virtual void visit (AST::TraitImpl &impl);
+  //  virtual void visit(ExternalItem& item);
+  virtual void visit (AST::ExternalStaticItem &item);
+  virtual void visit (AST::ExternalFunctionItem &item);
+  virtual void visit (AST::ExternBlock &block);
+
+  // rust-macro.h
+  virtual void visit (AST::MacroMatchFragment &match);
+  virtual void visit (AST::MacroMatchRepetition &match);
+  virtual void visit (AST::MacroMatcher &matcher);
+  virtual void visit (AST::MacroRulesDefinition &rules_def);
+  virtual void visit (AST::MacroInvocation &macro_invoc);
+  virtual void visit (AST::MetaItemPath &meta_item);
+  virtual void visit (AST::MetaItemSeq &meta_item);
+  virtual void visit (AST::MetaWord &meta_item);
+  virtual void visit (AST::MetaNameValueStr &meta_item);
+  virtual void visit (AST::MetaListPaths &meta_item);
+  virtual void visit (AST::MetaListNameValueStr &meta_item);
+
+  // rust-pattern.h
+  virtual void visit (AST::LiteralPattern &pattern);
+  virtual void visit (AST::IdentifierPattern &pattern);
+  virtual void visit (AST::WildcardPattern &pattern);
+  //  virtual void visit(RangePatternBound& bound);
+  virtual void visit (AST::RangePatternBoundLiteral &bound);
+  virtual void visit (AST::RangePatternBoundPath &bound);
+  virtual void visit (AST::RangePatternBoundQualPath &bound);
+  virtual void visit (AST::RangePattern &pattern);
+  virtual void visit (AST::ReferencePattern &pattern);
+  //  virtual void visit(StructPatternField& field);
+  virtual void visit (AST::StructPatternFieldTuplePat &field);
+  virtual void visit (AST::StructPatternFieldIdentPat &field);
+  virtual void visit (AST::StructPatternFieldIdent &field);
+  virtual void visit (AST::StructPattern &pattern);
+  //  virtual void visit(TupleStructItems& tuple_items);
+  virtual void visit (AST::TupleStructItemsNoRange &tuple_items);
+  virtual void visit (AST::TupleStructItemsRange &tuple_items);
+  virtual void visit (AST::TupleStructPattern &pattern);
+  //  virtual void visit(TuplePatternItems& tuple_items);
+  virtual void visit (AST::TuplePatternItemsMultiple &tuple_items);
+  virtual void visit (AST::TuplePatternItemsRanged &tuple_items);
+  virtual void visit (AST::TuplePattern &pattern);
+  virtual void visit (AST::GroupedPattern &pattern);
+  virtual void visit (AST::SlicePattern &pattern);
+
+  // rust-stmt.h
+  virtual void visit (AST::EmptyStmt &stmt);
+  virtual void visit (AST::LetStmt &stmt);
+  virtual void visit (AST::ExprStmtWithoutBlock &stmt);
+  virtual void visit (AST::ExprStmtWithBlock &stmt);
+
+  // rust-type.h
+  virtual void visit (AST::TraitBound &bound);
+  virtual void visit (AST::ImplTraitType &type);
+  virtual void visit (AST::TraitObjectType &type);
+  virtual void visit (AST::ParenthesisedType &type);
+  virtual void visit (AST::ImplTraitTypeOneBound &type);
+  virtual void visit (AST::TraitObjectTypeOneBound &type);
+  virtual void visit (AST::TupleType &type);
+  virtual void visit (AST::NeverType &type);
+  virtual void visit (AST::RawPointerType &type);
+  virtual void visit (AST::ReferenceType &type);
+  virtual void visit (AST::ArrayType &type);
+  virtual void visit (AST::SliceType &type);
+  virtual void visit (AST::InferredType &type);
+  virtual void visit (AST::BareFunctionType &type);
+
+protected:
+  ASTLoweringBase ()
+    : mappings (Analysis::Mappings::get ()),
+      attr_mappings (Analysis::BuiltinAttributeMappings::get ())
+  {}
+
+  Analysis::Mappings *mappings;
+  Analysis::BuiltinAttributeMappings *attr_mappings;
+
+  HIR::Lifetime lower_lifetime (AST::Lifetime &lifetime);
+
+  HIR::LoopLabel lower_loop_label (AST::LoopLabel &loop_label);
+
+  std::vector<std::unique_ptr<HIR::GenericParam> > lower_generic_params (
+    std::vector<std::unique_ptr<AST::GenericParam> > &params);
+
+  HIR::PathExprSegment lower_path_expr_seg (AST::PathExprSegment &s);
+
+  HIR::GenericArgs lower_generic_args (AST::GenericArgs &args);
+
+  HIR::GenericArgsBinding lower_binding (AST::GenericArgsBinding &binding);
+
+  HIR::SelfParam lower_self (AST::SelfParam &self);
+
+  HIR::Type *lower_type_no_bounds (AST::TypeNoBounds *type);
+
+  HIR::TypeParamBound *lower_bound (AST::TypeParamBound *bound);
+
+  HIR::QualifiedPathType
+  lower_qual_path_type (AST::QualifiedPathType &qual_path_type);
+
+  HIR::FunctionQualifiers
+  lower_qualifiers (const AST::FunctionQualifiers &qualifiers);
+
+  void handle_outer_attributes (const HIR::Item &item);
+
+  void handle_lang_item_attribute (const HIR::Item &item,
+				   const AST::Attribute &attr);
+
+  void handle_doc_item_attribute (const HIR::Item &item,
+				  const AST::Attribute &attr);
+
+  bool is_known_attribute (const std::string &attribute_path) const;
+
+  bool
+  attribute_handled_in_another_pass (const std::string &attribute_path) const;
+
+  std::unique_ptr<TuplePatternItems>
+  lower_tuple_pattern_multiple (AST::TuplePatternItemsMultiple &pattern);
+
+  std::unique_ptr<TuplePatternItems>
+  lower_tuple_pattern_ranged (AST::TuplePatternItemsRanged &pattern);
+
+  std::unique_ptr<HIR::RangePatternBound>
+  lower_range_pattern_bound (AST::RangePatternBound *bound);
+
+  HIR::Literal lower_literal (const AST::Literal &literal);
+
+  HIR::ExternBlock *lower_extern_block (AST::ExternBlock &extern_block);
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_BASE
diff --git a/gcc/rust/hir/rust-ast-lower-block.h b/gcc/rust/hir/rust-ast-lower-block.h
new file mode 100644
index 00000000000..0d3c704c6f1
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-block.h
@@ -0,0 +1,230 @@
+// 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_AST_LOWER_BLOCK
+#define RUST_AST_LOWER_BLOCK
+
+#include "rust-diagnostics.h"
+#include "rust-ast-lower-base.h"
+
+namespace Rust {
+namespace HIR {
+
+class ASTLoweringBlock : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::BlockExpr *translate (AST::BlockExpr *expr, bool *terminated)
+  {
+    ASTLoweringBlock resolver;
+    expr->accept_vis (resolver);
+    if (resolver.translated != nullptr)
+      {
+	resolver.mappings->insert_hir_expr (resolver.translated);
+      }
+
+    *terminated = resolver.terminated;
+    return resolver.translated;
+  }
+
+  static HIR::UnsafeBlockExpr *translate (AST::UnsafeBlockExpr *expr,
+					  bool *terminated)
+  {
+    ASTLoweringBlock resolver;
+
+    HIR::BlockExpr *block
+      = ASTLoweringBlock::translate (expr->get_block_expr ().get (),
+				     terminated);
+    auto crate_num = resolver.mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr->get_node_id (),
+				   resolver.mappings->get_next_hir_id (
+				     crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    HIR::UnsafeBlockExpr *translated
+      = new HIR::UnsafeBlockExpr (mapping,
+				  std::unique_ptr<HIR::BlockExpr> (block),
+				  expr->get_outer_attrs (), expr->get_locus ());
+
+    resolver.mappings->insert_hir_expr (translated);
+
+    return translated;
+  }
+
+  void visit (AST::BlockExpr &expr) override;
+
+private:
+  ASTLoweringBlock ()
+    : ASTLoweringBase (), translated (nullptr), terminated (false)
+  {}
+
+  HIR::BlockExpr *translated;
+  bool terminated;
+};
+
+class ASTLoweringIfBlock : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::IfExpr *translate (AST::IfExpr *expr, bool *terminated)
+  {
+    ASTLoweringIfBlock resolver;
+    expr->accept_vis (resolver);
+    if (resolver.translated != nullptr)
+      {
+	resolver.mappings->insert_hir_expr (resolver.translated);
+      }
+    *terminated = resolver.terminated;
+    return resolver.translated;
+  }
+
+  ~ASTLoweringIfBlock () {}
+
+  void visit (AST::IfExpr &expr) override;
+
+  void visit (AST::IfExprConseqElse &expr) override;
+
+  void visit (AST::IfExprConseqIf &expr) override;
+
+private:
+  ASTLoweringIfBlock ()
+    : ASTLoweringBase (), translated (nullptr), terminated (false)
+  {}
+
+  HIR::IfExpr *translated;
+  bool terminated;
+};
+
+class ASTLoweringIfLetBlock : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::IfLetExpr *translate (AST::IfLetExpr *expr)
+  {
+    ASTLoweringIfLetBlock resolver;
+    expr->accept_vis (resolver);
+    if (resolver.translated != nullptr)
+      {
+	resolver.mappings->insert_hir_expr (resolver.translated);
+      }
+    return resolver.translated;
+  }
+
+  ~ASTLoweringIfLetBlock () {}
+
+  void visit (AST::IfLetExpr &expr) override;
+
+private:
+  ASTLoweringIfLetBlock () : ASTLoweringBase (), translated (nullptr) {}
+
+  HIR::IfLetExpr *translated;
+};
+
+class ASTLoweringExprWithBlock : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::ExprWithBlock *translate (AST::ExprWithBlock *expr,
+					bool *terminated)
+  {
+    ASTLoweringExprWithBlock resolver;
+    expr->accept_vis (resolver);
+    if (resolver.translated != nullptr)
+      {
+	resolver.mappings->insert_hir_expr (resolver.translated);
+      }
+
+    *terminated = resolver.terminated;
+    return resolver.translated;
+  }
+
+  ~ASTLoweringExprWithBlock () {}
+
+  void visit (AST::IfExpr &expr) override
+  {
+    translated = ASTLoweringIfBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::IfExprConseqElse &expr) override
+  {
+    translated = ASTLoweringIfBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::IfExprConseqIf &expr) override
+  {
+    translated = ASTLoweringIfBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::IfLetExpr &expr) override
+  {
+    translated = ASTLoweringIfLetBlock::translate (&expr);
+  }
+
+  void visit (AST::BlockExpr &expr) override
+  {
+    translated = ASTLoweringBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::UnsafeBlockExpr &expr) override
+  {
+    translated = ASTLoweringBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::LoopExpr &expr) override
+  {
+    HIR::BlockExpr *loop_block
+      = ASTLoweringBlock::translate (expr.get_loop_block ().get (),
+				     &terminated);
+
+    HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::LoopExpr (mapping,
+			   std::unique_ptr<HIR::BlockExpr> (loop_block),
+			   expr.get_locus (), std::move (loop_label),
+			   expr.get_outer_attrs ());
+  }
+
+  void visit (AST::WhileLoopExpr &expr) override;
+
+  void visit (AST::ForLoopExpr &expr) override;
+
+  void visit (AST::MatchExpr &expr) override;
+
+private:
+  ASTLoweringExprWithBlock ()
+    : ASTLoweringBase (), translated (nullptr), terminated (false)
+  {}
+
+  HIR::ExprWithBlock *translated;
+  bool terminated;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_BLOCK
diff --git a/gcc/rust/hir/rust-ast-lower-enumitem.h b/gcc/rust/hir/rust-ast-lower-enumitem.h
new file mode 100644
index 00000000000..b76658c78cc
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-enumitem.h
@@ -0,0 +1,181 @@
+// 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_AST_LOWER_ENUMITEM
+#define RUST_AST_LOWER_ENUMITEM
+
+#include "rust-ast-lower.h"
+#include "rust-diagnostics.h"
+
+#include "rust-ast-lower-base.h"
+#include "rust-ast-lower-type.h"
+#include "rust-ast-lower-expr.h"
+#include "rust-hir-full-decls.h"
+
+namespace Rust {
+namespace HIR {
+
+class ASTLoweringEnumItem : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::EnumItem *translate (AST::EnumItem *item)
+  {
+    ASTLoweringEnumItem resolver;
+    item->accept_vis (resolver);
+
+    rust_assert (resolver.translated != nullptr);
+
+    auto hirid = resolver.translated->get_mappings ().get_hirid ();
+    auto defid = resolver.translated->get_mappings ().get_defid ();
+
+    resolver.mappings->insert_defid_mapping (defid, resolver.translated);
+    resolver.mappings->insert_hir_item (resolver.translated);
+    resolver.mappings->insert_location (hirid,
+					resolver.translated->get_locus ());
+
+    return resolver.translated;
+  }
+
+  void visit (AST::EnumItem &item) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, item.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    if (item.has_visibility ())
+      rust_error_at (item.get_locus (),
+		     "visibility qualifier %qs not allowed on enum item",
+		     item.get_visibility ().as_string ().c_str ());
+    translated = new HIR::EnumItem (mapping, item.get_identifier (),
+				    item.get_outer_attrs (), item.get_locus ());
+  }
+
+  void visit (AST::EnumItemTuple &item) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, item.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    if (item.has_visibility ())
+      rust_error_at (item.get_locus (),
+		     "visibility qualifier %qs not allowed on enum item",
+		     item.get_visibility ().as_string ().c_str ());
+
+    std::vector<HIR::TupleField> fields;
+    for (auto &field : item.get_tuple_fields ())
+      {
+	HIR::Visibility vis = translate_visibility (field.get_visibility ());
+	HIR::Type *type
+	  = ASTLoweringType::translate (field.get_field_type ().get ());
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping field_mapping (
+	  crate_num, field.get_node_id (),
+	  mappings->get_next_hir_id (crate_num),
+	  mappings->get_next_localdef_id (crate_num));
+
+	HIR::TupleField translated_field (field_mapping,
+					  std::unique_ptr<HIR::Type> (type),
+					  vis, field.get_locus (),
+					  field.get_outer_attrs ());
+	fields.push_back (std::move (translated_field));
+      }
+
+    translated
+      = new HIR::EnumItemTuple (mapping, item.get_identifier (),
+				std::move (fields), item.get_outer_attrs (),
+				item.get_locus ());
+  }
+
+  void visit (AST::EnumItemStruct &item) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, item.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    if (item.has_visibility ())
+      rust_error_at (item.get_locus (),
+		     "visibility qualifier %qs not allowed on enum item",
+		     item.get_visibility ().as_string ().c_str ());
+
+    std::vector<HIR::StructField> fields;
+    for (auto &field : item.get_struct_fields ())
+      {
+	HIR::Visibility vis = translate_visibility (field.get_visibility ());
+	HIR::Type *type
+	  = ASTLoweringType::translate (field.get_field_type ().get ());
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping field_mapping (
+	  crate_num, field.get_node_id (),
+	  mappings->get_next_hir_id (crate_num),
+	  mappings->get_next_localdef_id (crate_num));
+
+	HIR::StructField translated_field (field_mapping,
+					   field.get_field_name (),
+					   std::unique_ptr<HIR::Type> (type),
+					   vis, field.get_locus (),
+					   field.get_outer_attrs ());
+
+	if (struct_field_name_exists (fields, translated_field))
+	  break;
+
+	fields.push_back (std::move (translated_field));
+      }
+
+    translated
+      = new HIR::EnumItemStruct (mapping, item.get_identifier (),
+				 std::move (fields), item.get_outer_attrs (),
+				 item.get_locus ());
+  }
+
+  void visit (AST::EnumItemDiscriminant &item) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, item.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    if (item.has_visibility ())
+      rust_error_at (item.get_locus (),
+		     "visibility qualifier %qs not allowed on enum item",
+		     item.get_visibility ().as_string ().c_str ());
+
+    HIR::Expr *expr = ASTLoweringExpr::translate (item.get_expr ().get ());
+    translated
+      = new HIR::EnumItemDiscriminant (mapping, item.get_identifier (),
+				       std::unique_ptr<HIR::Expr> (expr),
+				       item.get_outer_attrs (),
+				       item.get_locus ());
+  }
+
+private:
+  ASTLoweringEnumItem () : translated (nullptr) {}
+
+  HIR::EnumItem *translated;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_ENUMITEM
diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h
new file mode 100644
index 00000000000..4f7f40f27e4
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-expr.h
@@ -0,0 +1,766 @@
+// 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_AST_LOWER_EXPR
+#define RUST_AST_LOWER_EXPR
+
+#include "rust-diagnostics.h"
+#include "rust-ast-lower-base.h"
+#include "rust-ast-lower-block.h"
+#include "rust-ast-lower-struct-field-expr.h"
+#include "rust-ast-lower-pattern.h"
+
+namespace Rust {
+namespace HIR {
+
+class ASTLowerPathInExpression : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::PathInExpression *translate (AST::PathInExpression *expr)
+  {
+    ASTLowerPathInExpression compiler;
+    expr->accept_vis (compiler);
+    rust_assert (compiler.translated);
+    return compiler.translated;
+  }
+
+  void visit (AST::PathInExpression &expr) override;
+
+private:
+  ASTLowerPathInExpression () : translated (nullptr) {}
+
+  HIR::PathInExpression *translated;
+};
+
+class ASTLowerQualPathInExpression : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::QualifiedPathInExpression *
+  translate (AST::QualifiedPathInExpression *expr)
+  {
+    ASTLowerQualPathInExpression compiler;
+    expr->accept_vis (compiler);
+    rust_assert (compiler.translated);
+    return compiler.translated;
+  }
+
+  void visit (AST::QualifiedPathInExpression &expr) override;
+
+private:
+  ASTLowerQualPathInExpression () : translated (nullptr) {}
+
+  HIR::QualifiedPathInExpression *translated;
+};
+
+class ASTLoweringExpr : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::Expr *translate (AST::Expr *expr, bool *terminated = nullptr)
+  {
+    ASTLoweringExpr resolver;
+    expr->accept_vis (resolver);
+    if (resolver.translated == nullptr)
+      {
+	rust_fatal_error (expr->get_locus (), "Failed to lower expr: [%s]",
+			  expr->as_string ().c_str ());
+	return nullptr;
+      }
+
+    resolver.mappings->insert_hir_expr (resolver.translated);
+    resolver.mappings->insert_location (
+      resolver.translated->get_mappings ().get_hirid (), expr->get_locus ());
+
+    if (terminated != nullptr)
+      *terminated = resolver.terminated;
+
+    return resolver.translated;
+  }
+
+  void visit (AST::TupleIndexExpr &expr) override
+  {
+    HIR::Expr *tuple_expr
+      = ASTLoweringExpr::translate (expr.get_tuple_expr ().get (), &terminated);
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::TupleIndexExpr (mapping,
+				 std::unique_ptr<HIR::Expr> (tuple_expr),
+				 expr.get_tuple_index (),
+				 expr.get_outer_attrs (), expr.get_locus ());
+  }
+
+  void visit (AST::TupleExpr &expr) override
+  {
+    std::vector<std::unique_ptr<HIR::Expr> > tuple_elements;
+    for (auto &e : expr.get_tuple_elems ())
+      {
+	HIR::Expr *t = ASTLoweringExpr::translate (e.get ());
+	tuple_elements.push_back (std::unique_ptr<HIR::Expr> (t));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::TupleExpr (std::move (mapping), std::move (tuple_elements),
+			    expr.get_inner_attrs (), expr.get_outer_attrs (),
+			    expr.get_locus ());
+  }
+
+  void visit (AST::IfExpr &expr) override
+  {
+    translated = ASTLoweringIfBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::IfExprConseqElse &expr) override
+  {
+    translated = ASTLoweringIfBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::IfExprConseqIf &expr) override
+  {
+    translated = ASTLoweringIfBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::BlockExpr &expr) override
+  {
+    translated = ASTLoweringBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::UnsafeBlockExpr &expr) override
+  {
+    translated = ASTLoweringBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::PathInExpression &expr) override
+  {
+    translated = ASTLowerPathInExpression::translate (&expr);
+  }
+
+  void visit (AST::QualifiedPathInExpression &expr) override
+  {
+    translated = ASTLowerQualPathInExpression::translate (&expr);
+  }
+
+  void visit (AST::ReturnExpr &expr) override
+  {
+    terminated = true;
+    HIR::Expr *return_expr
+      = expr.has_returned_expr ()
+	  ? ASTLoweringExpr::translate (expr.get_returned_expr ().get ())
+	  : nullptr;
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::ReturnExpr (mapping, expr.get_locus (),
+				      std::unique_ptr<HIR::Expr> (return_expr));
+  }
+
+  void visit (AST::CallExpr &expr) override
+  {
+    HIR::Expr *func
+      = ASTLoweringExpr::translate (expr.get_function_expr ().get ());
+
+    auto const &in_params = expr.get_params ();
+    std::vector<std::unique_ptr<HIR::Expr> > params;
+    for (auto &param : in_params)
+      {
+	auto trans = ASTLoweringExpr::translate (param.get ());
+	params.push_back (std::unique_ptr<HIR::Expr> (trans));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (
+      crate_num, UNKNOWN_NODEID /* this can map back to the AST*/,
+      mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::CallExpr (mapping, std::unique_ptr<HIR::Expr> (func),
+				    std::move (params), expr.get_outer_attrs (),
+				    expr.get_locus ());
+  }
+
+  void visit (AST::MethodCallExpr &expr) override
+  {
+    HIR::PathExprSegment method_path
+      = lower_path_expr_seg (expr.get_method_name ());
+
+    HIR::Expr *receiver
+      = ASTLoweringExpr::translate (expr.get_receiver_expr ().get ());
+
+    auto const &in_params = expr.get_params ();
+    std::vector<std::unique_ptr<HIR::Expr> > params;
+    for (auto &param : in_params)
+      {
+	auto trans = ASTLoweringExpr::translate (param.get ());
+	params.push_back (std::unique_ptr<HIR::Expr> (trans));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::MethodCallExpr (mapping, std::unique_ptr<HIR::Expr> (receiver),
+				 method_path, std::move (params),
+				 expr.get_outer_attrs (), expr.get_locus ());
+  }
+
+  void visit (AST::AssignmentExpr &expr) override
+  {
+    HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ());
+    HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::AssignmentExpr (mapping, std::unique_ptr<HIR::Expr> (lhs),
+				 std::unique_ptr<HIR::Expr> (rhs),
+				 expr.get_locus ());
+  }
+
+  void visit (AST::IdentifierExpr &expr) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping1 (crate_num, expr.get_node_id (),
+				    mappings->get_next_hir_id (crate_num),
+				    UNKNOWN_LOCAL_DEFID);
+    Analysis::NodeMapping mapping2 (mapping1);
+
+    HIR::PathIdentSegment ident_seg (expr.get_ident ());
+    HIR::PathExprSegment seg (mapping1, ident_seg, expr.get_locus (),
+			      HIR::GenericArgs::create_empty ());
+    translated = new HIR::PathInExpression (mapping2, {seg}, expr.get_locus (),
+					    false, expr.get_outer_attrs ());
+  }
+
+  void visit (AST::ArrayExpr &expr) override
+  {
+    expr.get_array_elems ()->accept_vis (*this);
+    rust_assert (translated_array_elems != nullptr);
+    HIR::ArrayElems *elems = translated_array_elems;
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::ArrayExpr (mapping, std::unique_ptr<HIR::ArrayElems> (elems),
+			    expr.get_inner_attrs (), expr.get_outer_attrs (),
+			    expr.get_locus ());
+  }
+
+  void visit (AST::ArrayIndexExpr &expr) override
+  {
+    HIR::Expr *array_expr
+      = ASTLoweringExpr::translate (expr.get_array_expr ().get ());
+    HIR::Expr *array_index_expr
+      = ASTLoweringExpr::translate (expr.get_index_expr ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::ArrayIndexExpr (mapping,
+				 std::unique_ptr<HIR::Expr> (array_expr),
+				 std::unique_ptr<HIR::Expr> (array_index_expr),
+				 expr.get_outer_attrs (), expr.get_locus ());
+  }
+
+  void visit (AST::ArrayElemsValues &elems) override
+  {
+    std::vector<std::unique_ptr<HIR::Expr> > elements;
+    for (auto &elem : elems.get_values ())
+      {
+	HIR::Expr *translated_elem = ASTLoweringExpr::translate (elem.get ());
+	elements.push_back (std::unique_ptr<HIR::Expr> (translated_elem));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (mappings->get_current_crate (),
+				   elems.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated_array_elems
+      = new HIR::ArrayElemsValues (mapping, std::move (elements));
+  }
+
+  void visit (AST::ArrayElemsCopied &elems) override
+  {
+    HIR::Expr *element
+      = ASTLoweringExpr::translate (elems.get_elem_to_copy ().get ());
+    HIR::Expr *num_copies
+      = ASTLoweringExpr::translate (elems.get_num_copies ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (mappings->get_current_crate (),
+				   elems.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated_array_elems
+      = new HIR::ArrayElemsCopied (mapping,
+				   std::unique_ptr<HIR::Expr> (element),
+				   std::unique_ptr<HIR::Expr> (num_copies));
+  }
+
+  void visit (AST::LiteralExpr &expr) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    HIR::Literal l = lower_literal (expr.get_literal ());
+    translated
+      = new HIR::LiteralExpr (mapping, std::move (l), expr.get_locus (),
+			      expr.get_outer_attrs ());
+  }
+
+  void visit (AST::ArithmeticOrLogicalExpr &expr) override
+  {
+    HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ());
+    rust_assert (lhs != nullptr);
+    HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ());
+    rust_assert (rhs != nullptr);
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::ArithmeticOrLogicalExpr (mapping,
+					  std::unique_ptr<HIR::Expr> (lhs),
+					  std::unique_ptr<HIR::Expr> (rhs),
+					  expr.get_expr_type (),
+					  expr.get_locus ());
+  }
+
+  void visit (AST::ComparisonExpr &expr) override
+  {
+    HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ());
+    rust_assert (lhs != nullptr);
+    HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ());
+    rust_assert (rhs != nullptr);
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::ComparisonExpr (mapping, std::unique_ptr<HIR::Expr> (lhs),
+				 std::unique_ptr<HIR::Expr> (rhs),
+				 expr.get_expr_type (), expr.get_locus ());
+  }
+
+  void visit (AST::LazyBooleanExpr &expr) override
+  {
+    HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ());
+    rust_assert (lhs != nullptr);
+    HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ());
+    rust_assert (rhs != nullptr);
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::LazyBooleanExpr (mapping, std::unique_ptr<HIR::Expr> (lhs),
+				  std::unique_ptr<HIR::Expr> (rhs),
+				  expr.get_expr_type (), expr.get_locus ());
+  }
+
+  void visit (AST::NegationExpr &expr) override
+  {
+    HIR::Expr *negated_value
+      = ASTLoweringExpr::translate (expr.get_negated_expr ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+    translated
+      = new HIR::NegationExpr (mapping,
+			       std::unique_ptr<HIR::Expr> (negated_value),
+			       expr.get_expr_type (), expr.get_outer_attrs (),
+			       expr.get_locus ());
+  }
+
+  void visit (AST::TypeCastExpr &expr) override
+  {
+    HIR::Expr *expr_to_cast_to
+      = ASTLoweringExpr::translate (expr.get_casted_expr ().get ());
+    HIR::Type *type_to_cast_to
+      = lower_type_no_bounds (expr.get_type_to_cast_to ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::TypeCastExpr (mapping,
+			       std::unique_ptr<HIR::Expr> (expr_to_cast_to),
+			       std::unique_ptr<HIR::Type> (type_to_cast_to),
+			       expr.get_locus ());
+  }
+
+  void visit (AST::CompoundAssignmentExpr &expr) override
+  {
+    ArithmeticOrLogicalOperator op;
+    switch (expr.get_expr_type ())
+      {
+      case CompoundAssignmentOperator::ADD:
+	op = ArithmeticOrLogicalOperator::ADD;
+	break;
+      case CompoundAssignmentOperator::SUBTRACT:
+	op = ArithmeticOrLogicalOperator::SUBTRACT;
+	break;
+      case CompoundAssignmentOperator::MULTIPLY:
+	op = ArithmeticOrLogicalOperator::MULTIPLY;
+	break;
+      case CompoundAssignmentOperator::DIVIDE:
+	op = ArithmeticOrLogicalOperator::DIVIDE;
+	break;
+      case CompoundAssignmentOperator::MODULUS:
+	op = ArithmeticOrLogicalOperator::MODULUS;
+	break;
+      case CompoundAssignmentOperator::BITWISE_AND:
+	op = ArithmeticOrLogicalOperator::BITWISE_AND;
+	break;
+      case CompoundAssignmentOperator::BITWISE_OR:
+	op = ArithmeticOrLogicalOperator::BITWISE_OR;
+	break;
+      case CompoundAssignmentOperator::BITWISE_XOR:
+	op = ArithmeticOrLogicalOperator::BITWISE_XOR;
+	break;
+      case CompoundAssignmentOperator::LEFT_SHIFT:
+	op = ArithmeticOrLogicalOperator::LEFT_SHIFT;
+	break;
+      case CompoundAssignmentOperator::RIGHT_SHIFT:
+	op = ArithmeticOrLogicalOperator::RIGHT_SHIFT;
+	break;
+      default:
+	gcc_unreachable ();
+      }
+
+    HIR::Expr *asignee_expr
+      = ASTLoweringExpr::translate (expr.get_left_expr ().get ());
+    HIR::Expr *value
+      = ASTLoweringExpr::translate (expr.get_right_expr ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::CompoundAssignmentExpr (
+      mapping, std::unique_ptr<HIR::Expr> (asignee_expr),
+      std::unique_ptr<HIR::Expr> (value), op, expr.get_locus ());
+  }
+
+  void visit (AST::StructExprStruct &struct_expr) override
+  {
+    HIR::PathInExpression *path
+      = ASTLowerPathInExpression::translate (&struct_expr.get_struct_name ());
+    HIR::PathInExpression copied_path (*path);
+    delete path;
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, struct_expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::StructExprStruct (mapping, copied_path,
+					    struct_expr.get_inner_attrs (),
+					    struct_expr.get_outer_attrs (),
+					    struct_expr.get_locus ());
+  }
+
+  void visit (AST::StructExprStructFields &struct_expr) override
+  {
+    // bit of a hack for now
+    HIR::PathInExpression *path
+      = ASTLowerPathInExpression::translate (&struct_expr.get_struct_name ());
+    HIR::PathInExpression copied_path (*path);
+    delete path;
+
+    HIR::StructBase *base = nullptr;
+    if (struct_expr.has_struct_base ())
+      {
+	HIR::Expr *translated_base = ASTLoweringExpr::translate (
+	  struct_expr.get_struct_base ().get_base_struct ().get ());
+	base
+	  = new HIR::StructBase (std::unique_ptr<HIR::Expr> (translated_base));
+      }
+
+    auto const &in_fields = struct_expr.get_fields ();
+    std::vector<std::unique_ptr<HIR::StructExprField> > fields;
+    for (auto &field : in_fields)
+      {
+	HIR::StructExprField *translated
+	  = ASTLowerStructExprField::translate (field.get ());
+	fields.push_back (std::unique_ptr<HIR::StructExprField> (translated));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, struct_expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::StructExprStructFields (
+      mapping, copied_path, std::move (fields), struct_expr.get_locus (), base,
+      struct_expr.get_inner_attrs (), struct_expr.get_outer_attrs ());
+  }
+
+  void visit (AST::GroupedExpr &expr) override
+  {
+    HIR::Expr *paren_expr
+      = ASTLoweringExpr::translate (expr.get_expr_in_parens ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::GroupedExpr (mapping, std::unique_ptr<HIR::Expr> (paren_expr),
+			      expr.get_inner_attrs (), expr.get_outer_attrs (),
+			      expr.get_locus ());
+  }
+
+  void visit (AST::FieldAccessExpr &expr) override
+  {
+    HIR::Expr *receiver
+      = ASTLoweringExpr::translate (expr.get_receiver_expr ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+    translated
+      = new HIR::FieldAccessExpr (mapping,
+				  std::unique_ptr<HIR::Expr> (receiver),
+				  expr.get_field_name (),
+				  expr.get_outer_attrs (), expr.get_locus ());
+  }
+
+  void visit (AST::LoopExpr &expr) override
+  {
+    translated = ASTLoweringExprWithBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::WhileLoopExpr &expr) override
+  {
+    translated = ASTLoweringExprWithBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::ForLoopExpr &expr) override
+  {
+    translated = ASTLoweringExprWithBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::BreakExpr &expr) override
+  {
+    HIR::Lifetime break_label = lower_lifetime (expr.get_label ());
+    HIR::Expr *break_expr
+      = expr.has_break_expr ()
+	  ? ASTLoweringExpr::translate (expr.get_break_expr ().get ())
+	  : nullptr;
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::BreakExpr (mapping, expr.get_locus (),
+				     std ::move (break_label),
+				     std::unique_ptr<HIR::Expr> (break_expr),
+				     expr.get_outer_attrs ());
+  }
+
+  void visit (AST::ContinueExpr &expr) override
+  {
+    HIR::Lifetime break_label = lower_lifetime (expr.get_label ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::ContinueExpr (mapping, expr.get_locus (),
+					std ::move (break_label),
+					expr.get_outer_attrs ());
+  }
+
+  void visit (AST::BorrowExpr &expr) override
+  {
+    HIR::Expr *borrow_lvalue
+      = ASTLoweringExpr::translate (expr.get_borrowed_expr ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::BorrowExpr (
+      mapping, std::unique_ptr<HIR::Expr> (borrow_lvalue),
+      expr.get_is_mut () ? Mutability::Mut : Mutability::Imm,
+      expr.get_is_double_borrow (), expr.get_outer_attrs (), expr.get_locus ());
+  }
+
+  void visit (AST::DereferenceExpr &expr) override
+  {
+    HIR::Expr *dref_lvalue
+      = ASTLoweringExpr::translate (expr.get_dereferenced_expr ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::DereferenceExpr (mapping,
+				  std::unique_ptr<HIR::Expr> (dref_lvalue),
+				  expr.get_outer_attrs (), expr.get_locus ());
+  }
+
+  void visit (AST::MatchExpr &expr) override
+  {
+    translated = ASTLoweringExprWithBlock::translate (&expr, &terminated);
+  }
+
+  void visit (AST::RangeFromToExpr &expr) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    HIR::Expr *range_from
+      = ASTLoweringExpr::translate (expr.get_from_expr ().get ());
+    HIR::Expr *range_to
+      = ASTLoweringExpr::translate (expr.get_to_expr ().get ());
+
+    translated
+      = new HIR::RangeFromToExpr (mapping,
+				  std::unique_ptr<HIR::Expr> (range_from),
+				  std::unique_ptr<HIR::Expr> (range_to),
+				  expr.get_locus ());
+  }
+
+  void visit (AST::RangeFromExpr &expr) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    HIR::Expr *range_from
+      = ASTLoweringExpr::translate (expr.get_from_expr ().get ());
+
+    translated
+      = new HIR::RangeFromExpr (mapping,
+				std::unique_ptr<HIR::Expr> (range_from),
+				expr.get_locus ());
+  }
+
+  void visit (AST::RangeToExpr &expr) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    HIR::Expr *range_to
+      = ASTLoweringExpr::translate (expr.get_to_expr ().get ());
+
+    translated
+      = new HIR::RangeToExpr (mapping, std::unique_ptr<HIR::Expr> (range_to),
+			      expr.get_locus ());
+  }
+
+  void visit (AST::RangeFullExpr &expr) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::RangeFullExpr (mapping, expr.get_locus ());
+  }
+
+  void visit (AST::RangeFromToInclExpr &expr) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    HIR::Expr *range_from
+      = ASTLoweringExpr::translate (expr.get_from_expr ().get ());
+    HIR::Expr *range_to
+      = ASTLoweringExpr::translate (expr.get_to_expr ().get ());
+
+    translated
+      = new HIR::RangeFromToInclExpr (mapping,
+				      std::unique_ptr<HIR::Expr> (range_from),
+				      std::unique_ptr<HIR::Expr> (range_to),
+				      expr.get_locus ());
+  }
+
+private:
+  ASTLoweringExpr ()
+    : ASTLoweringBase (), translated (nullptr),
+      translated_array_elems (nullptr), terminated (false)
+  {}
+
+  HIR::Expr *translated;
+  HIR::ArrayElems *translated_array_elems;
+  bool terminated;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_EXPR
diff --git a/gcc/rust/hir/rust-ast-lower-extern.h b/gcc/rust/hir/rust-ast-lower-extern.h
new file mode 100644
index 00000000000..eeb59c9c5d6
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-extern.h
@@ -0,0 +1,121 @@
+// 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_AST_LOWER_EXTERN_ITEM
+#define RUST_AST_LOWER_EXTERN_ITEM
+
+#include "rust-ast-lower-base.h"
+#include "rust-ast-lower-type.h"
+#include "rust-ast-lower.h"
+
+namespace Rust {
+namespace HIR {
+
+class ASTLoweringExternItem : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::ExternalItem *translate (AST::ExternalItem *item,
+				       HirId parent_hirid)
+  {
+    ASTLoweringExternItem resolver;
+    item->accept_vis (resolver);
+
+    rust_assert (resolver.translated != nullptr);
+    resolver.mappings->insert_hir_extern_item (resolver.translated,
+					       parent_hirid);
+    resolver.mappings->insert_location (
+      resolver.translated->get_mappings ().get_hirid (),
+      resolver.translated->get_locus ());
+
+    return resolver.translated;
+  }
+
+  void visit (AST::ExternalStaticItem &item) override
+  {
+    HIR::Visibility vis = translate_visibility (item.get_visibility ());
+    HIR::Type *static_type
+      = ASTLoweringType::translate (item.get_type ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, item.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::ExternalStaticItem (
+      mapping, item.get_identifier (), std::unique_ptr<HIR::Type> (static_type),
+      item.is_mut () ? Mutability::Mut : Mutability::Imm, std::move (vis),
+      item.get_outer_attrs (), item.get_locus ());
+  }
+
+  void visit (AST::ExternalFunctionItem &function) override
+  {
+    std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::Visibility vis = translate_visibility (function.get_visibility ());
+
+    std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+    if (function.has_generics ())
+      generic_params = lower_generic_params (function.get_generic_params ());
+
+    HIR::Type *return_type
+      = function.has_return_type ()
+	  ? ASTLoweringType::translate (function.get_return_type ().get ())
+	  : nullptr;
+
+    std::vector<HIR::NamedFunctionParam> function_params;
+    for (auto &param : function.get_function_params ())
+      {
+	HIR::Type *param_type
+	  = ASTLoweringType::translate (param.get_type ().get ());
+	Identifier param_name = param.get_name ();
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+				       mappings->get_next_hir_id (crate_num),
+				       mappings->get_next_localdef_id (
+					 crate_num));
+
+	function_params.push_back (
+	  HIR::NamedFunctionParam (mapping, param_name,
+				   std::unique_ptr<HIR::Type> (param_type)));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, function.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::ExternalFunctionItem (
+      mapping, function.get_identifier (), std::move (generic_params),
+      std::unique_ptr<HIR::Type> (return_type), std::move (where_clause),
+      std::move (function_params), function.is_variadic (), std::move (vis),
+      function.get_outer_attrs (), function.get_locus ());
+  }
+
+private:
+  ASTLoweringExternItem () : translated (nullptr) {}
+
+  HIR::ExternalItem *translated;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_ITEM
diff --git a/gcc/rust/hir/rust-ast-lower-implitem.h b/gcc/rust/hir/rust-ast-lower-implitem.h
new file mode 100644
index 00000000000..d5ca47587fc
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-implitem.h
@@ -0,0 +1,521 @@
+// 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_AST_LOWER_IMPLITEM_H
+#define RUST_AST_LOWER_IMPLITEM_H
+
+#include "rust-diagnostics.h"
+#include "rust-ast-lower-type.h"
+#include "rust-ast-lower-stmt.h"
+#include "rust-ast-lower-expr.h"
+#include "rust-ast-lower-pattern.h"
+#include "rust-ast-lower-block.h"
+
+namespace Rust {
+namespace HIR {
+
+class ASTLowerImplItem : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::ImplItem *translate (AST::InherentImplItem *item,
+				   HirId parent_impl_id)
+  {
+    ASTLowerImplItem resolver;
+    item->accept_vis (resolver);
+
+    if (resolver.translated != nullptr)
+      {
+	rust_assert (resolver.item_cast != nullptr);
+
+	auto id = resolver.translated->get_impl_mappings ().get_hirid ();
+	auto defid = resolver.translated->get_impl_mappings ().get_defid ();
+	auto locus = resolver.translated->get_locus ();
+
+	resolver.handle_outer_attributes (*resolver.item_cast);
+	resolver.mappings->insert_hir_implitem (parent_impl_id,
+						resolver.translated);
+	resolver.mappings->insert_location (id, locus);
+	resolver.mappings->insert_defid_mapping (defid, resolver.item_cast);
+      }
+
+    return resolver.translated;
+  }
+
+  static HIR::ImplItem *translate (AST::TraitImplItem *item,
+				   HirId parent_impl_id)
+  {
+    ASTLowerImplItem resolver;
+    item->accept_vis (resolver);
+
+    if (resolver.translated != nullptr)
+      {
+	rust_assert (resolver.item_cast != nullptr);
+
+	auto id = resolver.translated->get_impl_mappings ().get_hirid ();
+	auto defid = resolver.translated->get_impl_mappings ().get_defid ();
+	auto locus = resolver.translated->get_locus ();
+
+	resolver.handle_outer_attributes (*resolver.item_cast);
+	resolver.mappings->insert_hir_implitem (parent_impl_id,
+						resolver.translated);
+	resolver.mappings->insert_location (id, locus);
+	resolver.mappings->insert_defid_mapping (defid, resolver.item_cast);
+      }
+
+    return resolver.translated;
+  }
+
+  void visit (AST::TypeAlias &alias) override
+  {
+    std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::Visibility vis = translate_visibility (alias.get_visibility ());
+
+    std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+    if (alias.has_generics ())
+      generic_params = lower_generic_params (alias.get_generic_params ());
+
+    HIR::Type *existing_type
+      = ASTLoweringType::translate (alias.get_type_aliased ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, alias.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    auto type_alias = new HIR::TypeAlias (
+      mapping, alias.get_new_type_name (), std::move (generic_params),
+      std::move (where_clause), std::unique_ptr<HIR::Type> (existing_type),
+      std::move (vis), alias.get_outer_attrs (), alias.get_locus ());
+
+    translated = type_alias;
+    item_cast = type_alias;
+  }
+
+  void visit (AST::ConstantItem &constant) override
+  {
+    HIR::Visibility vis = translate_visibility (constant.get_visibility ());
+
+    HIR::Type *type = ASTLoweringType::translate (constant.get_type ().get ());
+    HIR::Expr *expr = ASTLoweringExpr::translate (constant.get_expr ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, constant.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    auto translated_constant
+      = new HIR::ConstantItem (mapping, constant.get_identifier (), vis,
+			       std::unique_ptr<HIR::Type> (type),
+			       std::unique_ptr<HIR::Expr> (expr),
+			       constant.get_outer_attrs (),
+			       constant.get_locus ());
+    translated = translated_constant;
+    item_cast = translated_constant;
+  }
+
+  void visit (AST::Function &function) override
+  {
+    // ignore for now and leave empty
+    std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::FunctionQualifiers qualifiers
+      = lower_qualifiers (function.get_qualifiers ());
+    HIR::Visibility vis = translate_visibility (function.get_visibility ());
+
+    // need
+    std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+    if (function.has_generics ())
+      {
+	generic_params = lower_generic_params (function.get_generic_params ());
+      }
+    Identifier function_name = function.get_function_name ();
+    Location locus = function.get_locus ();
+
+    std::unique_ptr<HIR::Type> return_type
+      = function.has_return_type () ? std::unique_ptr<HIR::Type> (
+	  ASTLoweringType::translate (function.get_return_type ().get ()))
+				    : nullptr;
+
+    std::vector<HIR::FunctionParam> function_params;
+    for (auto &param : function.get_function_params ())
+      {
+	auto translated_pattern = std::unique_ptr<HIR::Pattern> (
+	  ASTLoweringPattern::translate (param.get_pattern ().get ()));
+	auto translated_type = std::unique_ptr<HIR::Type> (
+	  ASTLoweringType::translate (param.get_type ().get ()));
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+				       mappings->get_next_hir_id (crate_num),
+				       UNKNOWN_LOCAL_DEFID);
+
+	auto hir_param
+	  = HIR::FunctionParam (mapping, std::move (translated_pattern),
+				std::move (translated_type),
+				param.get_locus ());
+	function_params.push_back (std::move (hir_param));
+      }
+
+    bool terminated = false;
+    std::unique_ptr<HIR::BlockExpr> function_body
+      = std::unique_ptr<HIR::BlockExpr> (
+	ASTLoweringBlock::translate (function.get_definition ().get (),
+				     &terminated));
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, function.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    mappings->insert_location (function_body->get_mappings ().get_hirid (),
+			       function.get_locus ());
+
+    auto fn
+      = new HIR::Function (mapping, std::move (function_name),
+			   std::move (qualifiers), std::move (generic_params),
+			   std::move (function_params), std::move (return_type),
+			   std::move (where_clause), std::move (function_body),
+			   std::move (vis), function.get_outer_attrs (),
+			   HIR::SelfParam::error (), locus);
+
+    // add the mappings for the function params at the end
+    for (auto &param : fn->get_function_params ())
+      {
+	mappings->insert_hir_param (&param);
+	mappings->insert_location (mapping.get_hirid (), param.get_locus ());
+      }
+
+    translated = fn;
+    item_cast = fn;
+  }
+
+  void visit (AST::Method &method) override
+  {
+    // ignore for now and leave empty
+    std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::FunctionQualifiers qualifiers
+      = lower_qualifiers (method.get_qualifiers ());
+    HIR::Visibility vis = translate_visibility (method.get_visibility ());
+
+    // need
+    std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+    if (method.has_generics ())
+      {
+	generic_params = lower_generic_params (method.get_generic_params ());
+      }
+    Identifier method_name = method.get_method_name ();
+    Location locus = method.get_locus ();
+
+    HIR::SelfParam self_param = lower_self (method.get_self_param ());
+
+    std::unique_ptr<HIR::Type> return_type
+      = method.has_return_type () ? std::unique_ptr<HIR::Type> (
+	  ASTLoweringType::translate (method.get_return_type ().get ()))
+				  : nullptr;
+
+    std::vector<HIR::FunctionParam> function_params;
+    for (auto &param : method.get_function_params ())
+      {
+	auto translated_pattern = std::unique_ptr<HIR::Pattern> (
+	  ASTLoweringPattern::translate (param.get_pattern ().get ()));
+	auto translated_type = std::unique_ptr<HIR::Type> (
+	  ASTLoweringType::translate (param.get_type ().get ()));
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+				       mappings->get_next_hir_id (crate_num),
+				       UNKNOWN_LOCAL_DEFID);
+
+	auto hir_param
+	  = HIR::FunctionParam (mapping, std::move (translated_pattern),
+				std::move (translated_type),
+				param.get_locus ());
+	function_params.push_back (std::move (hir_param));
+      }
+
+    bool terminated = false;
+    std::unique_ptr<HIR::BlockExpr> method_body
+      = std::unique_ptr<HIR::BlockExpr> (
+	ASTLoweringBlock::translate (method.get_definition ().get (),
+				     &terminated));
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, method.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+    auto mth
+      = new HIR::Function (mapping, std::move (method_name),
+			   std::move (qualifiers), std::move (generic_params),
+			   std::move (function_params), std::move (return_type),
+			   std::move (where_clause), std::move (method_body),
+			   std::move (vis), method.get_outer_attrs (),
+			   std::move (self_param), locus);
+
+    // insert mappings for self
+    mappings->insert_hir_self_param (&self_param);
+    mappings->insert_location (self_param.get_mappings ().get_hirid (),
+			       self_param.get_locus ());
+
+    // add the mappings for the function params at the end
+    for (auto &param : mth->get_function_params ())
+      {
+	mappings->insert_hir_param (&param);
+	mappings->insert_location (mapping.get_hirid (), param.get_locus ());
+      }
+
+    translated = mth;
+    item_cast = mth;
+  }
+
+private:
+  ASTLowerImplItem () : translated (nullptr), item_cast (nullptr) {}
+
+  HIR::ImplItem *translated;
+  HIR::Item *item_cast;
+};
+
+class ASTLowerTraitItem : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::TraitItem *translate (AST::TraitItem *item)
+  {
+    ASTLowerTraitItem resolver;
+    item->accept_vis (resolver);
+
+    if (resolver.translated != nullptr)
+      {
+	// FIXME
+
+	// auto id = resolver.translated->get_mappings ().get_hirid ();
+	// auto defid = resolver.translated->get_mappings ().get_defid ();
+	// auto locus = resolver.translated->get_locus ();
+
+	// resolver.handle_outer_attributes (*resolver.translated);
+	resolver.mappings->insert_hir_trait_item (resolver.translated);
+	// resolver.mappings->insert_location (id, locus);
+	// resolver.mappings->insert_defid_mapping (defid, resolver.item_cast);
+      }
+
+    return resolver.translated;
+  }
+
+  void visit (AST::TraitItemFunc &func) override
+  {
+    AST::TraitFunctionDecl &ref = func.get_trait_function_decl ();
+
+    std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::FunctionQualifiers qualifiers
+      = lower_qualifiers (func.get_trait_function_decl ().get_qualifiers ());
+
+    std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+    if (ref.has_generics ())
+      {
+	generic_params = lower_generic_params (ref.get_generic_params ());
+      }
+
+    std::unique_ptr<HIR::Type> return_type
+      = ref.has_return_type () ? std::unique_ptr<HIR::Type> (
+	  ASTLoweringType::translate (ref.get_return_type ().get ()))
+			       : nullptr;
+
+    std::vector<HIR::FunctionParam> function_params;
+    for (auto &param : ref.get_function_params ())
+      {
+	auto translated_pattern = std::unique_ptr<HIR::Pattern> (
+	  ASTLoweringPattern::translate (param.get_pattern ().get ()));
+	auto translated_type = std::unique_ptr<HIR::Type> (
+	  ASTLoweringType::translate (param.get_type ().get ()));
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+				       mappings->get_next_hir_id (crate_num),
+				       UNKNOWN_LOCAL_DEFID);
+
+	auto hir_param
+	  = HIR::FunctionParam (mapping, std::move (translated_pattern),
+				std::move (translated_type),
+				param.get_locus ());
+	function_params.push_back (std::move (hir_param));
+      }
+
+    HIR::TraitFunctionDecl decl (ref.get_identifier (), std::move (qualifiers),
+				 std::move (generic_params),
+				 HIR::SelfParam::error (),
+				 std::move (function_params),
+				 std::move (return_type),
+				 std::move (where_clause));
+    bool terminated = false;
+    std::unique_ptr<HIR::BlockExpr> block_expr
+      = func.has_definition () ? std::unique_ptr<HIR::BlockExpr> (
+	  ASTLoweringBlock::translate (func.get_definition ().get (),
+				       &terminated))
+			       : nullptr;
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, func.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    HIR::TraitItemFunc *trait_item
+      = new HIR::TraitItemFunc (mapping, std::move (decl),
+				std::move (block_expr), func.get_outer_attrs (),
+				func.get_locus ());
+    translated = trait_item;
+
+    // add the mappings for the function params at the end
+    for (auto &param : trait_item->get_decl ().get_function_params ())
+      {
+	mappings->insert_hir_param (&param);
+	mappings->insert_location (mapping.get_hirid (), param.get_locus ());
+      }
+  }
+
+  void visit (AST::TraitItemMethod &method) override
+  {
+    AST::TraitMethodDecl &ref = method.get_trait_method_decl ();
+
+    std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::FunctionQualifiers qualifiers
+      = lower_qualifiers (method.get_trait_method_decl ().get_qualifiers ());
+
+    std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+    if (ref.has_generics ())
+      {
+	generic_params = lower_generic_params (ref.get_generic_params ());
+      }
+
+    std::unique_ptr<HIR::Type> return_type
+      = ref.has_return_type () ? std::unique_ptr<HIR::Type> (
+	  ASTLoweringType::translate (ref.get_return_type ().get ()))
+			       : nullptr;
+
+    HIR::SelfParam self_param = lower_self (ref.get_self_param ());
+
+    std::vector<HIR::FunctionParam> function_params;
+    for (auto &param : ref.get_function_params ())
+      {
+	auto translated_pattern = std::unique_ptr<HIR::Pattern> (
+	  ASTLoweringPattern::translate (param.get_pattern ().get ()));
+	auto translated_type = std::unique_ptr<HIR::Type> (
+	  ASTLoweringType::translate (param.get_type ().get ()));
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+				       mappings->get_next_hir_id (crate_num),
+				       UNKNOWN_LOCAL_DEFID);
+
+	auto hir_param
+	  = HIR::FunctionParam (mapping, std::move (translated_pattern),
+				std::move (translated_type),
+				param.get_locus ());
+	function_params.push_back (hir_param);
+      }
+
+    HIR::TraitFunctionDecl decl (ref.get_identifier (), std::move (qualifiers),
+				 std::move (generic_params),
+				 std::move (self_param),
+				 std::move (function_params),
+				 std::move (return_type),
+				 std::move (where_clause));
+    bool terminated = false;
+    std::unique_ptr<HIR::BlockExpr> block_expr
+      = method.has_definition () ? std::unique_ptr<HIR::BlockExpr> (
+	  ASTLoweringBlock::translate (method.get_definition ().get (),
+				       &terminated))
+				 : nullptr;
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, method.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    HIR::TraitItemFunc *trait_item
+      = new HIR::TraitItemFunc (mapping, std::move (decl),
+				std::move (block_expr),
+				method.get_outer_attrs (), method.get_locus ());
+    translated = trait_item;
+
+    // insert mappings for self
+    mappings->insert_hir_self_param (&self_param);
+    mappings->insert_location (self_param.get_mappings ().get_hirid (),
+			       self_param.get_locus ());
+
+    // add the mappings for the function params at the end
+    for (auto &param : trait_item->get_decl ().get_function_params ())
+      {
+	mappings->insert_hir_param (&param);
+	mappings->insert_location (mapping.get_hirid (), param.get_locus ());
+      }
+  }
+
+  void visit (AST::TraitItemConst &constant) override
+  {
+    HIR::Type *type = ASTLoweringType::translate (constant.get_type ().get ());
+    HIR::Expr *expr
+      = constant.has_expression ()
+	  ? ASTLoweringExpr::translate (constant.get_expr ().get ())
+	  : nullptr;
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, constant.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    HIR::TraitItemConst *trait_item
+      = new HIR::TraitItemConst (mapping, constant.get_identifier (),
+				 std::unique_ptr<HIR::Type> (type),
+				 std::unique_ptr<HIR::Expr> (expr),
+				 constant.get_outer_attrs (),
+				 constant.get_locus ());
+    translated = trait_item;
+  }
+
+  void visit (AST::TraitItemType &type) override
+  {
+    std::vector<std::unique_ptr<HIR::TypeParamBound> > type_param_bounds;
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    HIR::TraitItemType *trait_item
+      = new HIR::TraitItemType (mapping, type.get_identifier (),
+				std::move (type_param_bounds),
+				type.get_outer_attrs (), type.get_locus ());
+    translated = trait_item;
+  }
+
+private:
+  ASTLowerTraitItem () : translated (nullptr) {}
+
+  HIR::TraitItem *translated;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_IMPLITEM_H
diff --git a/gcc/rust/hir/rust-ast-lower-item.cc b/gcc/rust/hir/rust-ast-lower-item.cc
new file mode 100644
index 00000000000..fefc938b8e5
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-item.cc
@@ -0,0 +1,741 @@
+// 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-ast-lower-item.h"
+
+namespace Rust {
+namespace HIR {
+
+HIR::Item *
+ASTLoweringItem::translate (AST::Item *item)
+{
+  ASTLoweringItem resolver;
+  item->accept_vis (resolver);
+
+  if (resolver.translated != nullptr)
+    {
+      auto id = resolver.translated->get_mappings ().get_hirid ();
+      auto defid = resolver.translated->get_mappings ().get_defid ();
+      auto locus = resolver.translated->get_locus ();
+
+      resolver.handle_outer_attributes (*resolver.translated);
+      resolver.mappings->insert_ast_item (item);
+      resolver.mappings->insert_hir_item (resolver.translated);
+      resolver.mappings->insert_location (id, locus);
+      resolver.mappings->insert_defid_mapping (defid, resolver.translated);
+    }
+
+  return resolver.translated;
+}
+
+void
+ASTLoweringItem::visit (AST::Module &module)
+{
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, module.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  // should be lowered from module.get_vis()
+  HIR::Visibility vis = translate_visibility (module.get_visibility ());
+
+  auto items = std::vector<std::unique_ptr<Item>> ();
+
+  for (auto &item : module.get_items ())
+    {
+      auto transitem = translate (item.get ());
+      items.push_back (std::unique_ptr<Item> (transitem));
+    }
+
+  // should be lowered/copied from module.get_in/outer_attrs()
+  AST::AttrVec inner_attrs = module.get_inner_attrs ();
+  AST::AttrVec outer_attrs = module.get_outer_attrs ();
+
+  translated
+    = new HIR::Module (mapping, module.get_name (), module.get_locus (),
+		       std::move (items), std::move (vis),
+		       std::move (inner_attrs), std::move (outer_attrs));
+  mappings->insert_module (static_cast<Module *> (translated));
+}
+
+void
+ASTLoweringItem::visit (AST::TypeAlias &alias)
+{
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+  for (auto &item : alias.get_where_clause ().get_items ())
+    {
+      HIR::WhereClauseItem *i
+	= ASTLowerWhereClauseItem::translate (*item.get ());
+      where_clause_items.push_back (std::unique_ptr<HIR::WhereClauseItem> (i));
+    }
+
+  HIR::WhereClause where_clause (std::move (where_clause_items));
+  HIR::Visibility vis = translate_visibility (alias.get_visibility ());
+
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+  if (alias.has_generics ())
+    generic_params = lower_generic_params (alias.get_generic_params ());
+
+  HIR::Type *existing_type
+    = ASTLoweringType::translate (alias.get_type_aliased ().get ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, alias.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated
+    = new HIR::TypeAlias (mapping, alias.get_new_type_name (),
+			  std::move (generic_params), std::move (where_clause),
+			  std::unique_ptr<HIR::Type> (existing_type),
+			  std::move (vis), alias.get_outer_attrs (),
+			  alias.get_locus ());
+}
+
+void
+ASTLoweringItem::visit (AST::TupleStruct &struct_decl)
+{
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+  if (struct_decl.has_generics ())
+    {
+      generic_params = lower_generic_params (struct_decl.get_generic_params ());
+    }
+
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+  for (auto &item : struct_decl.get_where_clause ().get_items ())
+    {
+      HIR::WhereClauseItem *i
+	= ASTLowerWhereClauseItem::translate (*item.get ());
+      where_clause_items.push_back (std::unique_ptr<HIR::WhereClauseItem> (i));
+    }
+
+  HIR::WhereClause where_clause (std::move (where_clause_items));
+  HIR::Visibility vis = translate_visibility (struct_decl.get_visibility ());
+
+  std::vector<HIR::TupleField> fields;
+  for (AST::TupleField &field : struct_decl.get_fields ())
+    {
+      if (field.get_field_type ()->is_marked_for_strip ())
+	continue;
+
+      // FIXME: How do we get the visibility from here?
+      HIR::Visibility vis = translate_visibility (field.get_visibility ());
+      HIR::Type *type
+	= ASTLoweringType::translate (field.get_field_type ().get ());
+
+      auto crate_num = mappings->get_current_crate ();
+      Analysis::NodeMapping mapping (crate_num, field.get_node_id (),
+				     mappings->get_next_hir_id (crate_num),
+				     mappings->get_next_localdef_id (
+				       crate_num));
+
+      HIR::TupleField translated_field (mapping,
+					std::unique_ptr<HIR::Type> (type), vis,
+					field.get_locus (),
+					field.get_outer_attrs ());
+      fields.push_back (std::move (translated_field));
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, struct_decl.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated = new HIR::TupleStruct (mapping, std::move (fields),
+				     struct_decl.get_identifier (),
+				     std::move (generic_params),
+				     std::move (where_clause), vis,
+				     struct_decl.get_outer_attrs (),
+				     struct_decl.get_locus ());
+}
+
+void
+ASTLoweringItem::visit (AST::StructStruct &struct_decl)
+{
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+  if (struct_decl.has_generics ())
+    {
+      generic_params = lower_generic_params (struct_decl.get_generic_params ());
+    }
+
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+  for (auto &item : struct_decl.get_where_clause ().get_items ())
+    {
+      HIR::WhereClauseItem *i
+	= ASTLowerWhereClauseItem::translate (*item.get ());
+      where_clause_items.push_back (std::unique_ptr<HIR::WhereClauseItem> (i));
+    }
+
+  HIR::WhereClause where_clause (std::move (where_clause_items));
+
+  HIR::Visibility vis = translate_visibility (struct_decl.get_visibility ());
+
+  bool is_unit = struct_decl.is_unit_struct ();
+  std::vector<HIR::StructField> fields;
+  for (AST::StructField &field : struct_decl.get_fields ())
+    {
+      if (field.get_field_type ()->is_marked_for_strip ())
+	continue;
+
+      HIR::Visibility vis = translate_visibility (field.get_visibility ());
+      HIR::Type *type
+	= ASTLoweringType::translate (field.get_field_type ().get ());
+
+      auto crate_num = mappings->get_current_crate ();
+      Analysis::NodeMapping mapping (crate_num, field.get_node_id (),
+				     mappings->get_next_hir_id (crate_num),
+				     mappings->get_next_localdef_id (
+				       crate_num));
+
+      HIR::StructField translated_field (mapping, field.get_field_name (),
+					 std::unique_ptr<HIR::Type> (type), vis,
+					 field.get_locus (),
+					 field.get_outer_attrs ());
+
+      if (struct_field_name_exists (fields, translated_field))
+	break;
+
+      fields.push_back (std::move (translated_field));
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, struct_decl.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated = new HIR::StructStruct (mapping, std::move (fields),
+				      struct_decl.get_identifier (),
+				      std::move (generic_params),
+				      std::move (where_clause), is_unit, vis,
+				      struct_decl.get_outer_attrs (),
+				      struct_decl.get_locus ());
+}
+
+void
+ASTLoweringItem::visit (AST::Enum &enum_decl)
+{
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+  if (enum_decl.has_generics ())
+    {
+      generic_params = lower_generic_params (enum_decl.get_generic_params ());
+    }
+
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+  for (auto &item : enum_decl.get_where_clause ().get_items ())
+    {
+      HIR::WhereClauseItem *i
+	= ASTLowerWhereClauseItem::translate (*item.get ());
+      where_clause_items.push_back (std::unique_ptr<HIR::WhereClauseItem> (i));
+    }
+
+  HIR::WhereClause where_clause (std::move (where_clause_items));
+  HIR::Visibility vis = translate_visibility (enum_decl.get_visibility ());
+
+  // bool is_unit = enum_decl.is_zero_variant ();
+  std::vector<std::unique_ptr<HIR::EnumItem>> items;
+  for (auto &variant : enum_decl.get_variants ())
+    {
+      if (variant->is_marked_for_strip ())
+	continue;
+
+      HIR::EnumItem *hir_item = ASTLoweringEnumItem::translate (variant.get ());
+      items.push_back (std::unique_ptr<HIR::EnumItem> (hir_item));
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, enum_decl.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated = new HIR::Enum (mapping, enum_decl.get_identifier (), vis,
+			      std::move (generic_params),
+			      std::move (where_clause), /* is_unit, */
+			      std::move (items), enum_decl.get_outer_attrs (),
+			      enum_decl.get_locus ());
+}
+
+void
+ASTLoweringItem::visit (AST::Union &union_decl)
+{
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+  if (union_decl.has_generics ())
+    {
+      generic_params = lower_generic_params (union_decl.get_generic_params ());
+    }
+
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+  for (auto &item : union_decl.get_where_clause ().get_items ())
+    {
+      HIR::WhereClauseItem *i
+	= ASTLowerWhereClauseItem::translate (*item.get ());
+      where_clause_items.push_back (std::unique_ptr<HIR::WhereClauseItem> (i));
+    }
+  HIR::WhereClause where_clause (std::move (where_clause_items));
+  HIR::Visibility vis = translate_visibility (union_decl.get_visibility ());
+
+  std::vector<HIR::StructField> variants;
+  for (AST::StructField &variant : union_decl.get_variants ())
+    {
+      if (variant.get_field_type ()->is_marked_for_strip ())
+	continue;
+
+      // FIXME: Does visibility apply here?
+      HIR::Visibility vis = translate_visibility (variant.get_visibility ());
+      HIR::Type *type
+	= ASTLoweringType::translate (variant.get_field_type ().get ());
+
+      auto crate_num = mappings->get_current_crate ();
+      Analysis::NodeMapping mapping (crate_num, variant.get_node_id (),
+				     mappings->get_next_hir_id (crate_num),
+				     mappings->get_next_localdef_id (
+				       crate_num));
+
+      HIR::StructField translated_variant (mapping, variant.get_field_name (),
+					   std::unique_ptr<HIR::Type> (type),
+					   vis, variant.get_locus (),
+					   variant.get_outer_attrs ());
+
+      if (struct_field_name_exists (variants, translated_variant))
+	break;
+
+      variants.push_back (std::move (translated_variant));
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, union_decl.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated
+    = new HIR::Union (mapping, union_decl.get_identifier (), vis,
+		      std::move (generic_params), std::move (where_clause),
+		      std::move (variants), union_decl.get_outer_attrs (),
+		      union_decl.get_locus ());
+}
+
+void
+ASTLoweringItem::visit (AST::StaticItem &var)
+{
+  HIR::Visibility vis = translate_visibility (var.get_visibility ());
+
+  HIR::Type *type = ASTLoweringType::translate (var.get_type ().get ());
+  HIR::Expr *expr = ASTLoweringExpr::translate (var.get_expr ().get ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, var.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated = new HIR::StaticItem (mapping, var.get_identifier (),
+				    var.is_mutable () ? Mutability::Mut
+						      : Mutability::Imm,
+				    std::unique_ptr<HIR::Type> (type),
+				    std::unique_ptr<HIR::Expr> (expr), vis,
+				    var.get_outer_attrs (), var.get_locus ());
+}
+
+void
+ASTLoweringItem::visit (AST::ConstantItem &constant)
+{
+  HIR::Visibility vis = translate_visibility (constant.get_visibility ());
+
+  HIR::Type *type = ASTLoweringType::translate (constant.get_type ().get ());
+  HIR::Expr *expr = ASTLoweringExpr::translate (constant.get_expr ().get ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, constant.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated = new HIR::ConstantItem (mapping, constant.get_identifier (), vis,
+				      std::unique_ptr<HIR::Type> (type),
+				      std::unique_ptr<HIR::Expr> (expr),
+				      constant.get_outer_attrs (),
+				      constant.get_locus ());
+}
+
+void
+ASTLoweringItem::visit (AST::Function &function)
+{
+  if (function.is_marked_for_strip ())
+    return;
+
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+  for (auto &item : function.get_where_clause ().get_items ())
+    {
+      HIR::WhereClauseItem *i
+	= ASTLowerWhereClauseItem::translate (*item.get ());
+      where_clause_items.push_back (std::unique_ptr<HIR::WhereClauseItem> (i));
+    }
+
+  HIR::WhereClause where_clause (std::move (where_clause_items));
+  HIR::FunctionQualifiers qualifiers
+    = lower_qualifiers (function.get_qualifiers ());
+  HIR::Visibility vis = translate_visibility (function.get_visibility ());
+
+  // need
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+  if (function.has_generics ())
+    {
+      generic_params = lower_generic_params (function.get_generic_params ());
+    }
+  Identifier function_name = function.get_function_name ();
+  Location locus = function.get_locus ();
+
+  std::unique_ptr<HIR::Type> return_type
+    = function.has_return_type () ? std::unique_ptr<HIR::Type> (
+	ASTLoweringType::translate (function.get_return_type ().get ()))
+				  : nullptr;
+
+  std::vector<HIR::FunctionParam> function_params;
+  for (auto &param : function.get_function_params ())
+    {
+      auto translated_pattern = std::unique_ptr<HIR::Pattern> (
+	ASTLoweringPattern::translate (param.get_pattern ().get ()));
+      auto translated_type = std::unique_ptr<HIR::Type> (
+	ASTLoweringType::translate (param.get_type ().get ()));
+
+      auto crate_num = mappings->get_current_crate ();
+      Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+				     mappings->get_next_hir_id (crate_num),
+				     UNKNOWN_LOCAL_DEFID);
+
+      auto hir_param
+	= HIR::FunctionParam (mapping, std::move (translated_pattern),
+			      std::move (translated_type), param.get_locus ());
+      function_params.push_back (std::move (hir_param));
+    }
+
+  bool terminated = false;
+  std::unique_ptr<HIR::BlockExpr> function_body
+    = std::unique_ptr<HIR::BlockExpr> (
+      ASTLoweringBlock::translate (function.get_definition ().get (),
+				   &terminated));
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, function.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  mappings->insert_location (function_body->get_mappings ().get_hirid (),
+			     function.get_locus ());
+
+  auto fn
+    = new HIR::Function (mapping, std::move (function_name),
+			 std::move (qualifiers), std::move (generic_params),
+			 std::move (function_params), std::move (return_type),
+			 std::move (where_clause), std::move (function_body),
+			 std::move (vis), function.get_outer_attrs (),
+			 HIR::SelfParam::error (), locus);
+
+  // add the mappings for the function params at the end
+  for (auto &param : fn->get_function_params ())
+    {
+      mappings->insert_hir_param (&param);
+      mappings->insert_location (mapping.get_hirid (), param.get_locus ());
+    }
+
+  translated = fn;
+}
+
+void
+ASTLoweringItem::visit (AST::InherentImpl &impl_block)
+{
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+  for (auto &item : impl_block.get_where_clause ().get_items ())
+    {
+      HIR::WhereClauseItem *i
+	= ASTLowerWhereClauseItem::translate (*item.get ());
+      where_clause_items.push_back (std::unique_ptr<HIR::WhereClauseItem> (i));
+    }
+
+  HIR::WhereClause where_clause (std::move (where_clause_items));
+  HIR::Visibility vis = translate_visibility (impl_block.get_visibility ());
+
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+  if (impl_block.has_generics ())
+    {
+      generic_params = lower_generic_params (impl_block.get_generic_params ());
+
+      for (auto &generic_param : generic_params)
+	{
+	  switch (generic_param->get_kind ())
+	    {
+	      case HIR::GenericParam::GenericKind::TYPE: {
+		const HIR::TypeParam &t
+		  = static_cast<const HIR::TypeParam &> (*generic_param);
+
+		if (t.has_type ())
+		  {
+		    // see https://github.com/rust-lang/rust/issues/36887
+		    rust_error_at (
+		      t.get_locus (),
+		      "defaults for type parameters are not allowed here");
+		  }
+	      }
+	      break;
+
+	    default:
+	      break;
+	    }
+	}
+    }
+
+  HIR::Type *impl_type
+    = ASTLoweringType::translate (impl_block.get_type ().get ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, impl_block.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  std::vector<std::unique_ptr<HIR::ImplItem>> impl_items;
+  std::vector<HirId> impl_item_ids;
+  for (auto &impl_item : impl_block.get_impl_items ())
+    {
+      if (impl_item->is_marked_for_strip ())
+	continue;
+
+      HIR::ImplItem *lowered
+	= ASTLowerImplItem::translate (impl_item.get (), mapping.get_hirid ());
+      rust_assert (lowered != nullptr);
+      impl_items.push_back (std::unique_ptr<HIR::ImplItem> (lowered));
+      impl_item_ids.push_back (lowered->get_impl_mappings ().get_hirid ());
+    }
+
+  Polarity polarity = Positive;
+  HIR::ImplBlock *hir_impl_block = new HIR::ImplBlock (
+    mapping, std::move (impl_items), std::move (generic_params),
+    std::unique_ptr<HIR::Type> (impl_type), nullptr, where_clause, polarity,
+    vis, impl_block.get_inner_attrs (), impl_block.get_outer_attrs (),
+    impl_block.get_locus ());
+  translated = hir_impl_block;
+
+  mappings->insert_hir_impl_block (hir_impl_block);
+  for (auto &impl_item_id : impl_item_ids)
+    {
+      mappings->insert_impl_item_mapping (impl_item_id, hir_impl_block);
+    }
+}
+
+void
+ASTLoweringItem::visit (AST::Trait &trait)
+{
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+  for (auto &item : trait.get_where_clause ().get_items ())
+    {
+      HIR::WhereClauseItem *i
+	= ASTLowerWhereClauseItem::translate (*item.get ());
+      where_clause_items.push_back (std::unique_ptr<HIR::WhereClauseItem> (i));
+    }
+  HIR::WhereClause where_clause (std::move (where_clause_items));
+
+  HIR::Visibility vis = translate_visibility (trait.get_visibility ());
+
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+  if (trait.has_generics ())
+    {
+      generic_params = lower_generic_params (trait.get_generic_params ());
+    }
+
+  std::vector<std::unique_ptr<HIR::TypeParamBound>> type_param_bounds;
+  if (trait.has_type_param_bounds ())
+    {
+      for (auto &bound : trait.get_type_param_bounds ())
+	{
+	  HIR::TypeParamBound *b = lower_bound (bound.get ());
+	  type_param_bounds.push_back (
+	    std::unique_ptr<HIR::TypeParamBound> (b));
+	}
+    }
+
+  std::vector<std::unique_ptr<HIR::TraitItem>> trait_items;
+  std::vector<HirId> trait_item_ids;
+  for (auto &item : trait.get_trait_items ())
+    {
+      if (item->is_marked_for_strip ())
+	continue;
+
+      HIR::TraitItem *lowered = ASTLowerTraitItem::translate (item.get ());
+      trait_items.push_back (std::unique_ptr<HIR::TraitItem> (lowered));
+      trait_item_ids.push_back (lowered->get_mappings ().get_hirid ());
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, trait.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  auto trait_unsafety = Unsafety::Normal;
+  if (trait.is_unsafe ())
+    {
+      trait_unsafety = Unsafety::Unsafe;
+    }
+
+  HIR::Trait *hir_trait
+    = new HIR::Trait (mapping, trait.get_identifier (), trait_unsafety,
+		      std::move (generic_params), std::move (type_param_bounds),
+		      where_clause, std::move (trait_items), vis,
+		      trait.get_outer_attrs (), trait.get_locus ());
+  translated = hir_trait;
+
+  for (auto trait_item_id : trait_item_ids)
+    {
+      mappings->insert_trait_item_mapping (trait_item_id, hir_trait);
+    }
+}
+
+void
+ASTLoweringItem::visit (AST::TraitImpl &impl_block)
+{
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+  for (auto &item : impl_block.get_where_clause ().get_items ())
+    {
+      HIR::WhereClauseItem *i
+	= ASTLowerWhereClauseItem::translate (*item.get ());
+      where_clause_items.push_back (std::unique_ptr<HIR::WhereClauseItem> (i));
+    }
+  HIR::WhereClause where_clause (std::move (where_clause_items));
+  HIR::Visibility vis = translate_visibility (impl_block.get_visibility ());
+
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+  if (impl_block.has_generics ())
+    {
+      generic_params = lower_generic_params (impl_block.get_generic_params ());
+
+      for (auto &generic_param : generic_params)
+	{
+	  switch (generic_param->get_kind ())
+	    {
+	      case HIR::GenericParam::GenericKind::TYPE: {
+		const HIR::TypeParam &t
+		  = static_cast<const HIR::TypeParam &> (*generic_param);
+
+		if (t.has_type ())
+		  {
+		    // see https://github.com/rust-lang/rust/issues/36887
+		    rust_error_at (
+		      t.get_locus (),
+		      "defaults for type parameters are not allowed here");
+		  }
+	      }
+	      break;
+
+	    default:
+	      break;
+	    }
+	}
+    }
+
+  HIR::Type *impl_type
+    = ASTLoweringType::translate (impl_block.get_type ().get ());
+  HIR::TypePath *trait_ref
+    = ASTLowerTypePath::translate (impl_block.get_trait_path ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, impl_block.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  std::vector<std::unique_ptr<HIR::ImplItem>> impl_items;
+  std::vector<HirId> impl_item_ids;
+  for (auto &impl_item : impl_block.get_impl_items ())
+    {
+      if (impl_item->is_marked_for_strip ())
+	continue;
+
+      HIR::ImplItem *lowered
+	= ASTLowerImplItem::translate (impl_item.get (), mapping.get_hirid ());
+      rust_assert (lowered != nullptr);
+      impl_items.push_back (std::unique_ptr<HIR::ImplItem> (lowered));
+      impl_item_ids.push_back (lowered->get_impl_mappings ().get_hirid ());
+    }
+
+  Polarity polarity = impl_block.is_exclam () ? Positive : Negative;
+  HIR::ImplBlock *hir_impl_block = new HIR::ImplBlock (
+    mapping, std::move (impl_items), std::move (generic_params),
+    std::unique_ptr<HIR::Type> (impl_type),
+    std::unique_ptr<HIR::TypePath> (trait_ref), where_clause, polarity, vis,
+    impl_block.get_inner_attrs (), impl_block.get_outer_attrs (),
+    impl_block.get_locus ());
+  translated = hir_impl_block;
+
+  mappings->insert_hir_impl_block (hir_impl_block);
+  for (auto &impl_item_id : impl_item_ids)
+    {
+      mappings->insert_impl_item_mapping (impl_item_id, hir_impl_block);
+    }
+}
+
+void
+ASTLoweringItem::visit (AST::ExternBlock &extern_block)
+{
+  translated = lower_extern_block (extern_block);
+}
+
+HIR::SimplePath
+ASTLoweringSimplePath::translate (const AST::SimplePath &path)
+{
+  ASTLoweringSimplePath resolver;
+
+  return resolver.lower (path);
+}
+
+HIR::SimplePathSegment
+ASTLoweringSimplePath::lower (const AST::SimplePathSegment &segment)
+{
+  auto crate_num = mappings->get_current_crate ();
+  auto node_id = segment.get_node_id ();
+
+  auto mapping = Analysis::NodeMapping (crate_num, node_id,
+					mappings->get_next_hir_id (crate_num),
+					UNKNOWN_LOCAL_DEFID);
+
+  auto hir_seg = HIR::SimplePathSegment (mapping);
+
+  mappings->insert_node_to_hir (node_id, mapping.get_hirid ());
+  // mappings->insert_simple_path_segment (crate_num, node_id, &segment);
+
+  return hir_seg;
+}
+
+HIR::SimplePath
+ASTLoweringSimplePath::lower (const AST::SimplePath &path)
+{
+  auto segments = std::vector<HIR::SimplePathSegment> ();
+  for (auto &segment : path.get_segments ())
+    segments.emplace_back (lower (segment));
+
+  auto crate_num = mappings->get_current_crate ();
+  auto node_id = path.get_node_id ();
+
+  auto mapping = Analysis::NodeMapping (crate_num, node_id,
+					mappings->get_next_hir_id (crate_num),
+					UNKNOWN_LOCAL_DEFID);
+
+  auto lowered
+    = HIR::SimplePath (std::move (segments), mapping, path.get_locus ());
+
+  mappings->insert_node_to_hir (node_id, mapping.get_hirid ());
+  // mappings->insert_simple_path (crate_num, node_id, &path);
+
+  return lowered;
+}
+
+} // namespace HIR
+} // namespace Rust
diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h
new file mode 100644
index 00000000000..5d4ee18f517
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-item.h
@@ -0,0 +1,78 @@
+// 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_AST_LOWER_ITEM
+#define RUST_AST_LOWER_ITEM
+
+#include "rust-diagnostics.h"
+
+#include "rust-ast-lower.h"
+#include "rust-ast-lower-base.h"
+#include "rust-ast-lower-enumitem.h"
+#include "rust-ast-lower-type.h"
+#include "rust-ast-lower-implitem.h"
+#include "rust-ast-lower-stmt.h"
+#include "rust-ast-lower-expr.h"
+#include "rust-ast-lower-pattern.h"
+#include "rust-ast-lower-block.h"
+#include "rust-ast-lower-extern.h"
+#include "rust-hir-full-decls.h"
+
+namespace Rust {
+namespace HIR {
+
+class ASTLoweringItem : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::Item *translate (AST::Item *item);
+
+  void visit (AST::Module &module) override;
+  void visit (AST::TypeAlias &alias) override;
+  void visit (AST::TupleStruct &struct_decl) override;
+  void visit (AST::StructStruct &struct_decl) override;
+  void visit (AST::Enum &enum_decl) override;
+  void visit (AST::Union &union_decl) override;
+  void visit (AST::StaticItem &var) override;
+  void visit (AST::ConstantItem &constant) override;
+  void visit (AST::Function &function) override;
+  void visit (AST::InherentImpl &impl_block) override;
+  void visit (AST::Trait &trait) override;
+  void visit (AST::TraitImpl &impl_block) override;
+  void visit (AST::ExternBlock &extern_block) override;
+
+private:
+  ASTLoweringItem () : translated (nullptr) {}
+
+  HIR::Item *translated;
+};
+
+class ASTLoweringSimplePath : public ASTLoweringBase
+{
+public:
+  static HIR::SimplePath translate (const AST::SimplePath &path);
+
+  HIR::SimplePathSegment lower (const AST::SimplePathSegment &segment);
+  HIR::SimplePath lower (const AST::SimplePath &path);
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_ITEM
diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc b/gcc/rust/hir/rust-ast-lower-pattern.cc
new file mode 100644
index 00000000000..2421ca84651
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-pattern.cc
@@ -0,0 +1,229 @@
+// 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-ast-lower-pattern.h"
+#include "rust-ast-lower-expr.h"
+
+namespace Rust {
+namespace HIR {
+
+void
+ASTLoweringPattern::visit (AST::IdentifierPattern &pattern)
+{
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  std::unique_ptr<Pattern> to_bind;
+  translated
+    = new HIR::IdentifierPattern (mapping, pattern.get_ident (),
+				  pattern.get_locus (), pattern.get_is_ref (),
+				  pattern.get_is_mut () ? Mutability::Mut
+							: Mutability::Imm,
+				  std::move (to_bind));
+}
+
+void
+ASTLoweringPattern::visit (AST::PathInExpression &pattern)
+{
+  translated = ASTLowerPathInExpression::translate (&pattern);
+}
+
+void
+ASTLoweringPattern::visit (AST::TupleStructPattern &pattern)
+{
+  HIR::PathInExpression *path
+    = ASTLowerPathInExpression::translate (&pattern.get_path ());
+
+  TupleStructItems *lowered = nullptr;
+  auto &items = pattern.get_items ();
+  switch (items->get_item_type ())
+    {
+      case AST::TupleStructItems::RANGE: {
+	// TODO
+	gcc_unreachable ();
+      }
+      break;
+
+      case AST::TupleStructItems::NO_RANGE: {
+	AST::TupleStructItemsNoRange &items_no_range
+	  = static_cast<AST::TupleStructItemsNoRange &> (*items.get ());
+
+	std::vector<std::unique_ptr<HIR::Pattern> > patterns;
+	for (auto &inner_pattern : items_no_range.get_patterns ())
+	  {
+	    HIR::Pattern *p
+	      = ASTLoweringPattern::translate (inner_pattern.get ());
+	    patterns.push_back (std::unique_ptr<HIR::Pattern> (p));
+	  }
+
+	lowered = new HIR::TupleStructItemsNoRange (std::move (patterns));
+      }
+      break;
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated = new HIR::TupleStructPattern (
+    mapping, *path, std::unique_ptr<HIR::TupleStructItems> (lowered));
+}
+
+void
+ASTLoweringPattern::visit (AST::StructPattern &pattern)
+{
+  HIR::PathInExpression *path
+    = ASTLowerPathInExpression::translate (&pattern.get_path ());
+
+  auto &raw_elems = pattern.get_struct_pattern_elems ();
+  rust_assert (!raw_elems.has_etc ());
+
+  std::vector<std::unique_ptr<HIR::StructPatternField> > fields;
+  for (auto &field : raw_elems.get_struct_pattern_fields ())
+    {
+      HIR::StructPatternField *f = nullptr;
+      switch (field->get_item_type ())
+	{
+	  case AST::StructPatternField::ItemType::TUPLE_PAT: {
+	    // TODO
+	    gcc_unreachable ();
+	  }
+	  break;
+
+	  case AST::StructPatternField::ItemType::IDENT_PAT: {
+	    // TODO
+	    gcc_unreachable ();
+	  }
+	  break;
+
+	  case AST::StructPatternField::ItemType::IDENT: {
+	    AST::StructPatternFieldIdent &ident
+	      = static_cast<AST::StructPatternFieldIdent &> (*field.get ());
+
+	    auto crate_num = mappings->get_current_crate ();
+	    Analysis::NodeMapping mapping (crate_num, ident.get_node_id (),
+					   mappings->get_next_hir_id (
+					     crate_num),
+					   UNKNOWN_LOCAL_DEFID);
+
+	    f = new HIR::StructPatternFieldIdent (
+	      mapping, ident.get_identifier (), ident.is_ref (),
+	      ident.is_mut () ? Mutability::Mut : Mutability::Imm,
+	      ident.get_outer_attrs (), ident.get_locus ());
+	  }
+	  break;
+	}
+
+      // insert the reverse mappings and locations
+      auto field_id = f->get_mappings ().get_hirid ();
+      auto field_node_id = f->get_mappings ().get_nodeid ();
+      mappings->insert_location (field_id, f->get_locus ());
+      mappings->insert_node_to_hir (field_node_id, field_id);
+
+      // add it to the lowered fields list
+      fields.push_back (std::unique_ptr<HIR::StructPatternField> (f));
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  HIR::StructPatternElements elems (std::move (fields));
+  translated = new HIR::StructPattern (mapping, *path, std::move (elems));
+}
+
+void
+ASTLoweringPattern::visit (AST::WildcardPattern &pattern)
+{
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated = new HIR::WildcardPattern (mapping, pattern.get_locus ());
+}
+
+void
+ASTLoweringPattern::visit (AST::TuplePattern &pattern)
+{
+  std::unique_ptr<HIR::TuplePatternItems> items;
+  switch (pattern.get_items ()->get_pattern_type ())
+    {
+      case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: {
+	AST::TuplePatternItemsMultiple &ref
+	  = *static_cast<AST::TuplePatternItemsMultiple *> (
+	    pattern.get_items ().get ());
+	items = lower_tuple_pattern_multiple (ref);
+      }
+      break;
+
+      case AST::TuplePatternItems::TuplePatternItemType::RANGED: {
+	AST::TuplePatternItemsRanged &ref
+	  = *static_cast<AST::TuplePatternItemsRanged *> (
+	    pattern.get_items ().get ());
+	items = lower_tuple_pattern_ranged (ref);
+      }
+      break;
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated
+    = new HIR::TuplePattern (mapping, std::move (items), pattern.get_locus ());
+}
+
+void
+ASTLoweringPattern::visit (AST::LiteralPattern &pattern)
+{
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  HIR::Literal l = lower_literal (pattern.get_literal ());
+  translated
+    = new HIR::LiteralPattern (mapping, std::move (l), pattern.get_locus ());
+}
+
+void
+ASTLoweringPattern::visit (AST::RangePattern &pattern)
+{
+  auto upper_bound
+    = lower_range_pattern_bound (pattern.get_upper_bound ().get ());
+  auto lower_bound
+    = lower_range_pattern_bound (pattern.get_lower_bound ().get ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated
+    = new HIR::RangePattern (mapping, std::move (lower_bound),
+			     std::move (upper_bound), pattern.get_locus ());
+}
+
+} // namespace HIR
+} // namespace Rust
diff --git a/gcc/rust/hir/rust-ast-lower-pattern.h b/gcc/rust/hir/rust-ast-lower-pattern.h
new file mode 100644
index 00000000000..aab99f602d5
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-pattern.h
@@ -0,0 +1,72 @@
+// 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_AST_LOWER_PATTERN
+#define RUST_AST_LOWER_PATTERN
+
+#include "rust-ast-lower-base.h"
+
+namespace Rust {
+namespace HIR {
+
+class ASTLoweringPattern : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::Pattern *translate (AST::Pattern *pattern)
+  {
+    ASTLoweringPattern resolver;
+    pattern->accept_vis (resolver);
+
+    rust_assert (resolver.translated != nullptr);
+
+    resolver.mappings->insert_hir_pattern (resolver.translated);
+    resolver.mappings->insert_location (
+      resolver.translated->get_pattern_mappings ().get_hirid (),
+      pattern->get_locus ());
+
+    return resolver.translated;
+  }
+
+  void visit (AST::IdentifierPattern &pattern) override;
+
+  void visit (AST::PathInExpression &pattern) override;
+
+  void visit (AST::StructPattern &pattern) override;
+
+  void visit (AST::TupleStructPattern &pattern) override;
+
+  void visit (AST::WildcardPattern &pattern) override;
+
+  void visit (AST::TuplePattern &pattern) override;
+
+  void visit (AST::LiteralPattern &pattern) override;
+
+  void visit (AST::RangePattern &pattern) override;
+
+private:
+  ASTLoweringPattern () : translated (nullptr) {}
+
+  HIR::Pattern *translated;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_PATTERN
diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h
new file mode 100644
index 00000000000..2b26ae3835c
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-stmt.h
@@ -0,0 +1,418 @@
+// 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_AST_LOWER_STMT
+#define RUST_AST_LOWER_STMT
+
+#include "rust-diagnostics.h"
+
+#include "rust-ast-lower-base.h"
+#include "rust-ast-lower-enumitem.h"
+#include "rust-ast-lower-type.h"
+#include "rust-ast-lower-block.h"
+#include "rust-ast-lower-expr.h"
+#include "rust-ast-lower-pattern.h"
+
+namespace Rust {
+namespace HIR {
+
+class ASTLoweringStmt : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::Stmt *translate (AST::Stmt *stmt, bool *terminated)
+  {
+    ASTLoweringStmt resolver;
+    stmt->accept_vis (resolver);
+
+    rust_assert (resolver.translated != nullptr);
+    *terminated = resolver.terminated;
+    resolver.mappings->insert_location (
+      resolver.translated->get_mappings ().get_hirid (),
+      resolver.translated->get_locus ());
+    resolver.mappings->insert_hir_stmt (resolver.translated);
+    if (resolver.translated->is_item ())
+      {
+	HIR::Item *i = static_cast<HIR::Item *> (resolver.translated);
+
+	auto defid = resolver.translated->get_mappings ().get_defid ();
+
+	resolver.handle_outer_attributes (*i);
+	resolver.mappings->insert_hir_item (i);
+	resolver.mappings->insert_defid_mapping (defid, i);
+      }
+
+    return resolver.translated;
+  }
+
+  void visit (AST::ExprStmtWithBlock &stmt) override
+  {
+    HIR::ExprWithBlock *expr
+      = ASTLoweringExprWithBlock::translate (stmt.get_expr ().get (),
+					     &terminated);
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, stmt.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+    translated
+      = new HIR::ExprStmtWithBlock (mapping,
+				    std::unique_ptr<HIR::ExprWithBlock> (expr),
+				    stmt.get_locus (),
+				    !stmt.is_semicolon_followed ());
+  }
+
+  void visit (AST::ExprStmtWithoutBlock &stmt) override
+  {
+    HIR::Expr *expr
+      = ASTLoweringExpr::translate (stmt.get_expr ().get (), &terminated);
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, stmt.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+    translated
+      = new HIR::ExprStmtWithoutBlock (mapping,
+				       std::unique_ptr<HIR::Expr> (expr),
+				       stmt.get_locus ());
+  }
+
+  void visit (AST::ConstantItem &constant) override
+  {
+    HIR::Visibility vis = translate_visibility (constant.get_visibility ());
+
+    HIR::Type *type = ASTLoweringType::translate (constant.get_type ().get ());
+    HIR::Expr *expr = ASTLoweringExpr::translate (constant.get_expr ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, constant.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::ConstantItem (mapping, constant.get_identifier (),
+					vis, std::unique_ptr<HIR::Type> (type),
+					std::unique_ptr<HIR::Expr> (expr),
+					constant.get_outer_attrs (),
+					constant.get_locus ());
+  }
+
+  void visit (AST::LetStmt &stmt) override
+  {
+    HIR::Pattern *variables
+      = ASTLoweringPattern::translate (stmt.get_pattern ().get ());
+    HIR::Type *type = stmt.has_type ()
+			? ASTLoweringType::translate (stmt.get_type ().get ())
+			: nullptr;
+    HIR::Expr *init_expression
+      = stmt.has_init_expr ()
+	  ? ASTLoweringExpr::translate (stmt.get_init_expr ().get ())
+	  : nullptr;
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, stmt.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+    translated
+      = new HIR::LetStmt (mapping, std::unique_ptr<HIR::Pattern> (variables),
+			  std::unique_ptr<HIR::Expr> (init_expression),
+			  std::unique_ptr<HIR::Type> (type),
+			  stmt.get_outer_attrs (), stmt.get_locus ());
+  }
+
+  void visit (AST::TupleStruct &struct_decl) override
+  {
+    std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+    if (struct_decl.has_generics ())
+      {
+	generic_params
+	  = lower_generic_params (struct_decl.get_generic_params ());
+      }
+
+    std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::Visibility vis = translate_visibility (struct_decl.get_visibility ());
+
+    std::vector<HIR::TupleField> fields;
+    for (AST::TupleField &field : struct_decl.get_fields ())
+      {
+	HIR::Visibility vis = translate_visibility (field.get_visibility ());
+	HIR::Type *type
+	  = ASTLoweringType::translate (field.get_field_type ().get ());
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping mapping (crate_num, field.get_node_id (),
+				       mappings->get_next_hir_id (crate_num),
+				       mappings->get_next_localdef_id (
+					 crate_num));
+
+	HIR::TupleField translated_field (mapping,
+					  std::unique_ptr<HIR::Type> (type),
+					  vis, field.get_locus (),
+					  field.get_outer_attrs ());
+	fields.push_back (std::move (translated_field));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, struct_decl.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::TupleStruct (mapping, std::move (fields),
+				       struct_decl.get_identifier (),
+				       std::move (generic_params),
+				       std::move (where_clause), vis,
+				       struct_decl.get_outer_attrs (),
+				       struct_decl.get_locus ());
+  }
+
+  void visit (AST::StructStruct &struct_decl) override
+  {
+    std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+    if (struct_decl.has_generics ())
+      {
+	generic_params
+	  = lower_generic_params (struct_decl.get_generic_params ());
+      }
+
+    std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::Visibility vis = translate_visibility (struct_decl.get_visibility ());
+
+    bool is_unit = struct_decl.is_unit_struct ();
+    std::vector<HIR::StructField> fields;
+    for (AST::StructField &field : struct_decl.get_fields ())
+      {
+	HIR::Visibility vis = translate_visibility (field.get_visibility ());
+	HIR::Type *type
+	  = ASTLoweringType::translate (field.get_field_type ().get ());
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping mapping (crate_num, field.get_node_id (),
+				       mappings->get_next_hir_id (crate_num),
+				       mappings->get_next_localdef_id (
+					 crate_num));
+
+	HIR::StructField translated_field (mapping, field.get_field_name (),
+					   std::unique_ptr<HIR::Type> (type),
+					   vis, field.get_locus (),
+					   field.get_outer_attrs ());
+
+	if (struct_field_name_exists (fields, translated_field))
+	  break;
+
+	fields.push_back (std::move (translated_field));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, struct_decl.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::StructStruct (mapping, std::move (fields),
+					struct_decl.get_identifier (),
+					std::move (generic_params),
+					std::move (where_clause), is_unit, vis,
+					struct_decl.get_outer_attrs (),
+					struct_decl.get_locus ());
+  }
+
+  void visit (AST::Union &union_decl) override
+  {
+    std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+    if (union_decl.has_generics ())
+      {
+	generic_params
+	  = lower_generic_params (union_decl.get_generic_params ());
+      }
+
+    std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::Visibility vis = translate_visibility (union_decl.get_visibility ());
+
+    std::vector<HIR::StructField> variants;
+    for (AST::StructField &variant : union_decl.get_variants ())
+      {
+	HIR::Visibility vis = translate_visibility (variant.get_visibility ());
+	HIR::Type *type
+	  = ASTLoweringType::translate (variant.get_field_type ().get ());
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping mapping (crate_num, variant.get_node_id (),
+				       mappings->get_next_hir_id (crate_num),
+				       mappings->get_next_localdef_id (
+					 crate_num));
+
+	HIR::StructField translated_variant (mapping, variant.get_field_name (),
+					     std::unique_ptr<HIR::Type> (type),
+					     vis, variant.get_locus (),
+					     variant.get_outer_attrs ());
+
+	if (struct_field_name_exists (variants, translated_variant))
+	  break;
+
+	variants.push_back (std::move (translated_variant));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, union_decl.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated
+      = new HIR::Union (mapping, union_decl.get_identifier (), vis,
+			std::move (generic_params), std::move (where_clause),
+			std::move (variants), union_decl.get_outer_attrs (),
+			union_decl.get_locus ());
+  }
+
+  void visit (AST::Enum &enum_decl) override
+  {
+    std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+    if (enum_decl.has_generics ())
+      {
+	generic_params = lower_generic_params (enum_decl.get_generic_params ());
+      }
+
+    std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::Visibility vis = translate_visibility (enum_decl.get_visibility ());
+
+    // bool is_unit = enum_decl.is_zero_variant ();
+    std::vector<std::unique_ptr<HIR::EnumItem>> items;
+    for (auto &variant : enum_decl.get_variants ())
+      {
+	HIR::EnumItem *hir_item
+	  = ASTLoweringEnumItem::translate (variant.get ());
+	items.push_back (std::unique_ptr<HIR::EnumItem> (hir_item));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, enum_decl.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::Enum (mapping, enum_decl.get_identifier (), vis,
+				std::move (generic_params),
+				std::move (where_clause), /* is_unit, */
+				std::move (items), enum_decl.get_outer_attrs (),
+				enum_decl.get_locus ());
+  }
+
+  void visit (AST::EmptyStmt &empty) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, empty.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::EmptyStmt (mapping, empty.get_locus ());
+  }
+
+  void visit (AST::Function &function) override
+  {
+    // ignore for now and leave empty
+    std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+    HIR::WhereClause where_clause (std::move (where_clause_items));
+    HIR::FunctionQualifiers qualifiers
+      = lower_qualifiers (function.get_qualifiers ());
+    HIR::Visibility vis = translate_visibility (function.get_visibility ());
+
+    // need
+    std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+    if (function.has_generics ())
+      {
+	generic_params = lower_generic_params (function.get_generic_params ());
+      }
+
+    Identifier function_name = function.get_function_name ();
+    Location locus = function.get_locus ();
+
+    std::unique_ptr<HIR::Type> return_type
+      = function.has_return_type () ? std::unique_ptr<HIR::Type> (
+	  ASTLoweringType::translate (function.get_return_type ().get ()))
+				    : nullptr;
+
+    std::vector<HIR::FunctionParam> function_params;
+    for (auto &param : function.get_function_params ())
+      {
+	auto translated_pattern = std::unique_ptr<HIR::Pattern> (
+	  ASTLoweringPattern::translate (param.get_pattern ().get ()));
+	auto translated_type = std::unique_ptr<HIR::Type> (
+	  ASTLoweringType::translate (param.get_type ().get ()));
+
+	auto crate_num = mappings->get_current_crate ();
+	Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+				       mappings->get_next_hir_id (crate_num),
+				       UNKNOWN_LOCAL_DEFID);
+
+	auto hir_param
+	  = HIR::FunctionParam (mapping, std::move (translated_pattern),
+				std::move (translated_type),
+				param.get_locus ());
+	function_params.push_back (hir_param);
+      }
+
+    bool terminated = false;
+    std::unique_ptr<HIR::BlockExpr> function_body
+      = std::unique_ptr<HIR::BlockExpr> (
+	ASTLoweringBlock::translate (function.get_definition ().get (),
+				     &terminated));
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, function.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    mappings->insert_location (function_body->get_mappings ().get_hirid (),
+			       function.get_locus ());
+
+    auto fn
+      = new HIR::Function (mapping, std::move (function_name),
+			   std::move (qualifiers), std::move (generic_params),
+			   std::move (function_params), std::move (return_type),
+			   std::move (where_clause), std::move (function_body),
+			   std::move (vis), function.get_outer_attrs (),
+			   HIR::SelfParam::error (), locus);
+
+    // add the mappings for the function params at the end
+    for (auto &param : fn->get_function_params ())
+      {
+	mappings->insert_hir_param (&param);
+	mappings->insert_location (mapping.get_hirid (), param.get_locus ());
+      }
+
+    translated = fn;
+  }
+
+  void visit (AST::ExternBlock &extern_block) override
+  {
+    translated = lower_extern_block (extern_block);
+  }
+
+private:
+  ASTLoweringStmt () : translated (nullptr), terminated (false) {}
+
+  HIR::Stmt *translated;
+  bool terminated;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_PATTERN
diff --git a/gcc/rust/hir/rust-ast-lower-struct-field-expr.h b/gcc/rust/hir/rust-ast-lower-struct-field-expr.h
new file mode 100644
index 00000000000..dadf3594904
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-struct-field-expr.h
@@ -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/>.
+
+#ifndef RUST_AST_LOWER_STRUCT_FIELD_EXPR
+#define RUST_AST_LOWER_STRUCT_FIELD_EXPR
+
+#include "rust-diagnostics.h"
+#include "rust-ast-lower-base.h"
+
+namespace Rust {
+namespace HIR {
+
+class ASTLowerStructExprField : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::StructExprField *translate (AST::StructExprField *field)
+  {
+    ASTLowerStructExprField compiler;
+    field->accept_vis (compiler);
+    rust_assert (compiler.translated != nullptr);
+
+    compiler.mappings->insert_hir_struct_field (compiler.translated);
+    compiler.mappings->insert_location (
+      compiler.translated->get_mappings ().get_hirid (), field->get_locus ());
+
+    return compiler.translated;
+  }
+
+  ~ASTLowerStructExprField () {}
+
+  void visit (AST::StructExprFieldIdentifierValue &field) override;
+
+  void visit (AST::StructExprFieldIndexValue &field) override;
+
+  void visit (AST::StructExprFieldIdentifier &field) override;
+
+private:
+  ASTLowerStructExprField () : translated (nullptr) {}
+
+  HIR::StructExprField *translated;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_STRUCT_FIELD_EXPR
diff --git a/gcc/rust/hir/rust-ast-lower-type.h b/gcc/rust/hir/rust-ast-lower-type.h
new file mode 100644
index 00000000000..46f765a3ea2
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-type.h
@@ -0,0 +1,532 @@
+// 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_AST_LOWER_TYPE
+#define RUST_AST_LOWER_TYPE
+
+#include "rust-ast-lower-base.h"
+#include "rust-diagnostics.h"
+#include "rust-ast-lower-expr.h"
+
+namespace Rust {
+namespace HIR {
+
+class ASTLowerTypePath : public ASTLoweringBase
+{
+protected:
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::TypePath *translate (AST::TypePath &type)
+  {
+    ASTLowerTypePath resolver;
+    type.accept_vis (resolver);
+    rust_assert (resolver.translated != nullptr);
+    return resolver.translated;
+  }
+
+  void visit (AST::TypePathSegmentFunction &) override { gcc_unreachable (); }
+
+  void visit (AST::TypePathSegment &segment) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    auto hirid = mappings->get_next_hir_id (crate_num);
+    Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid,
+				   UNKNOWN_LOCAL_DEFID);
+
+    HIR::PathIdentSegment ident (segment.get_ident_segment ().as_string ());
+    translated_segment
+      = new HIR::TypePathSegment (std::move (mapping), ident,
+				  segment.get_separating_scope_resolution (),
+				  segment.get_locus ());
+  }
+
+  void visit (AST::TypePathSegmentGeneric &segment) override;
+
+  void visit (AST::TypePath &path) override
+  {
+    std::vector<std::unique_ptr<HIR::TypePathSegment>> translated_segments;
+
+    for (auto &seg : path.get_segments ())
+      {
+	translated_segment = nullptr;
+	seg->accept_vis (*this);
+	if (translated_segment == nullptr)
+	  {
+	    rust_fatal_error (seg->get_locus (),
+			      "failed to translate AST TypePathSegment");
+	  }
+	translated_segments.push_back (
+	  std::unique_ptr<HIR::TypePathSegment> (translated_segment));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    auto hirid = mappings->get_next_hir_id (crate_num);
+    Analysis::NodeMapping mapping (crate_num, path.get_node_id (), hirid,
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated
+      = new HIR::TypePath (std::move (mapping), std::move (translated_segments),
+			   path.get_locus (),
+			   path.has_opening_scope_resolution_op ());
+  }
+
+protected:
+  HIR::TypePathSegment *translated_segment;
+
+private:
+  HIR::TypePath *translated;
+};
+
+class ASTLowerQualifiedPathInType : public ASTLowerTypePath
+{
+  using ASTLowerTypePath::visit;
+
+public:
+  static HIR::QualifiedPathInType *translate (AST::QualifiedPathInType &type)
+  {
+    ASTLowerQualifiedPathInType resolver;
+    type.accept_vis (resolver);
+    rust_assert (resolver.translated != nullptr);
+    return resolver.translated;
+  }
+
+  void visit (AST::QualifiedPathInType &path) override;
+
+private:
+  HIR::QualifiedPathInType *translated;
+};
+
+class ASTLoweringType : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::Type *translate (AST::Type *type)
+  {
+    ASTLoweringType resolver;
+    type->accept_vis (resolver);
+
+    rust_assert (resolver.translated != nullptr);
+    resolver.mappings->insert_hir_type (resolver.translated);
+    resolver.mappings->insert_location (
+      resolver.translated->get_mappings ().get_hirid (),
+      resolver.translated->get_locus ());
+
+    return resolver.translated;
+  }
+
+  void visit (AST::BareFunctionType &fntype) override
+  {
+    bool is_variadic = false;
+    std::vector<HIR::LifetimeParam> lifetime_params;
+    HIR::FunctionQualifiers qualifiers
+      = lower_qualifiers (fntype.get_function_qualifiers ());
+
+    std::vector<HIR::MaybeNamedParam> named_params;
+    for (auto &param : fntype.get_function_params ())
+      {
+	HIR::MaybeNamedParam::ParamKind kind;
+	switch (param.get_param_kind ())
+	  {
+	  case AST::MaybeNamedParam::ParamKind::UNNAMED:
+	    kind = HIR::MaybeNamedParam::ParamKind::UNNAMED;
+	    break;
+	  case AST::MaybeNamedParam::ParamKind::IDENTIFIER:
+	    kind = HIR::MaybeNamedParam::ParamKind::IDENTIFIER;
+	    break;
+	  case AST::MaybeNamedParam::ParamKind::WILDCARD:
+	    kind = HIR::MaybeNamedParam::ParamKind::WILDCARD;
+	    break;
+	  default:
+	    gcc_unreachable ();
+	  }
+
+	HIR::Type *param_type
+	  = ASTLoweringType::translate (param.get_type ().get ());
+
+	HIR::MaybeNamedParam p (param.get_name (), kind,
+				std::unique_ptr<HIR::Type> (param_type),
+				param.get_locus ());
+	named_params.push_back (std::move (p));
+      }
+
+    HIR::Type *return_type = nullptr;
+    if (fntype.has_return_type ())
+      {
+	return_type
+	  = ASTLoweringType::translate (fntype.get_return_type ().get ());
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, fntype.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::BareFunctionType (
+      std::move (mapping), std::move (lifetime_params), std::move (qualifiers),
+      std::move (named_params), is_variadic,
+      std::unique_ptr<HIR::Type> (return_type), fntype.get_locus ());
+  }
+
+  void visit (AST::TupleType &tuple) override
+  {
+    std::vector<std::unique_ptr<HIR::Type>> elems;
+    for (auto &e : tuple.get_elems ())
+      {
+	HIR::Type *t = ASTLoweringType::translate (e.get ());
+	elems.push_back (std::unique_ptr<HIR::Type> (t));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, tuple.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::TupleType (std::move (mapping), std::move (elems),
+				     tuple.get_locus ());
+  }
+
+  void visit (AST::TypePath &path) override
+  {
+    translated = ASTLowerTypePath::translate (path);
+  }
+
+  void visit (AST::QualifiedPathInType &path) override
+  {
+    translated = ASTLowerQualifiedPathInType::translate (path);
+  }
+
+  void visit (AST::ArrayType &type) override
+  {
+    HIR::Type *translated_type
+      = ASTLoweringType::translate (type.get_elem_type ().get ());
+    HIR::Expr *array_size
+      = ASTLoweringExpr::translate (type.get_size_expr ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated
+      = new HIR::ArrayType (mapping,
+			    std::unique_ptr<HIR::Type> (translated_type),
+			    std::unique_ptr<HIR::Expr> (array_size),
+			    type.get_locus ());
+  }
+
+  void visit (AST::ReferenceType &type) override
+  {
+    HIR::Lifetime lifetime = lower_lifetime (type.get_lifetime ());
+
+    HIR::Type *base_type
+      = ASTLoweringType::translate (type.get_base_type ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::ReferenceType (mapping,
+					 type.get_has_mut () ? Mutability::Mut
+							     : Mutability::Imm,
+					 std::unique_ptr<HIR::Type> (base_type),
+					 type.get_locus (), lifetime);
+  }
+
+  void visit (AST::RawPointerType &type) override
+  {
+    HIR::Type *base_type
+      = ASTLoweringType::translate (type.get_type_pointed_to ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated
+      = new HIR::RawPointerType (mapping,
+				 type.get_pointer_type ()
+				     == AST::RawPointerType::PointerType::MUT
+				   ? Mutability::Mut
+				   : Mutability::Imm,
+				 std::unique_ptr<HIR::Type> (base_type),
+				 type.get_locus ());
+  }
+
+  void visit (AST::SliceType &type) override
+  {
+    HIR::Type *base_type
+      = ASTLoweringType::translate (type.get_elem_type ().get ());
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated
+      = new HIR::SliceType (mapping, std::unique_ptr<HIR::Type> (base_type),
+			    type.get_locus ());
+  }
+
+  void visit (AST::InferredType &type) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::InferredType (mapping, type.get_locus ());
+  }
+
+  void visit (AST::NeverType &type) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated = new HIR::NeverType (mapping, type.get_locus ());
+  }
+
+  void visit (AST::TraitObjectTypeOneBound &type) override;
+
+  void visit (AST::TraitObjectType &type) override;
+
+private:
+  ASTLoweringType () : ASTLoweringBase (), translated (nullptr) {}
+
+  HIR::Type *translated;
+};
+
+class ASTLowerGenericParam : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::GenericParam *translate (AST::GenericParam *param)
+  {
+    ASTLowerGenericParam resolver;
+    param->accept_vis (resolver);
+
+    rust_assert (resolver.translated != nullptr);
+    resolver.mappings->insert_location (
+      resolver.translated->get_mappings ().get_hirid (), param->get_locus ());
+    resolver.mappings->insert_hir_generic_param (resolver.translated);
+
+    return resolver.translated;
+  }
+
+  void visit (AST::LifetimeParam &param) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    HIR::Lifetime lt (mapping, param.get_lifetime ().get_lifetime_type (),
+		      param.get_lifetime ().get_lifetime_name (),
+		      param.get_lifetime ().get_locus ());
+
+    translated = new HIR::LifetimeParam (mapping, lt, param.get_locus (),
+					 std::vector<Lifetime> ());
+  }
+
+  void visit (AST::ConstGenericParam &param) override
+  {
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    auto type = ASTLoweringType::translate (param.get_type ().get ());
+
+    HIR::Expr *default_expr = nullptr;
+    if (param.has_default_value ())
+      default_expr = ASTLoweringExpr::translate (
+	param.get_default_value ().get_expression ().get ());
+
+    translated
+      = new HIR::ConstGenericParam (param.get_name (),
+				    std::unique_ptr<Type> (type),
+				    std::unique_ptr<Expr> (default_expr),
+				    mapping, param.get_locus ());
+  }
+
+  void visit (AST::TypeParam &param) override
+  {
+    AST::Attribute outer_attr = AST::Attribute::create_empty ();
+    std::vector<std::unique_ptr<HIR::TypeParamBound>> type_param_bounds;
+    if (param.has_type_param_bounds ())
+      {
+	for (auto &bound : param.get_type_param_bounds ())
+	  {
+	    HIR::TypeParamBound *lowered_bound = lower_bound (bound.get ());
+	    type_param_bounds.push_back (
+	      std::unique_ptr<HIR::TypeParamBound> (lowered_bound));
+	  }
+      }
+
+    HIR::Type *type = param.has_type ()
+			? ASTLoweringType::translate (param.get_type ().get ())
+			: nullptr;
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   mappings->get_next_localdef_id (crate_num));
+
+    translated
+      = new HIR::TypeParam (mapping, param.get_type_representation (),
+			    param.get_locus (), std::move (type_param_bounds),
+			    std::unique_ptr<Type> (type),
+			    std::move (outer_attr));
+  }
+
+private:
+  ASTLowerGenericParam () : ASTLoweringBase (), translated (nullptr) {}
+
+  HIR::GenericParam *translated;
+};
+
+class ASTLoweringTypeBounds : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::TypeParamBound *translate (AST::TypeParamBound *type)
+  {
+    ASTLoweringTypeBounds resolver;
+    type->accept_vis (resolver);
+
+    rust_assert (resolver.translated != nullptr);
+    resolver.mappings->insert_location (
+      resolver.translated->get_mappings ().get_hirid (),
+      resolver.translated->get_locus ());
+
+    return resolver.translated;
+  }
+
+  void visit (AST::TraitBound &bound) override
+  {
+    // FIXME
+    std::vector<HIR::LifetimeParam> lifetimes;
+
+    AST::TypePath &ast_trait_path = bound.get_type_path ();
+    HIR::TypePath *trait_path = ASTLowerTypePath::translate (ast_trait_path);
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, bound.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::TraitBound (mapping, *trait_path, bound.get_locus (),
+				      bound.is_in_parens (),
+				      bound.has_opening_question_mark ());
+  }
+
+  void visit (AST::Lifetime &bound) override
+  {
+    HIR::Lifetime lifetime = lower_lifetime (bound);
+    translated = new HIR::Lifetime (lifetime);
+  }
+
+private:
+  ASTLoweringTypeBounds () : ASTLoweringBase (), translated (nullptr) {}
+
+  HIR::TypeParamBound *translated;
+};
+
+class ASTLowerWhereClauseItem : public ASTLoweringBase
+{
+  using Rust::HIR::ASTLoweringBase::visit;
+
+public:
+  static HIR::WhereClauseItem *translate (AST::WhereClauseItem &item)
+  {
+    ASTLowerWhereClauseItem compiler;
+    item.accept_vis (compiler);
+
+    rust_assert (compiler.translated != nullptr);
+    // FIXME
+    // compiler.mappings->insert_location (
+    //   compiler.translated->get_mappings ().get_hirid (),
+    //   compiler.translated->get_locus ());
+
+    return compiler.translated;
+  }
+
+  void visit (AST::LifetimeWhereClauseItem &item) override
+  {
+    HIR::Lifetime l = lower_lifetime (item.get_lifetime ());
+    std::vector<HIR::Lifetime> lifetime_bounds;
+    for (auto &lifetime_bound : item.get_lifetime_bounds ())
+      {
+	HIR::Lifetime ll = lower_lifetime (lifetime_bound);
+	lifetime_bounds.push_back (std::move (ll));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, item.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated = new HIR::LifetimeWhereClauseItem (mapping, std::move (l),
+						   std::move (lifetime_bounds),
+						   item.get_locus ());
+  }
+
+  void visit (AST::TypeBoundWhereClauseItem &item) override
+  {
+    // FIXME
+    std::vector<HIR::LifetimeParam> for_lifetimes;
+
+    std::unique_ptr<HIR::Type> bound_type = std::unique_ptr<HIR::Type> (
+      ASTLoweringType::translate (item.get_type ().get ()));
+
+    std::vector<std::unique_ptr<HIR::TypeParamBound>> type_param_bounds;
+    for (auto &bound : item.get_type_param_bounds ())
+      {
+	HIR::TypeParamBound *b
+	  = ASTLoweringTypeBounds::translate (bound.get ());
+	type_param_bounds.push_back (std::unique_ptr<HIR::TypeParamBound> (b));
+      }
+
+    auto crate_num = mappings->get_current_crate ();
+    Analysis::NodeMapping mapping (crate_num, item.get_node_id (),
+				   mappings->get_next_hir_id (crate_num),
+				   UNKNOWN_LOCAL_DEFID);
+
+    translated
+      = new HIR::TypeBoundWhereClauseItem (mapping, std::move (for_lifetimes),
+					   std::move (bound_type),
+					   std::move (type_param_bounds),
+					   item.get_locus ());
+  }
+
+private:
+  ASTLowerWhereClauseItem () : ASTLoweringBase (), translated (nullptr) {}
+
+  HIR::WhereClauseItem *translated;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_AST_LOWER_TYPE
diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc
new file mode 100644
index 00000000000..0bec8b088af
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower.cc
@@ -0,0 +1,477 @@
+// 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-ast-lower.h"
+#include "rust-ast-lower-item.h"
+#include "rust-ast-lower-implitem.h"
+#include "rust-ast-lower-expr.h"
+#include "rust-ast-lower-block.h"
+#include "rust-ast-lower-type.h"
+
+namespace Rust {
+namespace HIR {
+
+Visibility
+translate_visibility (const AST::Visibility &vis)
+{
+  // FIXME: How do we create a private visibility here? Is it always private if
+  // the AST vis is an error?
+  // FIXME: We need to add a `create_private()` static function to the
+  // AST::Visibility class and use it when the vis is empty in the parser...
+  if (vis.is_error ())
+    return Visibility::create_error ();
+
+  switch (vis.get_public_vis_type ())
+    {
+    case AST::Visibility::PUB:
+      return Visibility (Visibility::VisType::PUBLIC);
+    case AST::Visibility::PRIV:
+    case AST::Visibility::PUB_SELF:
+      return Visibility (Visibility::VisType::PRIVATE);
+    case AST::Visibility::PUB_CRATE:
+    case AST::Visibility::PUB_SUPER:
+    case AST::Visibility::PUB_IN_PATH:
+      return Visibility (Visibility::VisType::RESTRICTED,
+			 ASTLoweringSimplePath::translate (vis.get_path ()));
+      break;
+    }
+
+  return Visibility::create_error ();
+}
+
+ASTLowering::ASTLowering (AST::Crate &astCrate) : astCrate (astCrate) {}
+
+ASTLowering::~ASTLowering () {}
+
+std::unique_ptr<HIR::Crate>
+ASTLowering::Resolve (AST::Crate &astCrate)
+{
+  ASTLowering resolver (astCrate);
+  return resolver.go ();
+}
+
+std::unique_ptr<HIR::Crate>
+ASTLowering::go ()
+{
+  std::vector<std::unique_ptr<HIR::Item> > items;
+
+  for (auto it = astCrate.items.begin (); it != astCrate.items.end (); it++)
+    {
+      auto translated = ASTLoweringItem::translate (it->get ());
+      if (translated != nullptr)
+	items.push_back (std::unique_ptr<HIR::Item> (translated));
+    }
+
+  auto mappings = Analysis::Mappings::get ();
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, astCrate.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  return std::unique_ptr<HIR::Crate> (
+    new HIR::Crate (std::move (items), astCrate.get_inner_attrs (), mapping));
+}
+
+// rust-ast-lower-block.h
+void
+ASTLoweringBlock::visit (AST::BlockExpr &expr)
+{
+  std::vector<std::unique_ptr<HIR::Stmt> > block_stmts;
+  bool block_did_terminate = false;
+
+  for (auto &s : expr.get_statements ())
+    {
+      if (s->get_ast_kind () == AST::Kind::MACRO_RULES_DEFINITION)
+	continue;
+
+      if (s->get_ast_kind () == AST::Kind::MACRO_INVOCATION)
+	rust_fatal_error (
+	  s->get_locus (),
+	  "macro invocations should not get lowered to HIR - At "
+	  "this point in "
+	  "the pipeline, they should all have been expanded");
+
+      if (block_did_terminate)
+	rust_warning_at (s->get_locus (), 0, "unreachable statement");
+
+      bool terminated = false;
+      auto translated_stmt = ASTLoweringStmt::translate (s.get (), &terminated);
+      block_stmts.push_back (std::unique_ptr<HIR::Stmt> (translated_stmt));
+      block_did_terminate |= terminated;
+    }
+
+  if (expr.has_tail_expr () && block_did_terminate)
+    {
+      // warning unreachable tail expressions
+      rust_warning_at (expr.get_tail_expr ()->get_locus (), 0,
+		       "unreachable expression");
+    }
+
+  HIR::ExprWithoutBlock *tail_expr = nullptr;
+  if (expr.has_tail_expr ())
+    {
+      bool terminated = false;
+      tail_expr = (HIR::ExprWithoutBlock *)
+	ASTLoweringExpr::translate (expr.get_tail_expr ().get (), &terminated);
+      block_did_terminate |= terminated;
+    }
+
+  bool tail_reachable = !block_did_terminate;
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+  translated
+    = new HIR::BlockExpr (mapping, std::move (block_stmts),
+			  std::unique_ptr<HIR::ExprWithoutBlock> (tail_expr),
+			  tail_reachable, expr.get_inner_attrs (),
+			  expr.get_outer_attrs (), expr.get_start_locus (),
+			  expr.get_end_locus ());
+
+  terminated = block_did_terminate;
+}
+
+void
+ASTLoweringIfBlock::visit (AST::IfExpr &expr)
+{
+  bool ignored_terminated = false;
+  HIR::Expr *condition
+    = ASTLoweringExpr::translate (expr.get_condition_expr ().get (),
+				  &ignored_terminated);
+  HIR::BlockExpr *block
+    = ASTLoweringBlock::translate (expr.get_if_block ().get (),
+				   &ignored_terminated);
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated = new HIR::IfExpr (mapping, std::unique_ptr<HIR::Expr> (condition),
+				std::unique_ptr<HIR::BlockExpr> (block),
+				expr.get_locus ());
+}
+
+void
+ASTLoweringIfBlock::visit (AST::IfExprConseqElse &expr)
+{
+  HIR::Expr *condition
+    = ASTLoweringExpr::translate (expr.get_condition_expr ().get ());
+
+  bool if_block_terminated = false;
+  bool else_block_termianted = false;
+
+  HIR::BlockExpr *if_block
+    = ASTLoweringBlock::translate (expr.get_if_block ().get (),
+				   &if_block_terminated);
+  HIR::BlockExpr *else_block
+    = ASTLoweringBlock::translate (expr.get_else_block ().get (),
+				   &else_block_termianted);
+
+  terminated = if_block_terminated && else_block_termianted;
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated
+    = new HIR::IfExprConseqElse (mapping,
+				 std::unique_ptr<HIR::Expr> (condition),
+				 std::unique_ptr<HIR::BlockExpr> (if_block),
+				 std::unique_ptr<HIR::BlockExpr> (else_block),
+				 expr.get_locus ());
+}
+
+void
+ASTLoweringIfBlock::visit (AST::IfExprConseqIf &expr)
+{
+  HIR::Expr *condition
+    = ASTLoweringExpr::translate (expr.get_condition_expr ().get ());
+
+  bool ignored_terminated = false;
+  HIR::BlockExpr *block
+    = ASTLoweringBlock::translate (expr.get_if_block ().get (),
+				   &ignored_terminated);
+  HIR::IfExpr *conseq_if_expr
+    = ASTLoweringIfBlock::translate (expr.get_conseq_if_expr ().get (),
+				     &ignored_terminated);
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated
+    = new HIR::IfExprConseqIf (mapping, std::unique_ptr<HIR::Expr> (condition),
+			       std::unique_ptr<HIR::BlockExpr> (block),
+			       std::unique_ptr<HIR::IfExpr> (conseq_if_expr),
+			       expr.get_locus ());
+}
+
+void
+ASTLoweringIfLetBlock::visit (AST::IfLetExpr &expr)
+{
+  std::vector<std::unique_ptr<HIR::Pattern> > patterns;
+  for (auto &pattern : expr.get_patterns ())
+    {
+      HIR::Pattern *ptrn = ASTLoweringPattern::translate (pattern.get ());
+      patterns.push_back (std::unique_ptr<HIR::Pattern> (ptrn));
+    }
+  HIR::Expr *value_ptr
+    = ASTLoweringExpr::translate (expr.get_value_expr ().get ());
+
+  bool ignored_terminated = false;
+  HIR::BlockExpr *block
+    = ASTLoweringBlock::translate (expr.get_if_block ().get (),
+				   &ignored_terminated);
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated = new HIR::IfLetExpr (mapping, std::move (patterns),
+				   std::unique_ptr<HIR::Expr> (value_ptr),
+				   std::unique_ptr<HIR::BlockExpr> (block),
+				   expr.get_locus ());
+}
+
+// rust-ast-lower-struct-field-expr.h
+
+void
+ASTLowerStructExprField::visit (AST::StructExprFieldIdentifierValue &field)
+{
+  HIR::Expr *value = ASTLoweringExpr::translate (field.get_value ().get ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, field.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated = new HIR::StructExprFieldIdentifierValue (
+    mapping, field.get_field_name (), std::unique_ptr<HIR::Expr> (value),
+    field.get_locus ());
+}
+
+void
+ASTLowerStructExprField::visit (AST::StructExprFieldIndexValue &field)
+{
+  HIR::Expr *value = ASTLoweringExpr::translate (field.get_value ().get ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, field.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated
+    = new HIR::StructExprFieldIndexValue (mapping, field.get_index (),
+					  std::unique_ptr<HIR::Expr> (value),
+					  field.get_locus ());
+}
+
+void
+ASTLowerStructExprField::visit (AST::StructExprFieldIdentifier &field)
+{
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, field.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated
+    = new HIR::StructExprFieldIdentifier (mapping, field.get_field_name (),
+					  field.get_locus ());
+}
+
+// rust-ast-lower-block.h
+
+void
+ASTLoweringExprWithBlock::visit (AST::WhileLoopExpr &expr)
+{
+  HIR::BlockExpr *loop_block
+    = ASTLoweringBlock::translate (expr.get_loop_block ().get (), &terminated);
+
+  HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ());
+  HIR::Expr *loop_condition
+    = ASTLoweringExpr::translate (expr.get_predicate_expr ().get (),
+				  &terminated);
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated
+    = new HIR::WhileLoopExpr (mapping,
+			      std::unique_ptr<HIR::Expr> (loop_condition),
+			      std::unique_ptr<HIR::BlockExpr> (loop_block),
+			      expr.get_locus (), std::move (loop_label),
+			      expr.get_outer_attrs ());
+}
+
+void
+ASTLoweringExprWithBlock::visit (AST::ForLoopExpr &expr)
+{
+  HIR::BlockExpr *loop_block
+    = ASTLoweringBlock::translate (expr.get_loop_block ().get (), &terminated);
+  HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ());
+  HIR::Expr *iterator_expr
+    = ASTLoweringExpr::translate (expr.get_iterator_expr ().get (),
+				  &terminated);
+  HIR::Pattern *loop_pattern
+    = ASTLoweringPattern::translate (expr.get_pattern ().get ());
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated
+    = new HIR::ForLoopExpr (mapping,
+			    std::unique_ptr<HIR::Pattern> (loop_pattern),
+			    std::unique_ptr<HIR::Expr> (iterator_expr),
+			    std::unique_ptr<HIR::BlockExpr> (loop_block),
+			    expr.get_locus (), std::move (loop_label),
+			    expr.get_outer_attrs ());
+}
+
+void
+ASTLoweringExprWithBlock::visit (AST::MatchExpr &expr)
+{
+  HIR::Expr *branch_value
+    = ASTLoweringExpr::translate (expr.get_scrutinee_expr ().get ());
+
+  std::vector<HIR::MatchCase> match_arms;
+  for (auto &match_case : expr.get_match_cases ())
+    {
+      HIR::Expr *kase_expr
+	= ASTLoweringExpr::translate (match_case.get_expr ().get ());
+
+      HIR::Expr *kase_guard_expr = nullptr;
+      if (match_case.get_arm ().has_match_arm_guard ())
+	{
+	  kase_guard_expr = ASTLoweringExpr::translate (
+	    match_case.get_arm ().get_guard_expr ().get ());
+	}
+
+      std::vector<std::unique_ptr<HIR::Pattern> > match_arm_patterns;
+      for (auto &pattern : match_case.get_arm ().get_patterns ())
+	{
+	  HIR::Pattern *ptrn = ASTLoweringPattern::translate (pattern.get ());
+	  match_arm_patterns.push_back (std::unique_ptr<HIR::Pattern> (ptrn));
+	}
+
+      HIR::MatchArm arm (std::move (match_arm_patterns), expr.get_locus (),
+			 std::unique_ptr<HIR::Expr> (kase_guard_expr),
+			 match_case.get_arm ().get_outer_attrs ());
+
+      auto crate_num = mappings->get_current_crate ();
+      Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				     mappings->get_next_hir_id (crate_num),
+				     UNKNOWN_LOCAL_DEFID);
+
+      HIR::MatchCase kase (std::move (mapping), std::move (arm),
+			   std::unique_ptr<HIR::Expr> (kase_expr));
+      match_arms.push_back (std::move (kase));
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated
+    = new HIR::MatchExpr (mapping, std::unique_ptr<HIR::Expr> (branch_value),
+			  std::move (match_arms), expr.get_inner_attrs (),
+			  expr.get_outer_attrs (), expr.get_locus ());
+}
+
+// rust-ast-lower-expr.h
+
+void
+ASTLowerPathInExpression::visit (AST::PathInExpression &expr)
+{
+  std::vector<HIR::PathExprSegment> path_segments;
+  auto &segments = expr.get_segments ();
+  for (auto &s : segments)
+    {
+      path_segments.push_back (lower_path_expr_seg ((s)));
+
+      // insert the mappings for the segment
+      HIR::PathExprSegment *lowered_seg = &path_segments.back ();
+      mappings->insert_hir_path_expr_seg (lowered_seg);
+    }
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated = new HIR::PathInExpression (mapping, std::move (path_segments),
+					  expr.get_locus (),
+					  expr.opening_scope_resolution ());
+}
+
+HIR::QualifiedPathType
+ASTLoweringBase::lower_qual_path_type (AST::QualifiedPathType &qualified_type)
+{
+  HIR::Type *type
+    = ASTLoweringType::translate (qualified_type.get_type ().get ());
+  HIR::TypePath *trait
+    = qualified_type.has_as_clause ()
+	? ASTLowerTypePath::translate (qualified_type.get_as_type_path ())
+	: nullptr;
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, qualified_type.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  return HIR::QualifiedPathType (mapping, std::unique_ptr<HIR::Type> (type),
+				 std::unique_ptr<HIR::TypePath> (trait),
+				 qualified_type.get_locus ());
+}
+
+void
+ASTLowerQualPathInExpression::visit (AST::QualifiedPathInExpression &expr)
+{
+  HIR::QualifiedPathType qual_path_type
+    = lower_qual_path_type (expr.get_qualified_path_type ());
+
+  std::vector<HIR::PathExprSegment> path_segments;
+  auto &segments = expr.get_segments ();
+  for (auto &s : segments)
+    {
+      path_segments.push_back (lower_path_expr_seg ((s)));
+
+      // insert the mappings for the segment
+      HIR::PathExprSegment *lowered_seg = &path_segments.back ();
+      mappings->insert_hir_path_expr_seg (lowered_seg);
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated = new HIR::QualifiedPathInExpression (mapping, qual_path_type,
+						   std::move (path_segments),
+						   expr.get_locus (),
+						   expr.get_outer_attrs ());
+}
+} // namespace HIR
+} // namespace Rust
diff --git a/gcc/rust/hir/rust-ast-lower.h b/gcc/rust/hir/rust-ast-lower.h
new file mode 100644
index 00000000000..e726b4b8282
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower.h
@@ -0,0 +1,59 @@
+// 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_HIR_LOWER
+#define RUST_HIR_LOWER
+
+#include "rust-system.h"
+#include "rust-ast-full.h"
+#include "rust-ast-visitor.h"
+#include "rust-hir-full.h"
+
+namespace Rust {
+namespace HIR {
+
+/* Checks whether the name of a field already exists.  Returns true
+   and produces an error if so.  */
+bool
+struct_field_name_exists (std::vector<HIR::StructField> &fields,
+			  HIR::StructField &new_field);
+
+/**
+ * Lowers a Visibility from the AST into an HIR Visibility, desugaring it in
+ * the process
+ */
+Visibility
+translate_visibility (const AST::Visibility &vis);
+
+class ASTLowering
+{
+public:
+  static std::unique_ptr<HIR::Crate> Resolve (AST::Crate &astCrate);
+  ~ASTLowering ();
+
+private:
+  ASTLowering (AST::Crate &astCrate);
+  std::unique_ptr<HIR::Crate> go ();
+
+  AST::Crate &astCrate;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // RUST_HIR_LOWER
diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc
new file mode 100644
index 00000000000..bb139a7c1b7
--- /dev/null
+++ b/gcc/rust/hir/rust-hir-dump.cc
@@ -0,0 +1,521 @@
+// 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-hir-dump.h"
+
+namespace Rust {
+namespace HIR {
+
+Dump::Dump (std::ostream &stream) : stream (stream), indent (0) {}
+
+void
+Dump::go (HIR::Crate &crate)
+{
+  stream << "Crate"
+	 << " "
+	 << "{" << std::endl;
+  //
+
+  indent++;
+  stream << std::string (indent, indent_char);
+  stream << "inner_attrs"
+	 << ":"
+	 << " "
+	 << "[";
+  for (auto &attr : crate.inner_attrs)
+    stream << attr.as_string ();
+  stream << "]"
+	 << "," << std::endl;
+  indent--;
+
+  indent++;
+  stream << std::string (indent, indent_char);
+  //
+
+  stream << "items"
+	 << ":"
+	 << " "
+	 << "[";
+
+  stream << std::string (indent, indent_char);
+  for (const auto &item : crate.items)
+    {
+      stream << std::endl;
+      item->accept_vis (*this);
+    }
+  stream << std::string (indent, indent_char);
+  stream << "]"
+	 << "," << std::endl;
+  indent--;
+  //
+
+  indent++;
+  stream << std::string (indent, indent_char);
+  stream << "node_mappings"
+	 << ":"
+	 << " "
+	 << "[";
+  // TODO: print crate mapping attrs
+  stream << "]" << std::endl;
+  indent--;
+
+  stream << "}" << std::endl;
+}
+
+void
+Dump::visit (Lifetime &)
+{}
+void
+Dump::visit (LifetimeParam &)
+{}
+void
+Dump::visit (PathInExpression &)
+{}
+void
+Dump::visit (TypePathSegment &)
+{}
+void
+Dump::visit (TypePathSegmentGeneric &)
+{}
+void
+Dump::visit (TypePathSegmentFunction &)
+{}
+void
+Dump::visit (TypePath &)
+{}
+void
+Dump::visit (QualifiedPathInExpression &)
+{}
+void
+Dump::visit (QualifiedPathInType &)
+{}
+
+void
+Dump::visit (LiteralExpr &literal_expr)
+{
+  indent++;
+  stream << std::string (indent, indent_char);
+  stream << "( " + literal_expr.get_literal ().as_string () + " ("
+	      + literal_expr.get_mappings ().as_string () + "))";
+  stream << "\n";
+}
+void
+Dump::visit (BorrowExpr &)
+{}
+void
+Dump::visit (DereferenceExpr &)
+{}
+void
+Dump::visit (ErrorPropagationExpr &)
+{}
+void
+Dump::visit (NegationExpr &)
+{}
+void
+Dump::visit (ArithmeticOrLogicalExpr &)
+{}
+void
+Dump::visit (ComparisonExpr &)
+{}
+void
+Dump::visit (LazyBooleanExpr &)
+{}
+void
+Dump::visit (TypeCastExpr &)
+{}
+void
+Dump::visit (AssignmentExpr &)
+{}
+void
+Dump::visit (CompoundAssignmentExpr &)
+{}
+void
+Dump::visit (GroupedExpr &)
+{}
+
+void
+Dump::visit (ArrayElemsValues &)
+{}
+void
+Dump::visit (ArrayElemsCopied &)
+{}
+void
+Dump::visit (ArrayExpr &)
+{}
+void
+Dump::visit (ArrayIndexExpr &)
+{}
+void
+Dump::visit (TupleExpr &)
+{}
+void
+Dump::visit (TupleIndexExpr &)
+{}
+void
+Dump::visit (StructExprStruct &)
+{}
+
+void
+Dump::visit (StructExprFieldIdentifier &)
+{}
+void
+Dump::visit (StructExprFieldIdentifierValue &)
+{}
+
+void
+Dump::visit (StructExprFieldIndexValue &)
+{}
+void
+Dump::visit (StructExprStructFields &)
+{}
+void
+Dump::visit (StructExprStructBase &)
+{}
+
+void
+Dump::visit (CallExpr &)
+{}
+void
+Dump::visit (MethodCallExpr &)
+{}
+void
+Dump::visit (FieldAccessExpr &)
+{}
+void
+Dump::visit (ClosureExprInner &)
+{}
+void
+Dump::visit (BlockExpr &block_expr)
+{
+  stream << "BlockExpr"
+	 << ":"
+	 << " "
+	 << "[";
+  indent++;
+  // TODO: print statements
+  // TODO: print tail expression if exists
+  stream << "]";
+  indent--;
+}
+void
+Dump::visit (ClosureExprInnerTyped &)
+{}
+void
+Dump::visit (ContinueExpr &)
+{}
+void
+Dump::visit (BreakExpr &)
+{}
+void
+Dump::visit (RangeFromToExpr &)
+{}
+void
+Dump::visit (RangeFromExpr &)
+{}
+void
+Dump::visit (RangeToExpr &)
+{}
+void
+Dump::visit (RangeFullExpr &)
+{}
+void
+Dump::visit (RangeFromToInclExpr &)
+{}
+void
+Dump::visit (RangeToInclExpr &)
+{}
+void
+Dump::visit (ReturnExpr &)
+{}
+void
+Dump::visit (UnsafeBlockExpr &)
+{}
+void
+Dump::visit (LoopExpr &)
+{}
+void
+Dump::visit (WhileLoopExpr &)
+{}
+void
+Dump::visit (WhileLetLoopExpr &)
+{}
+void
+Dump::visit (ForLoopExpr &)
+{}
+void
+Dump::visit (IfExpr &)
+{}
+void
+Dump::visit (IfExprConseqElse &)
+{}
+void
+Dump::visit (IfExprConseqIf &)
+{}
+void
+Dump::visit (IfExprConseqIfLet &)
+{}
+void
+Dump::visit (IfLetExpr &)
+{}
+void
+Dump::visit (IfLetExprConseqElse &)
+{}
+void
+Dump::visit (IfLetExprConseqIf &)
+{}
+void
+Dump::visit (IfLetExprConseqIfLet &)
+{}
+
+void
+Dump::visit (MatchExpr &)
+{}
+void
+Dump::visit (AwaitExpr &)
+{}
+void
+Dump::visit (AsyncBlockExpr &)
+{}
+
+void
+Dump::visit (TypeParam &)
+{}
+
+void
+Dump::visit (ConstGenericParam &)
+{}
+
+void
+Dump::visit (LifetimeWhereClauseItem &)
+{}
+void
+Dump::visit (TypeBoundWhereClauseItem &)
+{}
+void
+Dump::visit (Module &)
+{}
+void
+Dump::visit (ExternCrate &)
+{}
+
+void
+Dump::visit (UseTreeGlob &)
+{}
+void
+Dump::visit (UseTreeList &)
+{}
+void
+Dump::visit (UseTreeRebind &)
+{}
+void
+Dump::visit (UseDeclaration &)
+{}
+void
+Dump::visit (Function &function)
+{
+  indent++;
+  stream << std::string (indent, indent_char);
+  stream << "Function"
+	 << " ";
+  stream << "{" << std::endl;
+  // TODO: print function params
+  stream << std::string (indent, indent_char);
+  stream << "}" << std::endl;
+  // TODO: get function definition and visit block
+
+  stream << std::endl;
+  indent--;
+}
+void
+Dump::visit (TypeAlias &)
+{}
+void
+Dump::visit (StructStruct &)
+{}
+void
+Dump::visit (TupleStruct &)
+{}
+void
+Dump::visit (EnumItem &)
+{}
+void
+Dump::visit (EnumItemTuple &)
+{}
+void
+Dump::visit (EnumItemStruct &)
+{}
+void
+Dump::visit (EnumItemDiscriminant &)
+{}
+void
+Dump::visit (Enum &)
+{}
+void
+Dump::visit (Union &)
+{}
+void
+Dump::visit (ConstantItem &)
+{}
+void
+Dump::visit (StaticItem &)
+{}
+void
+Dump::visit (TraitItemFunc &)
+{}
+void
+Dump::visit (TraitItemConst &)
+{}
+void
+Dump::visit (TraitItemType &)
+{}
+void
+Dump::visit (Trait &)
+{}
+void
+Dump::visit (ImplBlock &)
+{}
+
+void
+Dump::visit (ExternalStaticItem &)
+{}
+void
+Dump::visit (ExternalFunctionItem &)
+{}
+void
+Dump::visit (ExternBlock &)
+{}
+
+void
+Dump::visit (LiteralPattern &)
+{}
+void
+Dump::visit (IdentifierPattern &)
+{}
+void
+Dump::visit (WildcardPattern &)
+{}
+
+void
+Dump::visit (RangePatternBoundLiteral &)
+{}
+void
+Dump::visit (RangePatternBoundPath &)
+{}
+void
+Dump::visit (RangePatternBoundQualPath &)
+{}
+void
+Dump::visit (RangePattern &)
+{}
+void
+Dump::visit (ReferencePattern &)
+{}
+
+void
+Dump::visit (StructPatternFieldTuplePat &)
+{}
+void
+Dump::visit (StructPatternFieldIdentPat &)
+{}
+void
+Dump::visit (StructPatternFieldIdent &)
+{}
+void
+Dump::visit (StructPattern &)
+{}
+
+void
+Dump::visit (TupleStructItemsNoRange &)
+{}
+void
+Dump::visit (TupleStructItemsRange &)
+{}
+void
+Dump::visit (TupleStructPattern &)
+{}
+
+void
+Dump::visit (TuplePatternItemsMultiple &)
+{}
+void
+Dump::visit (TuplePatternItemsRanged &)
+{}
+void
+Dump::visit (TuplePattern &)
+{}
+void
+Dump::visit (GroupedPattern &)
+{}
+void
+Dump::visit (SlicePattern &)
+{}
+
+void
+Dump::visit (EmptyStmt &)
+{}
+void
+Dump::visit (LetStmt &)
+{}
+void
+Dump::visit (ExprStmtWithoutBlock &)
+{}
+void
+Dump::visit (ExprStmtWithBlock &)
+{}
+
+void
+Dump::visit (TraitBound &)
+{}
+void
+Dump::visit (ImplTraitType &)
+{}
+void
+Dump::visit (TraitObjectType &)
+{}
+void
+Dump::visit (ParenthesisedType &)
+{}
+void
+Dump::visit (ImplTraitTypeOneBound &)
+{}
+void
+Dump::visit (TupleType &)
+{}
+void
+Dump::visit (NeverType &)
+{}
+void
+Dump::visit (RawPointerType &)
+{}
+void
+Dump::visit (ReferenceType &)
+{}
+void
+Dump::visit (ArrayType &)
+{}
+void
+Dump::visit (SliceType &)
+{}
+void
+Dump::visit (InferredType &)
+{}
+void
+Dump::visit (BareFunctionType &)
+{}
+} // namespace HIR
+} // namespace Rust
diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h
new file mode 100644
index 00000000000..8b9e8939a28
--- /dev/null
+++ b/gcc/rust/hir/rust-hir-dump.h
@@ -0,0 +1,193 @@
+// 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_HIR_DUMP_H
+#define RUST_HIR_DUMP_H
+
+#include "rust-hir-visitor.h"
+#include "rust-hir.h"
+#include "rust-hir-full.h"
+
+namespace Rust {
+namespace HIR {
+
+class Dump : public HIRFullVisitor
+{
+public:
+  Dump (std::ostream &stream);
+  void go (HIR::Crate &crate);
+
+private:
+  std::ostream &stream;
+  std::size_t indent; // current indentation level
+  char indent_char = '\t';
+
+  virtual void visit (Lifetime &) override;
+  virtual void visit (LifetimeParam &) override;
+  virtual void visit (PathInExpression &) override;
+  virtual void visit (TypePathSegment &) override;
+  virtual void visit (TypePathSegmentGeneric &) override;
+  virtual void visit (TypePathSegmentFunction &) override;
+  virtual void visit (TypePath &) override;
+  virtual void visit (QualifiedPathInExpression &) override;
+  virtual void visit (QualifiedPathInType &) override;
+
+  virtual void visit (LiteralExpr &) override;
+  virtual void visit (BorrowExpr &) override;
+  virtual void visit (DereferenceExpr &) override;
+  virtual void visit (ErrorPropagationExpr &) override;
+  virtual void visit (NegationExpr &) override;
+  virtual void visit (ArithmeticOrLogicalExpr &) override;
+  virtual void visit (ComparisonExpr &) override;
+  virtual void visit (LazyBooleanExpr &) override;
+  virtual void visit (TypeCastExpr &) override;
+  virtual void visit (AssignmentExpr &) override;
+  virtual void visit (CompoundAssignmentExpr &) override;
+  virtual void visit (GroupedExpr &) override;
+
+  virtual void visit (ArrayElemsValues &) override;
+  virtual void visit (ArrayElemsCopied &) override;
+  virtual void visit (ArrayExpr &) override;
+  virtual void visit (ArrayIndexExpr &) override;
+  virtual void visit (TupleExpr &) override;
+  virtual void visit (TupleIndexExpr &) override;
+  virtual void visit (StructExprStruct &) override;
+
+  virtual void visit (StructExprFieldIdentifier &) override;
+  virtual void visit (StructExprFieldIdentifierValue &) override;
+
+  virtual void visit (StructExprFieldIndexValue &) override;
+  virtual void visit (StructExprStructFields &) override;
+  virtual void visit (StructExprStructBase &) override;
+
+  virtual void visit (CallExpr &) override;
+  virtual void visit (MethodCallExpr &) override;
+  virtual void visit (FieldAccessExpr &) override;
+  virtual void visit (ClosureExprInner &) override;
+  virtual void visit (BlockExpr &) override;
+  virtual void visit (ClosureExprInnerTyped &) override;
+  virtual void visit (ContinueExpr &) override;
+  virtual void visit (BreakExpr &) override;
+  virtual void visit (RangeFromToExpr &) override;
+  virtual void visit (RangeFromExpr &) override;
+  virtual void visit (RangeToExpr &) override;
+  virtual void visit (RangeFullExpr &) override;
+  virtual void visit (RangeFromToInclExpr &) override;
+  virtual void visit (RangeToInclExpr &) override;
+  virtual void visit (ReturnExpr &) override;
+  virtual void visit (UnsafeBlockExpr &) override;
+  virtual void visit (LoopExpr &) override;
+  virtual void visit (WhileLoopExpr &) override;
+  virtual void visit (WhileLetLoopExpr &) override;
+  virtual void visit (ForLoopExpr &) override;
+  virtual void visit (IfExpr &) override;
+  virtual void visit (IfExprConseqElse &) override;
+  virtual void visit (IfExprConseqIf &) override;
+  virtual void visit (IfExprConseqIfLet &) override;
+  virtual void visit (IfLetExpr &) override;
+  virtual void visit (IfLetExprConseqElse &) override;
+  virtual void visit (IfLetExprConseqIf &) override;
+  virtual void visit (IfLetExprConseqIfLet &) override;
+
+  virtual void visit (MatchExpr &) override;
+  virtual void visit (AwaitExpr &) override;
+  virtual void visit (AsyncBlockExpr &) override;
+
+  virtual void visit (TypeParam &) override;
+  virtual void visit (ConstGenericParam &) override;
+
+  virtual void visit (LifetimeWhereClauseItem &) override;
+  virtual void visit (TypeBoundWhereClauseItem &) override;
+  virtual void visit (Module &) override;
+  virtual void visit (ExternCrate &) override;
+
+  virtual void visit (UseTreeGlob &) override;
+  virtual void visit (UseTreeList &) override;
+  virtual void visit (UseTreeRebind &) override;
+  virtual void visit (UseDeclaration &) override;
+  virtual void visit (Function &) override;
+  virtual void visit (TypeAlias &) override;
+  virtual void visit (StructStruct &) override;
+  virtual void visit (TupleStruct &) override;
+  virtual void visit (EnumItem &) override;
+  virtual void visit (EnumItemTuple &) override;
+  virtual void visit (EnumItemStruct &) override;
+  virtual void visit (EnumItemDiscriminant &) override;
+  virtual void visit (Enum &) override;
+  virtual void visit (Union &) override;
+  virtual void visit (ConstantItem &) override;
+  virtual void visit (StaticItem &) override;
+  virtual void visit (TraitItemFunc &) override;
+  virtual void visit (TraitItemConst &) override;
+  virtual void visit (TraitItemType &) override;
+  virtual void visit (Trait &) override;
+  virtual void visit (ImplBlock &) override;
+
+  virtual void visit (ExternalStaticItem &) override;
+  virtual void visit (ExternalFunctionItem &) override;
+  virtual void visit (ExternBlock &) override;
+
+  virtual void visit (LiteralPattern &) override;
+  virtual void visit (IdentifierPattern &) override;
+  virtual void visit (WildcardPattern &) override;
+
+  virtual void visit (RangePatternBoundLiteral &) override;
+  virtual void visit (RangePatternBoundPath &) override;
+  virtual void visit (RangePatternBoundQualPath &) override;
+  virtual void visit (RangePattern &) override;
+  virtual void visit (ReferencePattern &) override;
+
+  virtual void visit (StructPatternFieldTuplePat &) override;
+  virtual void visit (StructPatternFieldIdentPat &) override;
+  virtual void visit (StructPatternFieldIdent &) override;
+  virtual void visit (StructPattern &) override;
+
+  virtual void visit (TupleStructItemsNoRange &) override;
+  virtual void visit (TupleStructItemsRange &) override;
+  virtual void visit (TupleStructPattern &) override;
+
+  virtual void visit (TuplePatternItemsMultiple &) override;
+  virtual void visit (TuplePatternItemsRanged &) override;
+  virtual void visit (TuplePattern &) override;
+  virtual void visit (GroupedPattern &) override;
+  virtual void visit (SlicePattern &) override;
+
+  virtual void visit (EmptyStmt &) override;
+  virtual void visit (LetStmt &) override;
+  virtual void visit (ExprStmtWithoutBlock &) override;
+  virtual void visit (ExprStmtWithBlock &) override;
+
+  virtual void visit (TraitBound &) override;
+  virtual void visit (ImplTraitType &) override;
+  virtual void visit (TraitObjectType &) override;
+  virtual void visit (ParenthesisedType &) override;
+  virtual void visit (ImplTraitTypeOneBound &) override;
+  virtual void visit (TupleType &) override;
+  virtual void visit (NeverType &) override;
+  virtual void visit (RawPointerType &) override;
+  virtual void visit (ReferenceType &) override;
+  virtual void visit (ArrayType &) override;
+  virtual void visit (SliceType &) override;
+  virtual void visit (InferredType &) override;
+  virtual void visit (BareFunctionType &) override;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif // !RUST_HIR_DUMP_H
