From: Enes Cevik <[email protected]>

This patch implement the lang item `owned_box` and add support box
expression.

gcc/rust/ChangeLog:

        * ast/rust-expr.h (BoxExpr): Add comment description to class.
        * backend/rust-compile-block.h (visit): Add stub for BoxExpr.
        * backend/rust-compile-expr.cc (compile_box_struct): New
        function.
        (compile_box): New function.
        (build_box_inner_ptr): New function.
        (CompileExpr::visit): Implement BoxExpr lowering using
        exchange_malloc and constructor expressions. Handle owned_box
        in FieldAccessExpr and DereferenceExpr.
        (HIRCompileBase::resolve_deref_adjustment): Support owned_box
        in deref adjustments.
        * backend/rust-compile-expr.h (visit): Declare BoxExpr visitor.
        * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
        (ExprStmtBuilder::visit): Evaluate inner expression and push
        tmp assignment for BoxExpr.
        * checks/errors/borrowck/rust-bir-builder-expr-stmt.h (visit):
        Declare BoxExpr visitor.
        * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
        (visit): Mark BoxExpr as unreachable.
        * checks/errors/borrowck/rust-bir-builder-struct.h (visit):
        Likewise.
        * checks/errors/borrowck/rust-function-collector.h (visit):
        Add visit stub for BoxExpr.
        * checks/errors/privacy/rust-privacy-reporter.cc
        (PrivacyReporter::visit): Delegate privacy reporting to inner
        expression of BoxExpr.
        * checks/errors/privacy/rust-privacy-reporter.h (visit):
        Declare BoxExpr visitor.
        * checks/errors/rust-const-checker.cc (ConstChecker::visit):
        Delegate const checking to inner expression.
        * checks/errors/rust-const-checker.h (visit): Declare BoxExpr
        visitor.
        * checks/errors/rust-hir-pattern-analysis.cc
        (PatternChecker::visit): Delegate pattern analysis to inner
        expression.
        * checks/errors/rust-hir-pattern-analysis.h (visit): Declare
        BoxExpr visitor.
        * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit):
        Delegate unsafe checking to inner expression.
        * checks/errors/rust-unsafe-checker.h (visit): Declare BoxExpr
        visitor.
        * checks/lints/rust-lint-marklive.cc (MarkLive::visit): Resolve
        inner ADT type for owned_box when marking live fields.
        * checks/lints/rust-lint-marklive.h (visit): Declare BoxExpr
        visitor.
        * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Translate
        AST BoxExpr to HIR BoxExpr.
        * hir/rust-hir-dump.cc (Dump::visit): Dump HIR BoxExpr.
        * hir/rust-hir-dump.h (visit): Declare BoxExpr visitor.
        * hir/tree/rust-hir-expr-abstract.h (ExprType): Add Box to enum.
        * hir/tree/rust-hir-expr.cc (BoxExpr::BoxExpr): Implement
        constructors for BoxExpr. (BoxExpr::operator=): Implement
        assignment operator.
        * hir/tree/rust-hir-expr.h (class BoxExpr): Define HIR BoxExpr
        node.
        * hir/tree/rust-hir-full-decls.h (class BoxExpr): Forward
        declaration.
        * hir/tree/rust-hir-visitor.cc (DefaultHIRVisitor::walk): Walk
        inner expression of BoxExpr.
        * hir/tree/rust-hir-visitor.h (visit): Add routing for BoxExpr.
        * hir/tree/rust-hir.cc (BoxExpr::to_string): Implement
        to_string.
        (BoxExpr::accept_vis): Implement visitor acceptance.
        * typecheck/rust-autoderef.cc (AutoderefCycle::cycle): Attempt
        autoderef using the owned_box lang item.
        * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit):
        Implement type checking, validation, and generic substitution
        for BoxExpr. Support owned_box autoderef in field access and
        dereferencing operations.
        * typecheck/rust-tyty.cc (try_get_box_inner_type): New function.
        * typecheck/rust-tyty.h (try_get_box_inner_type): New
        declaration.
        * typecheck/rust-hir-type-check-expr.h (visit): Declare BoxExpr
        visitor.
        * util/rust-lang-item.cc (Rust::LangItem::lang_items): Register
        owned_box to BiMap.
        * util/rust-lang-item.h (LangItem::Kind): Add OWNED_BOX.

gcc/testsuite/ChangeLog:

        * rust/compile/box-expr.rs: New test.
        * rust/compile/lang-owned-box-error1.rs: New test.
        * rust/compile/lang-owned-box-error2.rs: New test.

Signed-off-by: Enes Cevik <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/06e19241a8a023f58a0ca9dcd3b9f3d3dea0f0bf

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4574

 gcc/rust/ast/rust-expr.h                      |   1 +
 gcc/rust/backend/rust-compile-block.h         |   2 +
 gcc/rust/backend/rust-compile-expr.cc         | 171 +++++++++++++++++-
 gcc/rust/backend/rust-compile-expr.h          |   1 +
 .../borrowck/rust-bir-builder-expr-stmt.cc    |   9 +
 .../borrowck/rust-bir-builder-expr-stmt.h     |   1 +
 .../borrowck/rust-bir-builder-lazyboolexpr.h  |   1 +
 .../errors/borrowck/rust-bir-builder-struct.h |   1 +
 .../errors/borrowck/rust-function-collector.h |   1 +
 .../errors/privacy/rust-privacy-reporter.cc   |   6 +
 .../errors/privacy/rust-privacy-reporter.h    |   1 +
 gcc/rust/checks/errors/rust-const-checker.cc  |   6 +
 gcc/rust/checks/errors/rust-const-checker.h   |   1 +
 .../errors/rust-hir-pattern-analysis.cc       |   6 +
 .../checks/errors/rust-hir-pattern-analysis.h |   1 +
 gcc/rust/checks/errors/rust-unsafe-checker.cc |   6 +
 gcc/rust/checks/errors/rust-unsafe-checker.h  |   1 +
 gcc/rust/checks/lints/rust-lint-marklive.cc   |   7 +
 gcc/rust/checks/lints/rust-lint-marklive.h    |   5 +
 gcc/rust/hir/rust-ast-lower-expr.cc           |  11 +-
 gcc/rust/hir/rust-hir-dump.cc                 |  11 ++
 gcc/rust/hir/rust-hir-dump.h                  |   1 +
 gcc/rust/hir/tree/rust-hir-expr-abstract.h    |   1 +
 gcc/rust/hir/tree/rust-hir-expr.cc            |  27 +++
 gcc/rust/hir/tree/rust-hir-expr.h             |  46 +++++
 gcc/rust/hir/tree/rust-hir-full-decls.h       |   1 +
 gcc/rust/hir/tree/rust-hir-visitor.cc         |   7 +
 gcc/rust/hir/tree/rust-hir-visitor.h          |   5 +
 gcc/rust/hir/tree/rust-hir.cc                 |  21 +++
 gcc/rust/typecheck/rust-autoderef.cc          |  15 ++
 .../typecheck/rust-hir-type-check-expr.cc     |  76 +++++++-
 gcc/rust/typecheck/rust-hir-type-check-expr.h |   1 +
 gcc/rust/typecheck/rust-tyty.cc               |  23 +++
 gcc/rust/typecheck/rust-tyty.h                |   3 +
 gcc/rust/util/rust-lang-item.cc               |   1 +
 gcc/rust/util/rust-lang-item.h                |   3 +-
 gcc/testsuite/rust/compile/box-expr.rs        |  55 ++++++
 .../rust/compile/lang-owned-box-error1.rs     |  15 ++
 .../rust/compile/lang-owned-box-error2.rs     |  12 ++
 39 files changed, 556 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/box-expr.rs
 create mode 100644 gcc/testsuite/rust/compile/lang-owned-box-error1.rs
 create mode 100644 gcc/testsuite/rust/compile/lang-owned-box-error2.rs

diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h
index 90e4daec4..921b79800 100644
--- a/gcc/rust/ast/rust-expr.h
+++ b/gcc/rust/ast/rust-expr.h
@@ -3751,6 +3751,7 @@ protected:
   }
 };
 
+// Box expression AST node representation
 class BoxExpr : public ExprWithoutBlock
 {
   std::unique_ptr<Expr> expr;
diff --git a/gcc/rust/backend/rust-compile-block.h 
b/gcc/rust/backend/rust-compile-block.h
index 680b4fb6c..9d29e8fc5 100644
--- a/gcc/rust/backend/rust-compile-block.h
+++ b/gcc/rust/backend/rust-compile-block.h
@@ -94,6 +94,7 @@ public:
   void visit (HIR::RangeFullExpr &) override {}
   void visit (HIR::RangeFromToInclExpr &) override {}
   void visit (HIR::RangeToInclExpr &) override {}
+  void visit (HIR::BoxExpr &) override {}
   void visit (HIR::ReturnExpr &) override {}
   void visit (HIR::UnsafeBlockExpr &) override {}
   void visit (HIR::LoopExpr &) override {}
@@ -184,6 +185,7 @@ public:
   void visit (HIR::RangeFullExpr &) override {}
   void visit (HIR::RangeFromToInclExpr &) override {}
   void visit (HIR::RangeToInclExpr &) override {}
+  void visit (HIR::BoxExpr &) override {}
   void visit (HIR::ReturnExpr &) override {}
   void visit (HIR::UnsafeBlockExpr &) override {}
   void visit (HIR::LoopExpr &) override {}
diff --git a/gcc/rust/backend/rust-compile-expr.cc 
b/gcc/rust/backend/rust-compile-expr.cc
index 37a9c702a..55ff3263a 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -45,6 +45,114 @@
 namespace Rust {
 namespace Compile {
 
+namespace {
+tree
+compile_box_struct (Context *ctx, TyTy::BaseType *curr_ty, tree typed_ptr,
+                   location_t locus, int depth = 0)
+{
+  // infinite loop guard
+  rust_assert (depth < 100);
+
+  if (curr_ty->get_kind () == TyTy::TypeKind::POINTER
+      || curr_ty->get_kind () == TyTy::TypeKind::REF)
+    return typed_ptr;
+
+  if (curr_ty->get_kind () == TyTy::TypeKind::ADT)
+    {
+      TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (curr_ty);
+      tree adt_ty_tree = TyTyResolveCompile::compile (ctx, adt);
+      tree size_tree = TYPE_SIZE_UNIT (adt_ty_tree);
+
+      if (integer_zerop (size_tree))
+       return Backend::constructor_expression (adt_ty_tree, false, {}, -1,
+                                               locus);
+      rust_assert (!adt->is_enum ());
+      rust_assert (adt->number_of_variants () == 1);
+
+      std::vector<tree> args;
+      TyTy::VariantDef *variant = adt->get_variants ().at (0);
+      for (size_t i = 0; i < variant->num_fields (); i++)
+       {
+         TyTy::StructFieldType *field = variant->get_field_at_index (i);
+         TyTy::BaseType *field_ty = field->get_field_type ();
+         tree field_tree
+           = compile_box_struct (ctx, field_ty, typed_ptr, locus, depth + 1);
+         args.push_back (field_tree);
+       }
+      return Backend::constructor_expression (adt_ty_tree, false, args, -1,
+                                             locus);
+    }
+  if (curr_ty->get_kind () == TyTy::TypeKind::PARAM)
+    {
+      TyTy::ParamType *param_ty = static_cast<TyTy::ParamType *> (curr_ty);
+      TyTy::BaseType *resolved_ty = param_ty->resolve ();
+      rust_assert (resolved_ty != nullptr && resolved_ty != curr_ty);
+      return compile_box_struct (ctx, resolved_ty, typed_ptr, locus, depth + 
1);
+    }
+  rust_unreachable ();
+  return error_mark_node;
+};
+
+tree
+compile_box (Context *ctx, TyTy::BaseType *box_tyty, TyTy::BaseType 
*inner_tyty,
+            tree inner_expr_tree, location_t locus)
+{
+  tree inner_type_tree = TyTyResolveCompile::compile (ctx, inner_tyty);
+
+  if (!COMPLETE_TYPE_P (inner_type_tree))
+    {
+      rust_sorry_at (locus,
+                    "dynamically sized types in boxes are not supported yet");
+      return error_mark_node;
+    }
+  tree size_tree = TYPE_SIZE_UNIT (inner_type_tree);
+  tree align_tree
+    = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (inner_type_tree));
+
+  DefId exchange_malloc_defid
+    = ctx->get_mappings ().get_lang_item (LangItem::Kind::EXCHANGE_MALLOC,
+                                         locus);
+  HIR::Item *item
+    = ctx->get_mappings ().lookup_defid (exchange_malloc_defid).value ();
+
+  tree exchange_malloc_decl = nullptr;
+  ctx->lookup_function_decl (item->get_mappings ().get_hirid (),
+                            &exchange_malloc_decl, exchange_malloc_defid);
+
+  tree raw_ptr = save_expr (build_call_expr_loc (locus, exchange_malloc_decl, 
2,
+                                                size_tree, align_tree));
+  tree typed_ptr = fold_convert (build_pointer_type (inner_type_tree), 
raw_ptr);
+
+  tree deref = build1_loc (locus, INDIRECT_REF, inner_type_tree, typed_ptr);
+  tree assignment
+    = build2_loc (locus, MODIFY_EXPR, inner_type_tree, deref, inner_expr_tree);
+
+  tree box_struct = compile_box_struct (ctx, box_tyty, typed_ptr, locus);
+
+  return build2_loc (locus, COMPOUND_EXPR, TREE_TYPE (box_struct), assignment,
+                    box_struct);
+}
+
+tree
+build_box_inner_ptr (tree main_expr, location_t locus)
+{
+  // We continuously extract the first field of the struct until we hit the
+  // actual underlying raw pointer. This handles both simple Box layouts (ptr:
+  // *mut T) and complex ones like this (Box<Unique<NonNull<T>>>). This relies
+  // on the standard library's layout guarantees and will break if a stateful
+  // custom allocator is placed as the first field in the RECORD_TYPE.
+  while (TREE_CODE (TREE_TYPE (main_expr)) == RECORD_TYPE)
+    {
+      tree first_field = TYPE_FIELDS (TREE_TYPE (main_expr));
+      if (first_field == NULL_TREE)
+       break;
+      main_expr = build3_loc (locus, COMPONENT_REF, TREE_TYPE (first_field),
+                             main_expr, first_field, NULL_TREE);
+    }
+  return main_expr;
+}
+} // namespace
+
 CompileExpr::CompileExpr (Context *ctx)
   : HIRCompileBase (ctx), translated (error_mark_node)
 {}
@@ -115,6 +223,26 @@ CompileExpr::visit (HIR::TupleExpr &expr)
                                                expr.get_locus ());
 }
 
