diff --git a/gcc/rust/hir/rust-ast-lower-implitem.cc b/gcc/rust/hir/rust-ast-lower-implitem.cc
index 98db1dccd7c..77230e7a8bf 100644
--- a/gcc/rust/hir/rust-ast-lower-implitem.cc
+++ b/gcc/rust/hir/rust-ast-lower-implitem.cc
@@ -227,6 +227,92 @@ ASTLowerTraitItem::translate (AST::AssociatedItem *item)
   return resolver.translated;
 }
 
+void
+ASTLowerTraitItem::visit (AST::Function &func)
+{
+  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_qualifiers ());
+
+  std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+  if (func.has_generics ())
+    generic_params = lower_generic_params (func.get_generic_params ());
+
+  std::unique_ptr<HIR::Type> return_type
+    = func.has_return_type () ? std::unique_ptr<HIR::Type> (
+	ASTLoweringType::translate (func.get_return_type ().get ()))
+			      : nullptr;
+
+  // set self parameter to error if this is a method
+  // else lower to hir
+  HIR::SelfParam self_param = func.has_self_param ()
+				? lower_self (func.get_self_param ())
+				: HIR::SelfParam::error ();
+
+  std::vector<HIR::FunctionParam> function_params;
+  for (auto &p : func.get_function_params ())
+    {
+      if (p->is_variadic () || p->is_self ())
+	continue;
+
+      auto param = static_cast<AST::FunctionParam *> (p.get ());
+
+      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 (func.get_function_name (),
+			       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
+    = func.has_body () ? 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));
+
+  auto *trait_item
+    = new HIR::TraitItemFunc (mapping, std::move (decl), std::move (block_expr),
+			      func.get_outer_attrs (), func.get_locus ());
+  translated = trait_item;
+  if (func.has_self_param ())
+    {
+      // 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
 ASTLowerTraitItem::visit (AST::TraitItemFunc &func)
 {
diff --git a/gcc/rust/hir/rust-ast-lower-implitem.h b/gcc/rust/hir/rust-ast-lower-implitem.h
index 3a266b41ed4..b9d12cc4a56 100644
--- a/gcc/rust/hir/rust-ast-lower-implitem.h
+++ b/gcc/rust/hir/rust-ast-lower-implitem.h
@@ -48,6 +48,7 @@ class ASTLowerTraitItem : public ASTLoweringBase
 
 public:
   static HIR::TraitItem *translate (AST::AssociatedItem *item);
+  void visit (AST::Function &func) override;
   void visit (AST::TraitItemFunc &func) override;
   void visit (AST::TraitItemMethod &method) override;
   void visit (AST::TraitItemConst &constant) override;
diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h
index 365bdd6135f..d9c9bcb28c9 100644
--- a/gcc/rust/resolve/rust-ast-resolve-implitem.h
+++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h
@@ -110,6 +110,26 @@ public:
     item->accept_vis (resolver);
   };
 
+  void visit (AST::Function &function) override
+  {
+    auto decl
+      = CanonicalPath::new_seg (function.get_node_id (),
+				function.get_function_name ().as_string ());
+    auto path = prefix.append (decl);
+    auto cpath = canonical_prefix.append (decl);
+
+    resolver->get_name_scope ().insert (
+      path, function.get_node_id (), function.get_locus (), false,
+      Rib::ItemType::Function,
+      [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
+	rich_location r (line_table, function.get_locus ());
+	r.add_range (locus);
+	rust_error_at (r, "redefined multiple times");
+      });
+
+    mappings->insert_canonical_path (function.get_node_id (), cpath);
+  }
+
   void visit (AST::TraitItemFunc &function) override
   {
     auto decl = CanonicalPath::new_seg (
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc
index 60eca5b13c7..6037fe59f5b 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-item.cc
@@ -45,6 +45,94 @@ ResolveTraitItems::go (AST::AssociatedItem *item, const CanonicalPath &prefix,
   item->accept_vis (resolver);
 }
 
+void
+ResolveTraitItems::visit (AST::Function &function)
+{
+  auto decl
+    = CanonicalPath::new_seg (function.get_node_id (),
+			      function.get_function_name ().as_string ());
+  auto path = prefix.append (decl);
+  auto cpath = canonical_prefix.append (decl);
+  mappings->insert_canonical_path (function.get_node_id (), cpath);
+
+  NodeId scope_node_id = function.get_node_id ();
+  resolver->get_name_scope ().push (scope_node_id);
+  resolver->get_type_scope ().push (scope_node_id);
+  resolver->get_label_scope ().push (scope_node_id);
+  resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+  resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+  resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+  if (function.has_generics ())
+    for (auto &generic : function.get_generic_params ())
+      ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+  if (function.has_return_type ())
+    ResolveType::go (function.get_return_type ().get ());
+
+  // self turns into (self: Self) as a function param
+  std::vector<PatternBinding> bindings
+    = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
+
+  // we make a new scope so the names of parameters are resolved and shadowed
+  // correctly
+  for (auto &p : function.get_function_params ())
+    {
+      if (p->is_variadic ())
+	{
+	  auto param = static_cast<AST::VariadicParam *> (p.get ());
+	  PatternDeclaration::go (param->get_pattern ().get (),
+				  Rib::ItemType::Param, bindings);
+	}
+      else if (p->is_self ())
+	{
+	  auto param = static_cast<AST::SelfParam *> (p.get ());
+	  // FIXME: which location should be used for Rust::Identifier `self`?
+	  AST::IdentifierPattern self_pattern (
+	    param->get_node_id (), {"self"}, param->get_locus (),
+	    param->get_has_ref (), param->get_is_mut (),
+	    std::unique_ptr<AST::Pattern> (nullptr));
+
+	  PatternDeclaration::go (&self_pattern, Rib::ItemType::Param);
+
+	  if (param->has_type ())
+	    {
+	      // This shouldn't happen the parser should already error for this
+	      rust_assert (!param->get_has_ref ());
+	      ResolveType::go (param->get_type ().get ());
+	    }
+	  else
+	    {
+	      // here we implicitly make self have a type path of Self
+	      std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
+	      segments.push_back (std::unique_ptr<AST::TypePathSegment> (
+		new AST::TypePathSegment ("Self", false, param->get_locus ())));
+
+	      AST::TypePath self_type_path (std::move (segments),
+					    param->get_locus ());
+	      ResolveType::go (&self_type_path);
+	    }
+	}
+      else
+	{
+	  auto param = static_cast<AST::FunctionParam *> (p.get ());
+	  ResolveType::go (param->get_type ().get ());
+	  PatternDeclaration::go (param->get_pattern ().get (),
+				  Rib::ItemType::Param, bindings);
+	}
+    }
+
+  if (function.has_where_clause ())
+    ResolveWhereClause::Resolve (function.get_where_clause ());
+
+  // trait items have an optional body
+  if (function.has_body ())
+    ResolveExpr::go (function.get_definition ()->get (), path, cpath);
+
+  resolver->get_name_scope ().pop ();
+  resolver->get_type_scope ().pop ();
+  resolver->get_label_scope ().pop ();
+}
 void
 ResolveTraitItems::visit (AST::TraitItemType &type)
 {
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index 712fe62336f..33a78e21957 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -35,6 +35,7 @@ public:
   static void go (AST::AssociatedItem *item, const CanonicalPath &prefix,
 		  const CanonicalPath &canonical_prefix);
 
+  void visit (AST::Function &type) override;
   void visit (AST::TraitItemType &type) override;
   void visit (AST::TraitItemFunc &func) override;
   void visit (AST::TraitItemMethod &func) override;
