https://gcc.gnu.org/g:d4a4e68f56968981ec82e6b5a8de86d22a523a06
commit r17-2251-gd4a4e68f56968981ec82e6b5a8de86d22a523a06 Author: Enes Cevik <[email protected]> Date: Wed Jun 3 10:18:14 2026 +0300 gccrs: lang: Add lang owned_box and box expression 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]> Diff: --- 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 + .../errors/borrowck/rust-bir-builder-expr-stmt.cc | 9 ++ .../errors/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 + .../checks/errors/privacy/rust-privacy-reporter.cc | 6 + .../checks/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 + .../checks/errors/rust-hir-pattern-analysis.cc | 6 + gcc/rust/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 ++ gcc/rust/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(-) diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index 90e4daec413c..921b79800c1f 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 680b4fb6c5ea..9d29e8fc504b 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 37a9c702ae81..55ff3263a117 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 532e140c9ccf..90e1985c9930 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 0fe585c239a0..b1403609226b 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 198f3c8fdb17..8d50b0715f95 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 e7de77b9f957..d360508efc95 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 5311ba872f91..7c669e1cc902 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 a076bcaabf26..439f5b37b562 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 868c5679b5cf..2b4e87421de5 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 07627b1d6a62..d8d37a537873 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 39dd7095695d..7cfd81a4aa03 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 1dae715d8f3a..d2c9b1bf4317 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 460ded1b258d..ed1bd49baa67 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 433797ac035b..eba88e306b72 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 379cd4c9a381..0868aac3ae50 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 ee38c7e6649f..c964837ec1d5 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 8fc81b3631fa..796e47de467f 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 562104f671e3..bea28e55378b 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 47f98f3ad656..f41ba8bcf8cb 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 4e6545d021ff..4228788bcd44 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 e97072dfb776..c6496497d2f7 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 a3d77f668856..24fbffac309e 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 fe5d4b7ac8d8..b93309cdc79f 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 ffa2de76e7bf..ad14764eba48 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 dfafee1a35cd..33a1986bccdc 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 db4b2daa83ce..5128ff4e1ca4 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 e52938222bc4..d39c84fbb29e 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 ada104497069..2b9bd5670146 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 0c20d41c596a..4d323d62818e 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 c46338fb297a..8ed04d635fe9 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 03157bd281f5..44e870697ce0 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 9ad09a323d06..66f5fc5cb2c9 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 b27de7422c81..b5e5f02c6782 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 2f7704546575..91284e27b088 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 75f4090b97de..d96fa9e6a789 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 000000000000..979977658195 --- /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 000000000000..54258ddacb3e --- /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 000000000000..8a57dfa690f6 --- /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" } +}