+void
+CompileExpr::visit (HIR::BoxExpr &expr)
+{
+  TyTy::BaseType *inner_tyty = nullptr;
+  bool ok = ctx->get_tyctx ()->lookup_type (
+    expr.get_expr ().get_mappings ().get_hirid (), &inner_tyty);
+  rust_assert (ok);
+
+  TyTy::BaseType *box_tyty = nullptr;
+  ok = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
+                                      &box_tyty);
+  rust_assert (ok);
+
+  tree inner_expr_tree
+    = save_expr (CompileExpr::Compile (expr.get_expr (), ctx));
+
+  translated = compile_box (ctx, box_tyty, inner_tyty, inner_expr_tree,
+                           expr.get_locus ());
+}
+
 void
 CompileExpr::visit (HIR::ReturnExpr &expr)
 {
@@ -691,7 +819,21 @@ CompileExpr::visit (HIR::FieldAccessExpr &expr)
     }
 
   size_t field_index = 0;
-  if (receiver->get_kind () == TyTy::TypeKind::ADT)
+
+  if (auto inner_ty = TyTy::try_get_box_inner_type (receiver))
+    {
+      rust_assert ((*inner_ty)->get_kind () == TyTy::TypeKind::ADT);
+      TyTy::ADTType *inner_adt = static_cast<TyTy::ADTType *> (*inner_ty);
+      TyTy::VariantDef *variant = inner_adt->get_variants ().at (0);
+
+      bool ok = variant->lookup_field (expr.get_field_name ().as_string (),
+                                      nullptr, &field_index);
+      rust_assert (ok);
+
+      receiver_ref = build_box_inner_ptr (receiver_ref, expr.get_locus ());
+      receiver_ref = indirect_expression (receiver_ref, expr.get_locus ());
+    }
+  else if (receiver->get_kind () == TyTy::TypeKind::ADT)
     {
       TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver);
       rust_assert (!adt->is_enum ());
@@ -1045,6 +1187,21 @@ CompileExpr::visit (HIR::DereferenceExpr &expr)
 
   tree main_expr = CompileExpr::Compile (expr.get_expr (), ctx);
 
+  // Box<T> Dereference Hook
+  // Typechecker treats 'Box<T>' as a privileged pointer and allows
+  // explicit dereferencing.However, the backend sees Box as a normal
+  // RECORD_TYPE (struct). To solve this, if the type is the 'owned_box'
+  // lang item, we drill down.
+  TyTy::BaseType *base_tyty;
+  if (ctx->get_tyctx ()->lookup_type (
+       expr.get_expr ().get_mappings ().get_hirid (), &base_tyty))
+    {
+      if (TyTy::try_get_box_inner_type (base_tyty))
+       {
+         main_expr = build_box_inner_ptr (main_expr, expr.get_locus ());
+       }
+    }
+
   // this might be an operator overload situation lets check
   TyTy::FnType *fntype;
   bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
@@ -2253,7 +2410,17 @@ HIRCompileBase::resolve_deref_adjustment 
(Resolver::Adjustment &adjustment,
 {
   rust_assert (adjustment.is_deref_adjustment ()
               || adjustment.is_deref_mut_adjustment ());
-  rust_assert (adjustment.has_operator_overload ());
+  if (!adjustment.has_operator_overload ())
+    {
+      TyTy::BaseType *receiver = adjustment.get_actual ();
+      if (TyTy::try_get_box_inner_type (receiver))
+       {
+         tree receiver_ref = expression;
+         receiver_ref = build_box_inner_ptr (receiver_ref, locus);
+         return indirect_expression (receiver_ref, locus);
+       }
+      rust_assert (false);
+    }
 
   TyTy::FnType *lookup = adjustment.get_deref_operator_fn ();
   TyTy::BaseType *receiver = adjustment.get_actual ();
diff --git a/gcc/rust/backend/rust-compile-expr.h 
b/gcc/rust/backend/rust-compile-expr.h
index 532e140c9..90e1985c9 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -76,6 +76,7 @@ public:
   void visit (HIR::InlineAsm &expr) override;
   void visit (HIR::LlvmInlineAsm &expr) override;
   void visit (HIR::OffsetOf &expr) override;
+  void visit (HIR::BoxExpr &expr) override;
 
   // TODO
   void visit (HIR::ErrorPropagationExpr &) override {}
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc 
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
index 0fe585c23..b14036092 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
@@ -506,6 +506,15 @@ ExprStmtBuilder::visit (HIR::RangeToInclExpr &expr)
               expr.get_locus ());
 }
 
+void
+ExprStmtBuilder::visit (HIR::BoxExpr &expr)
+{
+  PlaceId result = visit_expr (expr.get_expr ());
+
+  rust_assert (result != INVALID_PLACE);
+  push_tmp_assignment (result, expr.get_locus ());
+}
+
 void
 ExprStmtBuilder::visit (HIR::ReturnExpr &ret)
 {
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h 
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
index 198f3c8fd..8d50b0715 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
@@ -95,6 +95,7 @@ protected: // Expr
   void visit (HIR::RangeFullExpr &expr) override;
   void visit (HIR::RangeFromToInclExpr &expr) override;
   void visit (HIR::RangeToInclExpr &expr) override;
+  void visit (HIR::BoxExpr &expr) override;
   void visit (HIR::ReturnExpr &ret) override;
   void visit (HIR::UnsafeBlockExpr &expr) override;
   void visit (HIR::LoopExpr &expr) override;
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h 
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
index e7de77b9f..d360508ef 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
@@ -240,6 +240,7 @@ protected: // Illegal at this position.
   void visit (HIR::RangeFromToInclExpr &expr) override { rust_unreachable (); }
   void visit (HIR::RangeToInclExpr &expr) override { rust_unreachable (); }
   void visit (HIR::ReturnExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::BoxExpr &expr) override { rust_unreachable (); }
 };
 
 } // namespace BIR
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h 
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
index 5311ba872..7c669e1cc 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
@@ -145,6 +145,7 @@ protected:
   void visit (HIR::RangeFullExpr &expr) override { rust_unreachable (); }
   void visit (HIR::RangeFromToInclExpr &expr) override { rust_unreachable (); }
   void visit (HIR::RangeToInclExpr &expr) override { rust_unreachable (); }
+  void visit (HIR::BoxExpr &expr) override { rust_unreachable (); }
   void visit (HIR::ReturnExpr &expr) override { rust_unreachable (); }
   void visit (HIR::UnsafeBlockExpr &expr) override { rust_unreachable (); }
   void visit (HIR::LoopExpr &expr) override { rust_unreachable (); }
diff --git a/gcc/rust/checks/errors/borrowck/rust-function-collector.h 
b/gcc/rust/checks/errors/borrowck/rust-function-collector.h
index a076bcaab..439f5b37b 100644
--- a/gcc/rust/checks/errors/borrowck/rust-function-collector.h
+++ b/gcc/rust/checks/errors/borrowck/rust-function-collector.h
@@ -115,6 +115,7 @@ public:
   void visit (HIR::RangeFullExpr &expr) override {}
   void visit (HIR::RangeFromToInclExpr &expr) override {}
   void visit (HIR::RangeToInclExpr &expr) override {}
+  void visit (HIR::BoxExpr &expr) override {}
   void visit (HIR::ReturnExpr &expr) override {}
   void visit (HIR::UnsafeBlockExpr &expr) override {}
   void visit (HIR::LoopExpr &expr) override {}
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc 
b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
index 868c5679b..2b4e87421 100644
--- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
@@ -588,6 +588,12 @@ PrivacyReporter::visit (HIR::RangeToInclExpr &)
   // Not handled yet
 }
 
+void
+PrivacyReporter::visit (HIR::BoxExpr &expr)
+{
+  expr.get_expr ().accept_vis (*this);
+}
+
 void
 PrivacyReporter::visit (HIR::ReturnExpr &expr)
 {
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h 
b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
index 07627b1d6..d8d37a537 100644
--- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
@@ -127,6 +127,7 @@ types
   virtual void visit (HIR::RangeFullExpr &expr);
   virtual void visit (HIR::RangeFromToInclExpr &expr);
   virtual void visit (HIR::RangeToInclExpr &expr);
+  virtual void visit (HIR::BoxExpr &expr);
   virtual void visit (HIR::ReturnExpr &expr);
   virtual void visit (HIR::UnsafeBlockExpr &expr);
   virtual void visit (HIR::LoopExpr &expr);
diff --git a/gcc/rust/checks/errors/rust-const-checker.cc 
b/gcc/rust/checks/errors/rust-const-checker.cc
index 39dd70956..7cfd81a4a 100644
--- a/gcc/rust/checks/errors/rust-const-checker.cc
+++ b/gcc/rust/checks/errors/rust-const-checker.cc
@@ -472,6 +472,12 @@ ConstChecker::visit (RangeToInclExpr &)
   // FIXME: Visit to_expr
 }
 
+void
+ConstChecker::visit (BoxExpr &expr)
+{
+  expr.get_expr ().accept_vis (*this);
+}
+
 void
 ConstChecker::visit (ReturnExpr &expr)
 {
diff --git a/gcc/rust/checks/errors/rust-const-checker.h 
b/gcc/rust/checks/errors/rust-const-checker.h
index 1dae715d8..d2c9b1bf4 100644
--- a/gcc/rust/checks/errors/rust-const-checker.h
+++ b/gcc/rust/checks/errors/rust-const-checker.h
@@ -123,6 +123,7 @@ private:
   virtual void visit (RangeFullExpr &expr) override;
   virtual void visit (RangeFromToInclExpr &expr) override;
   virtual void visit (RangeToInclExpr &expr) override;
+  virtual void visit (BoxExpr &expr) override;
   virtual void visit (ReturnExpr &expr) override;
   virtual void visit (UnsafeBlockExpr &expr) override;
   virtual void visit (LoopExpr &expr) override;
diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc 
b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
index 460ded1b2..ed1bd49ba 100644
--- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
+++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
@@ -343,6 +343,12 @@ PatternChecker::visit (RangeToInclExpr &expr)
   expr.get_to_expr ().accept_vis (*this);
 }
 
+void
+PatternChecker::visit (BoxExpr &expr)
+{
+  expr.get_expr ().accept_vis (*this);
+}
+
 void
 PatternChecker::visit (ReturnExpr &expr)
 {
diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h 
b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
index 433797ac0..eba88e306 100644
--- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
+++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
@@ -97,6 +97,7 @@ private:
   virtual void visit (RangeFullExpr &expr) override;
   virtual void visit (RangeFromToInclExpr &expr) override;
   virtual void visit (RangeToInclExpr &expr) override;
+  virtual void visit (BoxExpr &expr) override;
   virtual void visit (ReturnExpr &expr) override;
   virtual void visit (UnsafeBlockExpr &expr) override;
   virtual void visit (LoopExpr &expr) override;
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc 
b/gcc/rust/checks/errors/rust-unsafe-checker.cc
index 379cd4c9a..0868aac3a 100644
--- a/gcc/rust/checks/errors/rust-unsafe-checker.cc
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc
@@ -573,6 +573,12 @@ UnsafeChecker::visit (RangeToInclExpr &expr)
   expr.get_to_expr ().accept_vis (*this);
 }
 
+void
+UnsafeChecker::visit (BoxExpr &expr)
+{
+  expr.get_expr ().accept_vis (*this);
+}
+
 void
 UnsafeChecker::visit (ReturnExpr &expr)
 {
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h 
b/gcc/rust/checks/errors/rust-unsafe-checker.h
index ee38c7e66..c964837ec 100644
--- a/gcc/rust/checks/errors/rust-unsafe-checker.h
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.h
@@ -105,6 +105,7 @@ private:
   virtual void visit (RangeFullExpr &expr) override;
   virtual void visit (RangeFromToInclExpr &expr) override;
   virtual void visit (RangeToInclExpr &expr) override;
+  virtual void visit (BoxExpr &expr) override;
   virtual void visit (ReturnExpr &expr) override;
   virtual void visit (UnsafeBlockExpr &expr) override;
   virtual void visit (LoopExpr &expr) override;
diff --git a/gcc/rust/checks/lints/rust-lint-marklive.cc 
b/gcc/rust/checks/lints/rust-lint-marklive.cc
index 8fc81b363..796e47de4 100644
--- a/gcc/rust/checks/lints/rust-lint-marklive.cc
+++ b/gcc/rust/checks/lints/rust-lint-marklive.cc
@@ -28,6 +28,7 @@
 #include "rust-finalized-name-resolution-context.h"
 #include "rust-rib.h"
 #include "rust-system.h"
+#include "rust-tyty.h"
 
 namespace Rust {
 namespace Analysis {
@@ -199,6 +200,12 @@ MarkLive::visit (HIR::FieldAccessExpr &expr)
   if (receiver->get_kind () == TyTy::TypeKind::ADT)
     {
       adt = static_cast<TyTy::ADTType *> (receiver);
+
+      if (auto inner_ty = TyTy::try_get_box_inner_type (receiver))
+       {
+         rust_assert ((*inner_ty)->get_kind () == TyTy::TypeKind::ADT);
+         adt = static_cast<TyTy::ADTType *> (*inner_ty);
+       }
     }
   else if (receiver->get_kind () == TyTy::TypeKind::REF)
     {
diff --git a/gcc/rust/checks/lints/rust-lint-marklive.h 
b/gcc/rust/checks/lints/rust-lint-marklive.h
index 562104f67..bea28e553 100644
--- a/gcc/rust/checks/lints/rust-lint-marklive.h
+++ b/gcc/rust/checks/lints/rust-lint-marklive.h
@@ -139,6 +139,11 @@ public:
     function.get_definition ().accept_vis (*this);
   }
 
+  void visit (HIR::BoxExpr &expr) override
+  {
+    expr.get_expr ().accept_vis (*this);
+  }
+
   void visit (HIR::ReturnExpr &expr) override
   {
     if (expr.has_return_expr ())
diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc 
b/gcc/rust/hir/rust-ast-lower-expr.cc
index 47f98f3ad..f41ba8bcf 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.cc
+++ b/gcc/rust/hir/rust-ast-lower-expr.cc
@@ -192,8 +192,15 @@ ASTLoweringExpr::visit (AST::QualifiedPathInExpression 
&expr)
 void
 ASTLoweringExpr::visit (AST::BoxExpr &expr)
 {
-  rust_sorry_at (expr.get_locus (),
-                "box expression syntax is not supported yet");
+  HIR::Expr *box_expr = ASTLoweringExpr::translate (expr.get_boxed_expr ());
+
+  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::BoxExpr (mapping, expr.get_locus (),
+                                std::unique_ptr<HIR::Expr> (box_expr));
 }
 
 void
diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc
index 4e6545d02..4228788bc 100644
--- a/gcc/rust/hir/rust-hir-dump.cc
+++ b/gcc/rust/hir/rust-hir-dump.cc
@@ -1412,6 +1412,17 @@ Dump::visit (RangeToInclExpr &e)
   end ("RangeToInclExpr");
 }
 
+void
+Dump::visit (BoxExpr &e)
+{
+  begin ("BoxExpr");
+  do_mappings (e.get_mappings ());
+
+  visit_field ("box_expr", e.get_expr ());
+
+  end ("BoxExpr");
+}
+
 void
 Dump::visit (ReturnExpr &e)
 {
diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h
index e97072dfb..c6496497d 100644
--- a/gcc/rust/hir/rust-hir-dump.h
+++ b/gcc/rust/hir/rust-hir-dump.h
@@ -156,6 +156,7 @@ private:
   virtual void visit (RangeFullExpr &) override;
   virtual void visit (RangeFromToInclExpr &) override;
   virtual void visit (RangeToInclExpr &) override;
+  virtual void visit (BoxExpr &) override;
   virtual void visit (ReturnExpr &) override;
   virtual void visit (UnsafeBlockExpr &) override;
   virtual void visit (LoopExpr &) override;
diff --git a/gcc/rust/hir/tree/rust-hir-expr-abstract.h 
b/gcc/rust/hir/tree/rust-hir-expr-abstract.h
index a3d77f668..24fbffac3 100644
--- a/gcc/rust/hir/tree/rust-hir-expr-abstract.h
+++ b/gcc/rust/hir/tree/rust-hir-expr-abstract.h
@@ -75,6 +75,7 @@ public:
     InlineAsm,
     LlvmInlineAsm,
     OffsetOf,
+    Box,
   };
 
   BaseKind get_hir_kind () override final { return Node::BaseKind::EXPR; }
diff --git a/gcc/rust/hir/tree/rust-hir-expr.cc 
b/gcc/rust/hir/tree/rust-hir-expr.cc
index fe5d4b7ac..b93309cdc 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.cc
+++ b/gcc/rust/hir/tree/rust-hir-expr.cc
@@ -972,6 +972,33 @@ RangeToInclExpr::operator= (RangeToInclExpr const &other)
   return *this;
 }
 
+BoxExpr::BoxExpr (Analysis::NodeMapping mappings, location_t locus,
+                 std::unique_ptr<Expr> expr, AST::AttrVec outer_attribs)
+  : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)),
+    expr (std::move (expr)), locus (locus)
+{
+  rust_assert (this->expr != nullptr);
+}
+
+BoxExpr::BoxExpr (BoxExpr const &other)
+  : ExprWithoutBlock (other), locus (other.locus)
+{
+  rust_assert (other.expr != nullptr);
+  expr = other.expr->clone_expr ();
+}
+
+BoxExpr &
+BoxExpr::operator= (BoxExpr const &other)
+{
+  ExprWithoutBlock::operator= (other);
+
+  rust_assert (other.expr != nullptr);
+  expr = other.expr->clone_expr ();
+  locus = other.locus;
+
+  return *this;
+}
+
 ReturnExpr::ReturnExpr (Analysis::NodeMapping mappings, location_t locus,
                        std::unique_ptr<Expr> returned_expr,
                        AST::AttrVec outer_attribs)
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h 
b/gcc/rust/hir/tree/rust-hir-expr.h
index ffa2de76e..ad14764eb 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -2267,6 +2267,52 @@ protected:
   }
 };
 
+// Box expression HIR node representation
+class BoxExpr : public ExprWithoutBlock
+{
+public:
+  std::unique_ptr<Expr> expr;
+
+  location_t locus;
+
+  std::string to_string () const override;
+
+  // Constructor for BoxExpr.
+  BoxExpr (Analysis::NodeMapping mappings, location_t locus,
+          std::unique_ptr<Expr> expr,
+          AST::AttrVec outer_attribs = AST::AttrVec ());
+  // Copy constructor with clone
+  BoxExpr (BoxExpr const &other);
+
+  // Overloaded assignment operator to clone expr pointer
+  BoxExpr &operator= (BoxExpr const &other);
+
+  // move constructors
+  BoxExpr (BoxExpr &&other) = default;
+  BoxExpr &operator= (BoxExpr &&other) = default;
+
+  location_t get_locus () const override final { return locus; }
+
+  void accept_vis (HIRFullVisitor &vis) override;
+  void accept_vis (HIRExpressionVisitor &vis) override;
+
+  Expr &get_expr () { return *expr; }
+
+  ExprType get_expression_type () const override final { return ExprType::Box; 
}
+
+protected:
+  /* Use covariance to implement clone function as returning this object rather
+   * than base */
+  BoxExpr *clone_expr_impl () const override { return new BoxExpr (*this); }
+
+  /* Use covariance to implement clone function as returning this object rather
+   * than base */
+  BoxExpr *clone_expr_without_block_impl () const override
+  {
+    return new BoxExpr (*this);
+  }
+};
+
 // Return expression HIR node representation
 class ReturnExpr : public ExprWithoutBlock
 {
diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h 
b/gcc/rust/hir/tree/rust-hir-full-decls.h
index dfafee1a3..33a1986bc 100644
--- a/gcc/rust/hir/tree/rust-hir-full-decls.h
+++ b/gcc/rust/hir/tree/rust-hir-full-decls.h
@@ -106,6 +106,7 @@ class RangeToExpr;
 class RangeFullExpr;
 class RangeFromToInclExpr;
 class RangeToInclExpr;
+class BoxExpr;
 class ReturnExpr;
 class UnsafeBlockExpr;
 class LoopLabel;
diff --git a/gcc/rust/hir/tree/rust-hir-visitor.cc 
b/gcc/rust/hir/tree/rust-hir-visitor.cc
index db4b2daa8..5128ff4e1 100644
--- a/gcc/rust/hir/tree/rust-hir-visitor.cc
+++ b/gcc/rust/hir/tree/rust-hir-visitor.cc
@@ -435,6 +435,13 @@ DefaultHIRVisitor::walk (RangeToInclExpr &expr)
   expr.get_to_expr ().accept_vis (*this);
 }
 
+void
+DefaultHIRVisitor::walk (BoxExpr &expr)
+{
+  visit_outer_attrs (expr);
+  expr.get_expr ().accept_vis (*this);
+}
+
 void
 DefaultHIRVisitor::walk (ReturnExpr &expr)
 {
diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h 
b/gcc/rust/hir/tree/rust-hir-visitor.h
index e52938222..d39c84fbb 100644
--- a/gcc/rust/hir/tree/rust-hir-visitor.h
+++ b/gcc/rust/hir/tree/rust-hir-visitor.h
@@ -76,6 +76,7 @@ public:
   virtual void visit (RangeFullExpr &expr) = 0;
   virtual void visit (RangeFromToInclExpr &expr) = 0;
   virtual void visit (RangeToInclExpr &expr) = 0;
+  virtual void visit (BoxExpr &expr) = 0;
   virtual void visit (ReturnExpr &expr) = 0;
   virtual void visit (UnsafeBlockExpr &expr) = 0;
   virtual void visit (LoopExpr &expr) = 0;
@@ -245,6 +246,7 @@ public:
   virtual void visit (RangeFullExpr &node) override { walk (node); }
   virtual void visit (RangeFromToInclExpr &node) override { walk (node); }
   virtual void visit (RangeToInclExpr &node) override { walk (node); }
+  virtual void visit (BoxExpr &node) override { walk (node); }
   virtual void visit (ReturnExpr &node) override { walk (node); }
   virtual void visit (UnsafeBlockExpr &node) override { walk (node); }
   virtual void visit (LoopExpr &node) override { walk (node); }
@@ -386,6 +388,7 @@ protected:
   virtual void walk (RangeFullExpr &) final;
   virtual void walk (RangeFromToInclExpr &) final;
   virtual void walk (RangeToInclExpr &) final;
+  virtual void walk (BoxExpr &) final;
   virtual void walk (ReturnExpr &) final;
   virtual void walk (UnsafeBlockExpr &) final;
   virtual void walk (LoopExpr &) final;
@@ -527,6 +530,7 @@ public:
   virtual void visit (RangeFullExpr &) override {}
   virtual void visit (RangeFromToInclExpr &) override {}
   virtual void visit (RangeToInclExpr &) override {}
+  virtual void visit (BoxExpr &) override {}
   virtual void visit (ReturnExpr &) override {}
   virtual void visit (UnsafeBlockExpr &) override {}
   virtual void visit (LoopExpr &) override {}
@@ -759,6 +763,7 @@ public:
   virtual void visit (RangeFullExpr &expr) = 0;
   virtual void visit (RangeFromToInclExpr &expr) = 0;
   virtual void visit (RangeToInclExpr &expr) = 0;
+  virtual void visit (BoxExpr &expr) = 0;
   virtual void visit (ReturnExpr &expr) = 0;
   virtual void visit (UnsafeBlockExpr &expr) = 0;
   virtual void visit (LoopExpr &expr) = 0;
diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc
index ada104497..2b9bd5670 100644
--- a/gcc/rust/hir/tree/rust-hir.cc
+++ b/gcc/rust/hir/tree/rust-hir.cc
@@ -1308,6 +1308,15 @@ BorrowExpr::to_string () const
   return str;
 }
 
+std::string
+BoxExpr::to_string () const
+{
+  std::string str = "box ";
+  rust_assert (expr != nullptr);
+  str += expr->to_string ();
+  return str;
+}
+
 std::string
 ReturnExpr::to_string () const
 {
@@ -4249,6 +4258,12 @@ RangeToInclExpr::accept_vis (HIRFullVisitor &vis)
   vis.visit (*this);
 }
 
+void
+BoxExpr::accept_vis (HIRFullVisitor &vis)
+{
+  vis.visit (*this);
+}
+
 void
 ReturnExpr::accept_vis (HIRFullVisitor &vis)
 {
@@ -5131,6 +5146,12 @@ RangeToExpr::accept_vis (HIRExpressionVisitor &vis)
   vis.visit (*this);
 }
 
+void
+BoxExpr::accept_vis (HIRExpressionVisitor &vis)
+{
+  vis.visit (*this);
+}
+
 void
 ReturnExpr::accept_vis (HIRExpressionVisitor &vis)
 {
diff --git a/gcc/rust/typecheck/rust-autoderef.cc 
b/gcc/rust/typecheck/rust-autoderef.cc
index 0c20d41c5..4d323d628 100644
--- a/gcc/rust/typecheck/rust-autoderef.cc
+++ b/gcc/rust/typecheck/rust-autoderef.cc
@@ -330,6 +330,21 @@ AutoderefCycle::cycle (TyTy::BaseType *receiver)
       if (autoderef_flag)
        return false;
 
+      // try owned_box
+      if (auto deref_r = try_get_box_inner_type (r))
+       {
+         Adjustment box_deref (Adjustment::AdjustmentType::DEREF, r, *deref_r);
+         adjustments.push_back (box_deref);
+
+         rust_debug ("autoderef try owned_box: {%s}",
+                     (*deref_r)->debug_str ().c_str ());
+
+         if (try_autoderefed (*deref_r))
+           return true;
+
+         adjustments.pop_back ();
+       }
+
       // try unsize
       Adjustment unsize = Adjuster::try_unsize_type (r);
       if (!unsize.is_error ())
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc 
b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index c46338fb2..8ed04d635 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -184,6 +184,65 @@ TypeCheckExpr::visit (HIR::TupleExpr &expr)
                                 expr.get_locus (), fields);
 }
 
+void
+TypeCheckExpr::visit (HIR::BoxExpr &expr)
+{
+  auto owned_box_defid
+    = mappings.get_lang_item (LangItem::Kind::OWNED_BOX, expr.get_locus ());
+
+  HIR::Item *item = mappings.lookup_defid (owned_box_defid).value ();
+  TyTy::BaseType *item_type = nullptr;
+
+  bool ok
+    = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
+  rust_assert (ok);
+  if (item_type->get_kind () != TyTy::TypeKind::ADT)
+    {
+      rust_error_at (item->get_locus (), ErrorCode::E0718,
+                    "%qs language item must be applied to a struct",
+                    "owned_box");
+      return;
+    }
+  TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
+  if (!adt->is_tuple_struct () && !adt->is_struct_struct ())
+    {
+      rust_error_at (item->get_locus (), ErrorCode::E0718,
+                    "%qs language item must be applied to a struct",
+                    "owned_box");
+      return;
+    }
+
+  // this is at least one generic item
+  if (adt->get_num_substitutions () < 1)
+    {
+      rust_error_at (expr.get_locus (),
+                    "%qs lang item must be applied to a struct with at least "
+                    "1 generic argument",
+                    "owned_box");
+      return;
+    }
+
+  TyTy::BaseType *inner_ty = TypeCheckExpr::Resolve (expr.get_expr ());
+  if (inner_ty->get_kind () == TyTy::TypeKind::ERROR)
+    {
+      infered = inner_ty;
+      return;
+    }
+
+  auto lookup = SubstMapper::InferSubst (adt, expr.get_locus ());
+  rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
+  TyTy::ADTType *adt_box = static_cast<TyTy::ADTType *> (lookup);
+
+  TyTy::BaseType *infer = adt_box->get_substs ().at (0).get_param_ty ();
+
+  unify_site (expr.get_mappings ().get_hirid (),
+             TyTy::TyWithLocation (infer, expr.get_locus ()),
+             TyTy::TyWithLocation (inner_ty, expr.get_locus ()),
+             expr.get_locus ());
+
+  infered = adt_box;
+}
+
 void
 TypeCheckExpr::visit (HIR::ReturnExpr &expr)
 {
@@ -1285,6 +1344,12 @@ TypeCheckExpr::visit (HIR::FieldAccessExpr &expr)
 {
   auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ());
 
+  // Box<T> autoderef
+  if (auto try_struct_base = TyTy::try_get_box_inner_type (struct_base))
+    {
+      struct_base = *try_struct_base;
+    }
+
   // FIXME does this require autoderef here?
   if (struct_base->get_kind () == TyTy::TypeKind::REF)
     {
@@ -1728,14 +1793,21 @@ TypeCheckExpr::visit (HIR::DereferenceExpr &expr)
 
   bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF
                       || resolved_base->get_kind () == TyTy::TypeKind::POINTER;
-  if (!is_valid_type)
+
+  auto try_owned_box = TyTy::try_get_box_inner_type (resolved_base);
+
+  if (!is_valid_type && !try_owned_box)
     {
       rust_error_at (expr.get_locus (), "expected reference type got %s",
                     resolved_base->as_string ().c_str ());
       return;
     }
 
-  if (resolved_base->get_kind () == TyTy::TypeKind::REF)
+  if (try_owned_box)
+    {
+      infered = (*try_owned_box)->clone ();
+    }
+  else if (resolved_base->get_kind () == TyTy::TypeKind::REF)
     {
       TyTy::ReferenceType *ref_base
        = static_cast<TyTy::ReferenceType *> (resolved_base);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h 
b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 03157bd28..44e870697 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -80,6 +80,7 @@ public:
   void visit (HIR::InlineAsm &expr) override;
   void visit (HIR::LlvmInlineAsm &expr) override;
   void visit (HIR::OffsetOf &expr) override;
+  void visit (HIR::BoxExpr &expr) override;
 
   // TODO
   void visit (HIR::ErrorPropagationExpr &) override {}
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 9ad09a323..66f5fc5cb 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -4538,5 +4538,28 @@ DynamicObjectType::get_object_items () const
   return items;
 }
 
+WARN_UNUSED_RESULT tl::optional<BaseType *>
+try_get_box_inner_type (BaseType *base)
+{
+  if (base->get_kind () != TypeKind::ADT)
+    return tl::nullopt;
+
+  ADTType *adt = static_cast<ADTType *> (base);
+  auto owned_box_lookup
+    = Analysis::Mappings::get ().lookup_lang_item (LangItem::Kind::OWNED_BOX);
+
+  if (owned_box_lookup && adt->get_id () == *owned_box_lookup)
+    {
+      auto args = adt->get_substitution_arguments ();
+      if (!args.is_empty ())
+       {
+         auto inner = args.get_mappings ().front ().get_tyty ();
+         rust_assert (inner != nullptr);
+         return inner;
+       }
+    }
+  return tl::nullopt;
+}
+
 } // namespace TyTy
 } // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index b27de7422..b5e5f02c6 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -1960,6 +1960,9 @@ BaseType::try_as<const SubstitutionRef> () const
   return nullptr;
 }
 
+WARN_UNUSED_RESULT tl::optional<BaseType *>
+try_get_box_inner_type (BaseType *base);
+
 } // namespace TyTy
 } // namespace Rust
 
diff --git a/gcc/rust/util/rust-lang-item.cc b/gcc/rust/util/rust-lang-item.cc
index 2f7704546..91284e27b 100644
--- a/gcc/rust/util/rust-lang-item.cc
+++ b/gcc/rust/util/rust-lang-item.cc
@@ -125,6 +125,7 @@ const BiMap<std::string, LangItem::Kind> 
Rust::LangItem::lang_items = {{
   {"manually_drop", Kind::MANUALLY_DROP},
 
   {"exchange_malloc", Kind::EXCHANGE_MALLOC},
+  {"owned_box", Kind::OWNED_BOX},
 }};
 
 tl::optional<LangItem::Kind>
diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h
index 75f4090b9..d96fa9e6a 100644
--- a/gcc/rust/util/rust-lang-item.h
+++ b/gcc/rust/util/rust-lang-item.h
@@ -160,7 +160,8 @@ public:
 
     MANUALLY_DROP,
 
-    EXCHANGE_MALLOC
+    EXCHANGE_MALLOC,
+    OWNED_BOX,
   };
 
   static const BiMap<std::string, Kind> lang_items;
diff --git a/gcc/testsuite/rust/compile/box-expr.rs 
b/gcc/testsuite/rust/compile/box-expr.rs
new file mode 100644
index 000000000..979977658
--- /dev/null
+++ b/gcc/testsuite/rust/compile/box-expr.rs
@@ -0,0 +1,55 @@
+#![no_core]
+#![feature(no_core, lang_items, box_syntax)]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T: ?Sized>;
+
+pub struct NonNull<T: ?Sized> {
+    _pointer: *const T,
+}
+
+pub struct Unique<T: ?Sized> {
+    _pointer: NonNull<T>,
+    _marker: PhantomData<T>,
+}
+
+pub struct Global;
+
+#[lang = "exchange_malloc"]
+fn _exchange_malloc() -> *mut u8 {
+    0 as *mut u8
+}
+
+#[lang = "owned_box"]
+pub struct Box<T, A = Global>(Unique<T>, A);
+
+impl<T> Box<T> {
+    pub fn new(x: T) -> Self {
+        box x
+    }
+}
+
+struct NonCopyStruct {
+    id: i32,
+}
+
+impl NonCopyStruct {
+    fn get_id(&self) -> i32 {
+        self.id
+    }
+}
+
+fn main() {
+    let my_box: Box<NonCopyStruct> = Box::new(NonCopyStruct { id: 42 });
+    let _moved_val = *my_box;
+
+
+    let my_box2: Box<NonCopyStruct> = Box::new(NonCopyStruct { id: 100 });
+
+    let _val_id = my_box2.id;
+
+    let _val_method_id = my_box2.get_id();
+}
diff --git a/gcc/testsuite/rust/compile/lang-owned-box-error1.rs 
b/gcc/testsuite/rust/compile/lang-owned-box-error1.rs
new file mode 100644
index 000000000..54258ddac
--- /dev/null
+++ b/gcc/testsuite/rust/compile/lang-owned-box-error1.rs
@@ -0,0 +1,15 @@
+#![feature(no_core, lang_items, box_syntax)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "owned_box"]
+pub enum EnumBox<T> { // { dg-error "language item must be applied to a 
struct" }
+    Some(T),
+    None,
+}
+
+fn _foo() {
+    let _ = box 5;
+}
diff --git a/gcc/testsuite/rust/compile/lang-owned-box-error2.rs 
b/gcc/testsuite/rust/compile/lang-owned-box-error2.rs
new file mode 100644
index 000000000..8a57dfa69
--- /dev/null
+++ b/gcc/testsuite/rust/compile/lang-owned-box-error2.rs
@@ -0,0 +1,12 @@
+#![feature(no_core, lang_items, box_syntax)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "owned_box"]
+pub struct BadBox;
+
+fn _foo() {
+    let _ = box 5; // { dg-error "lang item must be applied to a struct with 
at least 1 generic argument" }
+}

base-commit: 95a37ea1f0e451c769072130e1893706cd2bcdad
-- 
2.54.0

Reply via email to