diff options
author | SimplyTheOther <simplytheother@gmail.com> | 2021-02-11 12:15:39 +0800 |
---|---|---|
committer | SimplyTheOther <simplytheother@gmail.com> | 2021-02-11 12:15:39 +0800 |
commit | 7d4ed9d38c7a636408a262f70aa69d2a34e2169d (patch) | |
tree | 915c10b77703d0ef8d074775ddea95eb0f728cab /gcc | |
parent | cfd1d805ff5921480d9badd7d215e1b1deb33aca (diff) | |
parent | 0c7d0135663b6f0d94e0ffd931366ba2b32f8b2c (diff) | |
download | gcc-7d4ed9d38c7a636408a262f70aa69d2a34e2169d.zip gcc-7d4ed9d38c7a636408a262f70aa69d2a34e2169d.tar.gz gcc-7d4ed9d38c7a636408a262f70aa69d2a34e2169d.tar.bz2 |
Merge branch 'master' of https://github.com/redbrain/gccrs
Diffstat (limited to 'gcc')
46 files changed, 1216 insertions, 461 deletions
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 14816e2..b34525e 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -1152,11 +1152,14 @@ private: Location locus; + NodeId node_id; + public: // Constructor Lifetime (LifetimeType type, std::string name = std::string (), Location locus = Location ()) - : lifetime_type (type), lifetime_name (std::move (name)), locus (locus) + : lifetime_type (type), lifetime_name (std::move (name)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} // Creates an "error" lifetime. @@ -1172,6 +1175,14 @@ public: void accept_vis (ASTVisitor &vis) override; + LifetimeType get_lifetime_type () { return lifetime_type; } + + Location get_locus () { return locus; } + + std::string get_lifetime_name () const { return lifetime_name; } + + NodeId get_node_id () const { return node_id; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index 511c30d..5366fac 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -3163,7 +3163,7 @@ public: // TODO: is this better? Or is a "vis_block" better? std::unique_ptr<Expr> &get_break_expr () { - rust_assert (break_expr != nullptr); + rust_assert (has_break_expr ()); return break_expr; } @@ -3171,6 +3171,8 @@ public: std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } void set_outer_attrs (std::vector<Attribute> new_attrs) override { outer_attrs = std::move (new_attrs); } + + Lifetime &get_label () { return label; } protected: /* Use covariance to implement clone function as returning this object rather @@ -3751,11 +3753,14 @@ class LoopLabel /*: public Node*/ Lifetime label; // or type LIFETIME_OR_LABEL Location locus; + NodeId node_id; + public: std::string as_string () const; LoopLabel (Lifetime loop_label, Location locus = Location ()) - : label (std::move (loop_label)), locus (locus) + : label (std::move (loop_label)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} // Returns whether the LoopLabel is in an error state. @@ -3765,6 +3770,10 @@ public: static LoopLabel error () { return LoopLabel (Lifetime::error ()); } Location get_locus () const { return locus; } + + Lifetime &get_lifetime () { return label; } + + NodeId get_node_id () const { return node_id; } }; // Base loop expression AST node - aka LoopExpr @@ -3823,6 +3832,8 @@ protected: public: bool has_loop_label () const { return !loop_label.is_error (); } + LoopLabel &get_loop_label () { return loop_label; } + Location get_locus () const { return locus; } Location get_locus_slow () const final override { return get_locus (); } diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index 25c9b89..288b917 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -162,6 +162,21 @@ public: return true; } + void insert_label_decl (HirId id, ::Blabel *label) + { + compiled_labels[id] = label; + } + + bool lookup_label_decl (HirId id, ::Blabel **label) + { + auto it = compiled_labels.find (id); + if (it == compiled_labels.end ()) + return false; + + *label = it->second; + return true; + } + void push_fn (::Bfunction *fn, ::Bvariable *ret_addr) { fn_stack.push_back (fncontext{fn, ret_addr}); @@ -193,6 +208,17 @@ public: return false; } + void push_loop_context (Bvariable *var) { loop_value_stack.push_back (var); } + + Bvariable *peek_loop_context () { return loop_value_stack.back (); } + + Bvariable *pop_loop_context () + { + auto back = loop_value_stack.back (); + loop_value_stack.pop_back (); + return back; + } + private: ::Backend *backend; Resolver::Resolver *resolver; @@ -205,8 +231,10 @@ private: std::map<HirId, ::Btype *> compiled_type_map; std::map<HirId, ::Bfunction *> compiled_fn_map; std::map<HirId, ::Bexpression *> compiled_consts; + std::map<HirId, ::Blabel *> compiled_labels; std::vector< ::std::vector<Bstatement *> > statements; std::vector< ::Bblock *> scope_stack; + std::vector< ::Bvariable *> loop_value_stack; // To GCC middle-end std::vector< ::Btype *> type_decls; diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index b823d29..7b25c5e 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -84,14 +84,18 @@ public: void visit (HIR::ReturnExpr &expr) { - Bexpression *compiled_expr - = CompileExpr::Compile (expr.return_expr.get (), ctx); - rust_assert (compiled_expr != nullptr); - auto fncontext = ctx->peek_fn (); std::vector<Bexpression *> retstmts; - retstmts.push_back (compiled_expr); + if (expr.has_return_expr ()) + { + Bexpression *compiled_expr + = CompileExpr::Compile (expr.return_expr.get (), ctx); + rust_assert (compiled_expr != nullptr); + + retstmts.push_back (compiled_expr); + } + auto s = ctx->get_backend ()->return_statement (fncontext.fndecl, retstmts, expr.get_locus ()); ctx->add_statement (s); @@ -417,7 +421,6 @@ public: void visit (HIR::IfExprConseqElse &expr) { - // this can be a return expression TyTy::TyBase *if_type = nullptr; if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &if_type)) @@ -427,27 +430,67 @@ public: return; } - fncontext fnctx = ctx->peek_fn (); - Bblock *enclosing_scope = ctx->peek_enclosing_scope (); - Btype *block_type = TyTyResolveCompile::compile (ctx, if_type); - - bool is_address_taken = false; - Bstatement *ret_var_stmt = nullptr; - Bvariable *tmp = ctx->get_backend ()->temporary_variable ( - fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, - expr.get_locus (), &ret_var_stmt); - ctx->add_statement (ret_var_stmt); + Bvariable *tmp = NULL; + bool needs_temp = if_type->get_kind () != TyTy::TypeKind::UNIT; + if (needs_temp) + { + fncontext fnctx = ctx->peek_fn (); + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + Btype *block_type = TyTyResolveCompile::compile (ctx, if_type); + + bool is_address_taken = false; + Bstatement *ret_var_stmt = nullptr; + tmp = ctx->get_backend ()->temporary_variable ( + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, + expr.get_locus (), &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + } auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp); ctx->add_statement (stmt); - translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); + if (tmp != NULL) + { + translated + = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); + } } void visit (HIR::IfExprConseqIf &expr) { - auto stmt = CompileConditionalBlocks::compile (&expr, ctx, nullptr); + TyTy::TyBase *if_type = nullptr; + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), + &if_type)) + { + rust_error_at (expr.get_locus (), + "failed to lookup type of IfExprConseqElse"); + return; + } + + Bvariable *tmp = NULL; + bool needs_temp = if_type->get_kind () != TyTy::TypeKind::UNIT; + if (needs_temp) + { + fncontext fnctx = ctx->peek_fn (); + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + Btype *block_type = TyTyResolveCompile::compile (ctx, if_type); + + bool is_address_taken = false; + Bstatement *ret_var_stmt = nullptr; + tmp = ctx->get_backend ()->temporary_variable ( + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, + expr.get_locus (), &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + } + + auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp); ctx->add_statement (stmt); + + if (tmp != NULL) + { + translated + = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); + } } void visit (HIR::BlockExpr &expr) @@ -460,22 +503,31 @@ public: return; } - fncontext fnctx = ctx->peek_fn (); - Bblock *enclosing_scope = ctx->peek_enclosing_scope (); - Btype *block_type = TyTyResolveCompile::compile (ctx, block_tyty); - - bool is_address_taken = false; - Bstatement *ret_var_stmt = nullptr; - Bvariable *tmp = ctx->get_backend ()->temporary_variable ( - fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, - expr.get_locus (), &ret_var_stmt); - ctx->add_statement (ret_var_stmt); + Bvariable *tmp = NULL; + bool needs_temp = block_tyty->get_kind () != TyTy::TypeKind::UNIT; + if (needs_temp) + { + fncontext fnctx = ctx->peek_fn (); + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + Btype *block_type = TyTyResolveCompile::compile (ctx, block_tyty); + + bool is_address_taken = false; + Bstatement *ret_var_stmt = nullptr; + tmp = ctx->get_backend ()->temporary_variable ( + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, + expr.get_locus (), &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + } auto code_block = CompileBlock::compile (&expr, ctx, tmp); auto block_stmt = ctx->get_backend ()->block_statement (code_block); ctx->add_statement (block_stmt); - translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); + if (tmp != NULL) + { + translated + = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); + } } void visit (HIR::StructExprStructFields &struct_expr) @@ -532,6 +584,127 @@ public: translated = ResolvePathRef::Compile (&expr, ctx); } + void visit (HIR::LoopExpr &expr) + { + TyTy::TyBase *block_tyty = nullptr; + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), + &block_tyty)) + { + rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr"); + return; + } + + fncontext fnctx = ctx->peek_fn (); + Bvariable *tmp = NULL; + bool needs_temp = block_tyty->get_kind () != TyTy::TypeKind::UNIT; + if (needs_temp) + { + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + Btype *block_type = TyTyResolveCompile::compile (ctx, block_tyty); + + bool is_address_taken = false; + Bstatement *ret_var_stmt = nullptr; + tmp = ctx->get_backend ()->temporary_variable ( + fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, + expr.get_locus (), &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + ctx->push_loop_context (tmp); + } + + if (expr.has_loop_label ()) + { + HIR::LoopLabel &loop_label = expr.get_loop_label (); + Blabel *label + = ctx->get_backend ()->label (fnctx.fndecl, + loop_label.get_lifetime ().get_name (), + loop_label.get_locus ()); + Bstatement *label_decl + = ctx->get_backend ()->label_definition_statement (label); + ctx->add_statement (label_decl); + ctx->insert_label_decl ( + loop_label.get_lifetime ().get_mappings ().get_hirid (), label); + } + + Bblock *code_block + = CompileBlock::compile (expr.get_loop_block ().get (), ctx, nullptr); + Bexpression *loop_expr + = ctx->get_backend ()->loop_expression (code_block, expr.get_locus ()); + Bstatement *loop_stmt + = ctx->get_backend ()->expression_statement (fnctx.fndecl, loop_expr); + ctx->add_statement (loop_stmt); + + if (tmp != NULL) + { + ctx->pop_loop_context (); + translated + = ctx->get_backend ()->var_expression (tmp, expr.get_locus ()); + } + } + + void visit (HIR::BreakExpr &expr) + { + if (expr.has_break_expr ()) + { + fncontext fnctx = ctx->peek_fn (); + Bexpression *compiled_expr + = CompileExpr::Compile (expr.get_expr ().get (), ctx); + + Bvariable *loop_result_holder = ctx->peek_loop_context (); + Bexpression *result_reference = ctx->get_backend ()->var_expression ( + loop_result_holder, expr.get_expr ()->get_locus_slow ()); + + Bstatement *assignment = ctx->get_backend ()->assignment_statement ( + fnctx.fndecl, result_reference, compiled_expr, expr.get_locus ()); + ctx->add_statement (assignment); + } + + if (expr.has_label ()) + { + NodeId resolved_node_id = UNKNOWN_NODEID; + if (!ctx->get_resolver ()->lookup_resolved_label ( + expr.get_label ().get_mappings ().get_nodeid (), + &resolved_node_id)) + { + rust_error_at ( + expr.get_label ().get_locus (), + "failed to resolve compiled label for label %s", + expr.get_label ().get_mappings ().as_string ().c_str ()); + return; + } + + HirId ref = UNKNOWN_HIRID; + if (!ctx->get_mappings ()->lookup_node_to_hir ( + expr.get_mappings ().get_crate_num (), resolved_node_id, &ref)) + { + rust_fatal_error (expr.get_locus (), + "reverse lookup label failure"); + return; + } + + Blabel *label = nullptr; + if (!ctx->lookup_label_decl (ref, &label)) + { + rust_error_at (expr.get_label ().get_locus (), + "failed to lookup compiled label"); + return; + } + + Bstatement *goto_label + = ctx->get_backend ()->goto_statement (label, expr.get_locus ()); + ctx->add_statement (goto_label); + } + else + { + fncontext fnctx = ctx->peek_fn (); + Bexpression *exit_expr = ctx->get_backend ()->exit_expression ( + ctx->get_backend ()->boolean_constant_expression (true), + expr.get_locus ()); + Bstatement *break_stmt + = ctx->get_backend ()->expression_statement (fnctx.fndecl, exit_expr); + ctx->add_statement (break_stmt); + } + } + private: CompileExpr (Context *ctx) : HIRCompileBase (ctx), translated (nullptr) {} diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index 0b83c72..dd87d45 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -53,33 +53,9 @@ CompileCrate::go () void CompileExpr::visit (HIR::CallExpr &expr) { - // this can be a function call or it can be a constructor for a tuple struct - Bexpression *fn = ResolvePathRef::Compile (expr.get_fnexpr (), ctx); - if (fn != nullptr) + Btype *type = ResolvePathType::Compile (expr.get_fnexpr (), ctx); + if (type != nullptr) { - std::vector<Bexpression *> args; - expr.iterate_params ([&] (HIR::Expr *p) mutable -> bool { - Bexpression *compiled_expr = CompileExpr::Compile (p, ctx); - rust_assert (compiled_expr != nullptr); - args.push_back (compiled_expr); - return true; - }); - - auto fncontext = ctx->peek_fn (); - translated - = ctx->get_backend ()->call_expression (fncontext.fndecl, fn, args, - nullptr, expr.get_locus ()); - } - else - { - Btype *type = ResolvePathType::Compile (expr.get_fnexpr (), ctx); - if (type == nullptr) - { - rust_fatal_error (expr.get_locus (), - "failed to lookup type associated with call"); - return; - } - // this assumes all fields are in order from type resolution and if a base // struct was specified those fields are filed via accesors std::vector<Bexpression *> vals; @@ -93,6 +69,24 @@ CompileExpr::visit (HIR::CallExpr &expr) = ctx->get_backend ()->constructor_expression (type, vals, expr.get_locus ()); } + else + { + // must be a call to a function + Bexpression *fn = CompileExpr::Compile (expr.get_fnexpr (), ctx); + + std::vector<Bexpression *> args; + expr.iterate_params ([&] (HIR::Expr *p) mutable -> bool { + Bexpression *compiled_expr = CompileExpr::Compile (p, ctx); + rust_assert (compiled_expr != nullptr); + args.push_back (compiled_expr); + return true; + }); + + auto fncontext = ctx->peek_fn (); + translated + = ctx->get_backend ()->call_expression (fncontext.fndecl, fn, args, + nullptr, expr.get_locus ()); + } } void @@ -242,23 +236,28 @@ CompileBlock::visit (HIR::BlockExpr &expr) // the previous passes will ensure this is a valid return // dead code elimination should remove any bad trailing expressions Bexpression *compiled_expr = CompileExpr::Compile (expr.expr.get (), ctx); - rust_assert (compiled_expr != nullptr); - - if (result == nullptr) - { - Bstatement *final_stmt - = ctx->get_backend ()->expression_statement (fnctx.fndecl, - compiled_expr); - ctx->add_statement (final_stmt); - } - else + if (compiled_expr != nullptr) { - Bexpression *result_reference = ctx->get_backend ()->var_expression ( - result, expr.get_final_expr ()->get_locus_slow ()); - - Bstatement *assignment = ctx->get_backend ()->assignment_statement ( - fnctx.fndecl, result_reference, compiled_expr, expr.get_locus ()); - ctx->add_statement (assignment); + if (result == nullptr) + { + Bstatement *final_stmt + = ctx->get_backend ()->expression_statement (fnctx.fndecl, + compiled_expr); + ctx->add_statement (final_stmt); + } + else + { + Bexpression *result_reference + = ctx->get_backend ()->var_expression ( + result, expr.get_final_expr ()->get_locus_slow ()); + + Bstatement *assignment + = ctx->get_backend ()->assignment_statement (fnctx.fndecl, + result_reference, + compiled_expr, + expr.get_locus ()); + ctx->add_statement (assignment); + } } } diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index 093129e..beeff87 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -243,6 +243,47 @@ protected: ASTLoweringBase () : mappings (Analysis::Mappings::get ()) {} Analysis::Mappings *mappings; + + HIR::Lifetime lower_lifetime (AST::Lifetime &lifetime) + { + HIR::Lifetime::LifetimeType type = HIR::Lifetime::LifetimeType::NAMED; + switch (lifetime.get_lifetime_type ()) + { + case AST::Lifetime::LifetimeType::NAMED: + type = HIR::Lifetime::LifetimeType::NAMED; + break; + case AST::Lifetime::LifetimeType::STATIC: + type = HIR::Lifetime::LifetimeType::STATIC; + break; + case AST::Lifetime::LifetimeType::WILDCARD: + type = HIR::Lifetime::LifetimeType::WILDCARD; + break; + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, lifetime.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + mappings->insert_node_to_hir (mapping.get_crate_num (), + mapping.get_nodeid (), mapping.get_hirid ()); + + return HIR::Lifetime (mapping, type, lifetime.get_lifetime_name (), + lifetime.get_locus ()); + } + + HIR::LoopLabel lower_loop_label (AST::LoopLabel &loop_label) + { + HIR::Lifetime life = lower_lifetime (loop_label.get_lifetime ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, loop_label.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + mappings->insert_node_to_hir (mapping.get_crate_num (), + mapping.get_nodeid (), mapping.get_hirid ()); + + return HIR::LoopLabel (mapping, std::move (life), loop_label.get_locus ()); + } }; } // namespace HIR diff --git a/gcc/rust/hir/rust-ast-lower-block.h b/gcc/rust/hir/rust-ast-lower-block.h index f81a242..c945042 100644 --- a/gcc/rust/hir/rust-ast-lower-block.h +++ b/gcc/rust/hir/rust-ast-lower-block.h @@ -134,6 +134,27 @@ public: translated = ASTLoweringBlock::translate (&expr, &terminated); } + void visit (AST::LoopExpr &expr) + { + std::vector<HIR::Attribute> outer_attribs; + HIR::BlockExpr *loop_block + = ASTLoweringBlock::translate (expr.get_loop_block ().get (), + &terminated); + + HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::LoopExpr (mapping, + std::unique_ptr<HIR::BlockExpr> (loop_block), + expr.get_locus (), std::move (loop_label), + std::move (outer_attribs)); + } + private: ASTLoweringExprWithBlock () : ASTLoweringBase (), translated (nullptr), terminated (false) diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index cd1863f..e10448f 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -74,8 +74,6 @@ public: return compiler.translated; } - ~ASTLowerPathInExpression () {} - void visit (AST::PathInExpression &expr) { std::vector<HIR::PathExprSegment> path_segments; @@ -697,9 +695,35 @@ public: std::move (outer_attribs), expr.get_locus ()); } + void visit (AST::LoopExpr &expr) + { + translated = ASTLoweringExprWithBlock::translate (&expr, &terminated); + } + + void visit (AST::BreakExpr &expr) + { + std::vector<HIR::Attribute> outer_attribs; + HIR::Lifetime break_label = lower_lifetime (expr.get_label ()); + HIR::Expr *break_expr + = expr.has_break_expr () + ? ASTLoweringExpr::translate (expr.get_break_expr ().get ()) + : nullptr; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::BreakExpr (mapping, expr.get_locus (), + std ::move (break_label), + std::unique_ptr<HIR::Expr> (break_expr), + std::move (outer_attribs)); + } + private: ASTLoweringExpr () - : translated (nullptr), translated_array_elems (nullptr), terminated (false) + : ASTLoweringBase (), translated (nullptr), + translated_array_elems (nullptr), terminated (false) {} HIR::Expr *translated; diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index d4af3c2..e92e059 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -2712,8 +2712,7 @@ public: bool has_label () const { return !label.is_error (); } // Constructor for a ContinueExpr with a label. - ContinueExpr (Analysis::NodeMapping mappings, Location locus, - Lifetime label = Lifetime::error (), + ContinueExpr (Analysis::NodeMapping mappings, Location locus, Lifetime label, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), @@ -2765,7 +2764,7 @@ public: // Constructor for a break expression BreakExpr (Analysis::NodeMapping mappings, Location locus, - Lifetime break_label = Lifetime::error (), + Lifetime break_label, std::unique_ptr<Expr> expr_in_break = nullptr, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), @@ -2803,6 +2802,10 @@ public: void accept_vis (HIRVisitor &vis) override; + Lifetime &get_label () { return label; } + + std::unique_ptr<Expr> &get_expr () { return break_expr; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3266,20 +3269,23 @@ class LoopLabel /*: public Node*/ Location locus; + Analysis::NodeMapping mappings; + public: std::string as_string () const; - LoopLabel (Lifetime loop_label, Location locus = Location ()) - : label (std::move (loop_label)), locus (locus) + LoopLabel (Analysis::NodeMapping mapping, Lifetime loop_label, Location locus) + : label (std::move (loop_label)), locus (locus), mappings (mapping) {} // Returns whether the LoopLabel is in an error state. bool is_error () const { return label.is_error (); } - // Creates an error state LoopLabel. - static LoopLabel error () { return LoopLabel (Lifetime::error ()); } - Location get_locus () const { return locus; } + + Analysis::NodeMapping &get_mappings () { return mappings; } + + Lifetime &get_lifetime () { return label; } }; // Base loop expression HIR node - aka LoopExpr @@ -3299,7 +3305,7 @@ protected: // Constructor for BaseLoopExpr BaseLoopExpr (Analysis::NodeMapping mappings, std::unique_ptr<BlockExpr> loop_block, Location locus, - LoopLabel loop_label = LoopLabel::error (), + LoopLabel loop_label, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : ExprWithBlock (std::move (mappings), std::move (outer_attribs)), @@ -3334,6 +3340,10 @@ public: Location get_locus () const { return locus; } Location get_locus_slow () const override { return get_locus (); } + + std::unique_ptr<HIR::BlockExpr> &get_loop_block () { return loop_block; }; + + LoopLabel &get_loop_label () { return loop_label; } }; // 'Loop' expression (i.e. the infinite loop) HIR node @@ -3345,7 +3355,7 @@ public: // Constructor for LoopExpr LoopExpr (Analysis::NodeMapping mappings, std::unique_ptr<BlockExpr> loop_block, Location locus, - LoopLabel loop_label = LoopLabel::error (), + LoopLabel loop_label, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : BaseLoopExpr (std::move (mappings), std::move (loop_block), locus, std::move (loop_label), std::move (outer_attribs)) @@ -3378,7 +3388,7 @@ public: WhileLoopExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> loop_condition, std::unique_ptr<BlockExpr> loop_block, Location locus, - LoopLabel loop_label = LoopLabel::error (), + LoopLabel loop_label, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : BaseLoopExpr (std::move (mappings), std::move (loop_block), locus, @@ -3440,7 +3450,7 @@ public: std::vector<std::unique_ptr<Pattern> > match_arm_patterns, std::unique_ptr<Expr> condition, std::unique_ptr<BlockExpr> loop_block, Location locus, - LoopLabel loop_label = LoopLabel::error (), + LoopLabel loop_label, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : BaseLoopExpr (std::move (mappings), std::move (loop_block), locus, @@ -3513,7 +3523,7 @@ public: std::unique_ptr<Pattern> loop_pattern, std::unique_ptr<Expr> iterator_expr, std::unique_ptr<BlockExpr> loop_body, Location locus, - LoopLabel loop_label = LoopLabel::error (), + LoopLabel loop_label, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : BaseLoopExpr (std::move (mappings), std::move (loop_body), locus, std::move (loop_label), std::move (outer_attribs)), diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index 4ab23e1..c0d6d0f 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -324,7 +324,8 @@ public: // Type-based self parameter (not ref, no lifetime) SelfParam (Analysis::NodeMapping mappings, std::unique_ptr<Type> type, bool is_mut, Location locus) - : has_ref (false), is_mut (is_mut), lifetime (Lifetime::error ()), + : has_ref (false), is_mut (is_mut), + lifetime (Lifetime (mappings, Lifetime::LifetimeType::NAMED, "", locus)), type (std::move (type)), locus (locus), mappings (mappings) {} diff --git a/gcc/rust/hir/tree/rust-hir-type.h b/gcc/rust/hir/tree/rust-hir-type.h index ebed119..746e3e2 100644 --- a/gcc/rust/hir/tree/rust-hir-type.h +++ b/gcc/rust/hir/tree/rust-hir-type.h @@ -531,7 +531,7 @@ public: // Constructor ReferenceType (Analysis::NodeMapping mappings, bool is_mut, std::unique_ptr<TypeNoBounds> type_no_bounds, Location locus, - Lifetime lifetime = Lifetime::error ()) + Lifetime lifetime) : TypeNoBounds (mappings), lifetime (std::move (lifetime)), has_mut (is_mut), type (std::move (type_no_bounds)), locus (locus) {} diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h index 6fd6297..1567215 100644 --- a/gcc/rust/hir/tree/rust-hir.h +++ b/gcc/rust/hir/tree/rust-hir.h @@ -1060,16 +1060,16 @@ private: Location locus; + Analysis::NodeMapping mappings; + public: // Constructor - Lifetime (LifetimeType type, std::string name = std::string (), - Location locus = Location ()) - : lifetime_type (type), lifetime_name (std::move (name)), locus (locus) + Lifetime (Analysis::NodeMapping mapping, LifetimeType type, std::string name, + Location locus) + : lifetime_type (type), lifetime_name (std::move (name)), locus (locus), + mappings (mapping) {} - // Creates an "error" lifetime. - static Lifetime error () { return Lifetime (NAMED, std::string ("")); } - // Returns true if the lifetime is in an error state. bool is_error () const { @@ -1080,6 +1080,14 @@ public: void accept_vis (HIRVisitor &vis) override; + std::string get_name () const { return lifetime_name; } + + LifetimeType get_lifetime_type () const { return lifetime_type; } + + Location get_locus () const { return locus; } + + Analysis::NodeMapping get_mappings () const { return mappings; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1133,12 +1141,6 @@ public: // Returns whether the lifetime param has an outer attribute. bool has_outer_attribute () const { return !outer_attr.is_empty (); } - // Creates an error state lifetime param. - static LifetimeParam create_error () - { - return LifetimeParam (Lifetime::error ()); - } - // Returns whether the lifetime param is in an error state. bool is_error () const { return lifetime.is_error (); } diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 4a9f3a3..437a7b5 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -386,6 +386,8 @@ Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token) return LBP_MOD_ASSIG; case AMP_EQ: return LBP_AMP_ASSIG; + case PIPE_EQ: + return LBP_PIPE_ASSIG; case CARET_EQ: return LBP_CARET_ASSIG; case LEFT_SHIFT_EQ: @@ -7396,8 +7398,10 @@ Parser<ManagedTokenSource>::parse_return_expr ( } // parse expression to return, if it exists - std::unique_ptr<AST::Expr> returned_expr = parse_expr (); - // FIXME: ensure this doesn't ruin the middle of any expressions or anything + ParseRestrictions restrictions; + restrictions.expr_can_be_null = true; + std::unique_ptr<AST::Expr> returned_expr + = parse_expr (std::vector<AST::Attribute> (), restrictions); return std::unique_ptr<AST::ReturnExpr> ( new AST::ReturnExpr (std::move (returned_expr), std::move (outer_attrs), @@ -7433,7 +7437,10 @@ Parser<ManagedTokenSource>::parse_break_expr ( } // parse break return expression if it exists - std::unique_ptr<AST::Expr> return_expr = parse_expr (); + ParseRestrictions restrictions; + restrictions.expr_can_be_null = true; + std::unique_ptr<AST::Expr> return_expr + = parse_expr (std::vector<AST::Attribute> (), restrictions); return std::unique_ptr<AST::BreakExpr> ( new AST::BreakExpr (std::move (label), std::move (return_expr), @@ -7502,10 +7509,23 @@ Parser<ManagedTokenSource>::parse_loop_label () template <typename ManagedTokenSource> std::unique_ptr<AST::IfExpr> Parser<ManagedTokenSource>::parse_if_expr ( - std::vector<AST::Attribute> outer_attrs) + std::vector<AST::Attribute> outer_attrs, bool pratt_parse) { - Location locus = lexer.peek_token ()->get_locus (); - skip_token (IF); + // TODO: make having outer attributes an error? + Location locus = Linemap::unknown_location (); + if (!pratt_parse) + { + locus = lexer.peek_token ()->get_locus (); + if (!skip_token (IF)) + { + skip_after_end_block (); + return nullptr; + } + } + else + { + locus = lexer.peek_token ()->get_locus () - 1; + } // detect accidental if let if (lexer.peek_token ()->get_id () == LET) @@ -7639,10 +7659,23 @@ Parser<ManagedTokenSource>::parse_if_expr ( template <typename ManagedTokenSource> std::unique_ptr<AST::IfLetExpr> Parser<ManagedTokenSource>::parse_if_let_expr ( - std::vector<AST::Attribute> outer_attrs) + std::vector<AST::Attribute> outer_attrs, bool pratt_parse) { - Location locus = lexer.peek_token ()->get_locus (); - skip_token (IF); + // TODO: make having outer attributes an error? + Location locus = Linemap::unknown_location (); + if (!pratt_parse) + { + locus = lexer.peek_token ()->get_locus (); + if (!skip_token (IF)) + { + skip_after_end_block (); + return nullptr; + } + } + else + { + locus = lexer.peek_token ()->get_locus () - 1; + } // detect accidental if expr parsed as if let expr if (lexer.peek_token ()->get_id () != LET) @@ -7802,14 +7835,30 @@ Parser<ManagedTokenSource>::parse_if_let_expr ( template <typename ManagedTokenSource> std::unique_ptr<AST::LoopExpr> Parser<ManagedTokenSource>::parse_loop_expr ( - std::vector<AST::Attribute> outer_attrs, AST::LoopLabel label) + std::vector<AST::Attribute> outer_attrs, AST::LoopLabel label, + bool pratt_parse) { Location locus = Linemap::unknown_location (); - if (label.is_error ()) - locus = lexer.peek_token ()->get_locus (); + if (!pratt_parse) + { + if (label.is_error ()) + locus = lexer.peek_token ()->get_locus (); + else + locus = label.get_locus (); + + if (!skip_token (LOOP)) + { + skip_after_end_block (); + return nullptr; + } + } else - locus = label.get_locus (); - skip_token (LOOP); + { + if (label.is_error ()) + locus = lexer.peek_token ()->get_locus () - 1; + else + locus = label.get_locus (); + } // parse loop body, which is required std::unique_ptr<AST::BlockExpr> loop_body = parse_block_expr (); @@ -12390,6 +12439,21 @@ Parser<ManagedTokenSource>::null_denotation ( case LEFT_CURLY: // ok - this is an expression with block for once. return parse_block_expr (std::move (outer_attrs), true); + case IF: + // if or if let, so more lookahead to find out + if (lexer.peek_token (1)->get_id () == LET) + { + // if let expr + return parse_if_let_expr (std::move (outer_attrs), true); + } + else + { + // if expr + return parse_if_expr (std::move (outer_attrs), true); + } + case LOOP: + return parse_loop_expr (std::move (outer_attrs), AST::LoopLabel::error (), + true); case MATCH_TOK: // also an expression with block return parse_match_expr (std::move (outer_attrs), true); @@ -12397,9 +12461,10 @@ Parser<ManagedTokenSource>::null_denotation ( // array definition expr (not indexing) return parse_array_expr (std::move (outer_attrs), true); default: - rust_error_at (tok->get_locus (), - "found unexpected token %qs in null denotation", - tok->get_token_description ()); + if (!restrictions.expr_can_be_null) + rust_error_at (tok->get_locus (), + "found unexpected token %qs in null denotation", + tok->get_token_description ()); return nullptr; } } @@ -14415,7 +14480,7 @@ Parser<ManagedTokenSource>::done_end () // Dumps lexer output to stderr. template <typename ManagedTokenSource> void -Parser<ManagedTokenSource>::debug_dump_lex_output () +Parser<ManagedTokenSource>::debug_dump_lex_output (std::ostream &out) { /* TODO: a better implementation of "lexer dump" (as in dump what was actually * tokenised) would actually be to "write" a token to a file every time @@ -14426,6 +14491,9 @@ Parser<ManagedTokenSource>::debug_dump_lex_output () while (true) { + if (tok->get_id () == Rust::END_OF_FILE) + break; + bool has_text = tok->get_id () == Rust::IDENTIFIER || tok->get_id () == Rust::INT_LITERAL || tok->get_id () == Rust::FLOAT_LITERAL @@ -14436,16 +14504,13 @@ Parser<ManagedTokenSource>::debug_dump_lex_output () Location loc = tok->get_locus (); - fprintf (stderr, "<id=%s%s, %s\n", tok->token_id_to_str (), - has_text ? (std::string (", text=") + tok->get_str () - + std::string (", typehint=") - + std::string (tok->get_type_hint_str ())) - .c_str () - : "", - lexer.get_line_map ()->to_string (loc).c_str ()); - - if (tok->get_id () == Rust::END_OF_FILE) - break; + out << "<id="; + out << tok->token_id_to_str (); + out << has_text ? (std::string (", text=") + tok->get_str () + + std::string (", typehint=") + + std::string (tok->get_type_hint_str ())) + : ""; + out << lexer.get_line_map ()->to_string (loc); lexer.skip_token (); tok = lexer.peek_token (); @@ -14455,9 +14520,9 @@ Parser<ManagedTokenSource>::debug_dump_lex_output () // Parses crate and dumps AST to stderr, recursively. template <typename ManagedTokenSource> void -Parser<ManagedTokenSource>::debug_dump_ast_output (AST::Crate &crate) +Parser<ManagedTokenSource>::debug_dump_ast_output (AST::Crate &crate, + std::ostream &out) { - // print crate "as string", which then calls each item as string, etc. - fprintf (stderr, "%s", crate.as_string ().c_str ()); + out << crate.as_string (); } } // namespace Rust diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 2778ec7..e691c9e 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -82,6 +82,7 @@ struct ParseRestrictions /* Whether the expression was entered from a unary expression - prevents stuff * like struct exprs being parsed from a dereference. */ bool entered_from_unary = false; + bool expr_can_be_null = false; }; // Parser implementation for gccrs. @@ -166,22 +167,30 @@ private: parse_generic_params_in_angles (); std::vector<std::unique_ptr<AST::GenericParam> > parse_generic_params (); template <typename EndTokenPred> - std::vector<std::unique_ptr<AST::GenericParam> > parse_generic_params (EndTokenPred is_end_token); + std::vector<std::unique_ptr<AST::GenericParam> > + parse_generic_params (EndTokenPred is_end_token); std::vector<std::unique_ptr<AST::LifetimeParam> > parse_lifetime_params (); template <typename EndTokenPred> - std::vector<std::unique_ptr<AST::LifetimeParam> > parse_lifetime_params (EndTokenPred is_end_token); + std::vector<std::unique_ptr<AST::LifetimeParam> > + parse_lifetime_params (EndTokenPred is_end_token); std::vector<AST::LifetimeParam> parse_lifetime_params_objs (); template <typename EndTokenPred> - std::vector<AST::LifetimeParam> parse_lifetime_params_objs (EndTokenPred is_end_token); + std::vector<AST::LifetimeParam> + parse_lifetime_params_objs (EndTokenPred is_end_token); template <typename ParseFunction, typename EndTokenPred> - auto parse_non_ptr_sequence (ParseFunction parsing_function, EndTokenPred is_end_token, std::string error_msg = "failed to parse generic param in generic params") -> std::vector<decltype(parsing_function ())>; + auto parse_non_ptr_sequence ( + ParseFunction parsing_function, EndTokenPred is_end_token, + std::string error_msg = "failed to parse generic param in generic params") + -> std::vector<decltype (parsing_function ())>; AST::LifetimeParam parse_lifetime_param (); std::vector<std::unique_ptr<AST::TypeParam> > parse_type_params (); template <typename EndTokenPred> - std::vector<std::unique_ptr<AST::TypeParam> > parse_type_params (EndTokenPred is_end_token); + std::vector<std::unique_ptr<AST::TypeParam> > + parse_type_params (EndTokenPred is_end_token); std::unique_ptr<AST::TypeParam> parse_type_param (); template <typename EndTokenPred> - std::vector<AST::FunctionParam> parse_function_params (EndTokenPred is_end_token); + std::vector<AST::FunctionParam> + parse_function_params (EndTokenPred is_end_token); AST::FunctionParam parse_function_param (); std::unique_ptr<AST::Type> parse_function_return_type (); AST::WhereClause parse_where_clause (); @@ -192,7 +201,8 @@ private: parse_type_bound_where_clause_item (); std::vector<AST::LifetimeParam> parse_for_lifetimes (); template <typename EndTokenPred> - std::vector<std::unique_ptr<AST::TypeParamBound> > parse_type_param_bounds (EndTokenPred is_end_token); + std::vector<std::unique_ptr<AST::TypeParamBound> > + parse_type_param_bounds (EndTokenPred is_end_token); std::vector<std::unique_ptr<AST::TypeParamBound> > parse_type_param_bounds (); std::unique_ptr<AST::TypeParamBound> parse_type_param_bound (); std::unique_ptr<AST::TraitBound> parse_trait_bound (); @@ -215,7 +225,8 @@ private: parse_enum (AST::Visibility vis, std::vector<AST::Attribute> outer_attrs); std::vector<std::unique_ptr<AST::EnumItem> > parse_enum_items (); template <typename EndTokenPred> - std::vector<std::unique_ptr<AST::EnumItem> > parse_enum_items (EndTokenPred is_end_token); + std::vector<std::unique_ptr<AST::EnumItem> > + parse_enum_items (EndTokenPred is_end_token); std::unique_ptr<AST::EnumItem> parse_enum_item (); std::unique_ptr<AST::Union> parse_union (AST::Visibility vis, std::vector<AST::Attribute> outer_attrs); @@ -247,8 +258,9 @@ private: parse_extern_block (AST::Visibility vis, std::vector<AST::Attribute> outer_attrs); std::unique_ptr<AST::ExternalItem> parse_external_item (); - AST::NamedFunctionParam parse_named_function_param ( - std::vector<AST::Attribute> outer_attrs = std::vector<AST::Attribute> ()); + AST::NamedFunctionParam + parse_named_function_param (std::vector<AST::Attribute> outer_attrs + = std::vector<AST::Attribute> ()); AST::Method parse_method (); // Expression-related (Pratt parsed) @@ -272,9 +284,11 @@ private: = std::vector<AST::Attribute> (), ParseRestrictions restrictions = ParseRestrictions ()); std::unique_ptr<AST::ArithmeticOrLogicalExpr> - parse_arithmetic_or_logical_expr (const_TokenPtr tok, std::unique_ptr<AST::Expr> left, - std::vector<AST::Attribute> outer_attrs, AST::ArithmeticOrLogicalExpr::ExprType expr_type, - ParseRestrictions restrictions = ParseRestrictions ()); + parse_arithmetic_or_logical_expr ( + const_TokenPtr tok, std::unique_ptr<AST::Expr> left, + std::vector<AST::Attribute> outer_attrs, + AST::ArithmeticOrLogicalExpr::ExprType expr_type, + ParseRestrictions restrictions = ParseRestrictions ()); std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_binary_plus_expr (const_TokenPtr tok, std::unique_ptr<AST::Expr> left, std::vector<AST::Attribute> outer_attrs, @@ -368,10 +382,11 @@ private: parse_assig_expr (const_TokenPtr tok, std::unique_ptr<AST::Expr> left, std::vector<AST::Attribute> outer_attrs, ParseRestrictions restrictions = ParseRestrictions ()); - std::unique_ptr<AST::CompoundAssignmentExpr> - parse_compound_assignment_expr (const_TokenPtr tok, std::unique_ptr<AST::Expr> left, - std::vector<AST::Attribute> outer_attrs, AST::CompoundAssignmentExpr::ExprType expr_type, - ParseRestrictions restrictions = ParseRestrictions ()); + std::unique_ptr<AST::CompoundAssignmentExpr> parse_compound_assignment_expr ( + const_TokenPtr tok, std::unique_ptr<AST::Expr> left, + std::vector<AST::Attribute> outer_attrs, + AST::CompoundAssignmentExpr::ExprType expr_type, + ParseRestrictions restrictions = ParseRestrictions ()); std::unique_ptr<AST::CompoundAssignmentExpr> parse_plus_assig_expr (const_TokenPtr tok, std::unique_ptr<AST::Expr> left, std::vector<AST::Attribute> outer_attrs, @@ -480,14 +495,15 @@ private: bool pratt_parse = false); std::unique_ptr<AST::IfExpr> parse_if_expr (std::vector<AST::Attribute> outer_attrs - = std::vector<AST::Attribute> ()); + = std::vector<AST::Attribute> (), + bool pratt_parse = false); std::unique_ptr<AST::IfLetExpr> parse_if_let_expr (std::vector<AST::Attribute> outer_attrs - = std::vector<AST::Attribute> ()); - std::unique_ptr<AST::LoopExpr> - parse_loop_expr (std::vector<AST::Attribute> outer_attrs - = std::vector<AST::Attribute> (), - AST::LoopLabel label = AST::LoopLabel::error ()); + = std::vector<AST::Attribute> (), + bool pratt_parse = false); + std::unique_ptr<AST::LoopExpr> parse_loop_expr ( + std::vector<AST::Attribute> outer_attrs = std::vector<AST::Attribute> (), + AST::LoopLabel label = AST::LoopLabel::error (), bool pratt_parse = false); std::unique_ptr<AST::WhileLoopExpr> parse_while_loop_expr (std::vector<AST::Attribute> outer_attrs = std::vector<AST::Attribute> (), @@ -561,7 +577,8 @@ private: std::unique_ptr<AST::Type> parse_paren_prefixed_type (); std::unique_ptr<AST::TypeNoBounds> parse_paren_prefixed_type_no_bounds (); std::unique_ptr<AST::Type> parse_for_prefixed_type (); - AST::MaybeNamedParam parse_maybe_named_param (std::vector<AST::Attribute> outer_attrs); + AST::MaybeNamedParam + parse_maybe_named_param (std::vector<AST::Attribute> outer_attrs); // Statement-related std::unique_ptr<AST::Stmt> parse_stmt (); @@ -591,7 +608,8 @@ private: std::unique_ptr<AST::TupleStructItems> parse_tuple_struct_items (); AST::StructPatternElements parse_struct_pattern_elems (); std::unique_ptr<AST::StructPatternField> parse_struct_pattern_field (); - std::unique_ptr<AST::StructPatternField> parse_struct_pattern_field_partial (std::vector<AST::Attribute> outer_attrs); + std::unique_ptr<AST::StructPatternField> + parse_struct_pattern_field_partial (std::vector<AST::Attribute> outer_attrs); int left_binding_power (const_TokenPtr token); @@ -607,8 +625,8 @@ public: AST::Crate parse_crate (); // Dumps all lexer output. - void debug_dump_lex_output (); - void debug_dump_ast_output (AST::Crate &crate); + void debug_dump_lex_output (std::ostream &out); + void debug_dump_ast_output (AST::Crate &crate, std::ostream &out); private: // The token source (usually lexer) associated with the parser. diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index d563f93..9cfa04d 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -241,6 +241,62 @@ public: ResolveExpr::go (expr.get_receiver_expr ().get (), expr.get_node_id ()); } + void visit (AST::LoopExpr &expr) + { + if (expr.has_loop_label ()) + { + auto label = expr.get_loop_label (); + if (label.get_lifetime ().get_lifetime_type () + != AST::Lifetime::LifetimeType::NAMED) + { + rust_error_at (label.get_locus (), + "Labels must be a named lifetime value"); + return; + } + + auto label_name = label.get_lifetime ().get_lifetime_name (); + auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); + resolver->get_label_scope ().insert ( + label_name, label_lifetime_node_id, label.get_locus (), false, + [&] (std::string, NodeId, Location locus) -> void { + rust_error_at (label.get_locus (), + "label redefined multiple times"); + rust_error_at (locus, "was defined here"); + }); + resolver->insert_new_definition (label_lifetime_node_id, + Definition{label_lifetime_node_id, + label.get_node_id ()}); + } + ResolveExpr::go (expr.get_loop_block ().get (), expr.get_node_id ()); + } + + void visit (AST::BreakExpr &expr) + { + if (expr.has_label ()) + { + auto label = expr.get_label (); + if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED) + { + rust_error_at (label.get_locus (), + "Labels must be a named lifetime value"); + return; + } + + NodeId resolved_node = UNKNOWN_NODEID; + if (!resolver->get_label_scope ().lookup (label.get_lifetime_name (), + &resolved_node)) + { + rust_error_at (expr.get_label ().get_locus (), + "failed to resolve label"); + return; + } + resolver->insert_resolved_label (label.get_node_id (), resolved_node); + } + + if (expr.has_break_expr ()) + ResolveExpr::go (expr.get_break_expr ().get (), expr.get_node_id ()); + } + private: ResolveExpr (NodeId parent) : ResolverBase (parent) {} }; diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h index 8b6227e..f5dc579 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.h +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -88,8 +88,10 @@ public: 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 ()); // we make a new scope so the names of parameters are resolved and shadowed // correctly @@ -111,6 +113,7 @@ public: resolver->get_name_scope ().pop (); resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); } void visit (AST::InherentImpl &impl_block) diff --git a/gcc/rust/resolve/rust-ast-resolve-unused.h b/gcc/rust/resolve/rust-ast-resolve-unused.h index 928cf11..748f972 100644 --- a/gcc/rust/resolve/rust-ast-resolve-unused.h +++ b/gcc/rust/resolve/rust-ast-resolve-unused.h @@ -43,6 +43,7 @@ public: auto resolver = Resolver::get (); resolver->iterate_name_ribs ([&] (Rib *r) -> void { ScanRib (r); }); resolver->iterate_type_ribs ([&] (Rib *r) -> void { ScanRib (r); }); + resolver->iterate_label_ribs ([&] (Rib *r) -> void { ScanRib (r); }); } }; diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index d514132..4f7382a 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -49,7 +49,8 @@ namespace Resolver { Resolver::Resolver () : mappings (Analysis::Mappings::get ()), tyctx (TypeCheckContext::get ()), name_scope (Scope (mappings->get_current_crate ())), - type_scope (Scope (mappings->get_current_crate ())) + type_scope (Scope (mappings->get_current_crate ())), + label_scope (Scope (mappings->get_current_crate ())) { generate_builtins (); } @@ -81,6 +82,13 @@ Resolver::push_new_type_rib (Rib *r) type_ribs[r->get_node_id ()] = r; } +void +Resolver::push_new_label_rib (Rib *r) +{ + rust_assert (label_ribs.find (r->get_node_id ()) == label_ribs.end ()); + label_ribs[r->get_node_id ()] = r; +} + bool Resolver::find_name_rib (NodeId id, Rib **rib) { @@ -238,6 +246,27 @@ Resolver::lookup_resolved_type (NodeId refId, NodeId *defId) return true; } +void +Resolver::insert_resolved_label (NodeId refId, NodeId defId) +{ + auto it = resolved_labels.find (refId); + rust_assert (it == resolved_labels.end ()); + + resolved_labels[refId] = defId; + get_label_scope ().append_reference_for_def (refId, defId); +} + +bool +Resolver::lookup_resolved_label (NodeId refId, NodeId *defId) +{ + auto it = resolved_labels.find (refId); + if (it == resolved_labels.end ()) + return false; + + *defId = it->second; + return true; +} + // NameResolution NameResolution * @@ -275,6 +304,9 @@ NameResolution::go (AST::Crate &crate) // setup parent scoping for new types resolver->get_type_scope ().push (mappings->get_next_node_id ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + // setup label scope + resolver->get_label_scope ().push (mappings->get_next_node_id ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); // first gather the top-level namespace names then we drill down for (auto it = crate.items.begin (); it != crate.items.end (); it++) @@ -293,8 +325,10 @@ ResolveExpr::visit (AST::BlockExpr &expr) NodeId scope_node_id = expr.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 ()); expr.iterate_stmts ([&] (AST::Stmt *s) mutable -> bool { ResolveStmt::go (s, s->get_node_id ()); @@ -306,6 +340,7 @@ ResolveExpr::visit (AST::BlockExpr &expr) resolver->get_name_scope ().pop (); resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); } // rust-ast-resolve-struct-expr-field.h diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h index ea0e4f5..9c01d47 100644 --- a/gcc/rust/resolve/rust-name-resolver.h +++ b/gcc/rust/resolve/rust-name-resolver.h @@ -250,9 +250,11 @@ public: void push_new_name_rib (Rib *r); void push_new_type_rib (Rib *r); + void push_new_label_rib (Rib *r); bool find_name_rib (NodeId id, Rib **rib); bool find_type_rib (NodeId id, Rib **rib); + bool find_label_rib (NodeId id, Rib **rib); void insert_new_definition (NodeId id, Definition def); bool lookup_definition (NodeId id, Definition *def); @@ -263,9 +265,13 @@ public: void insert_resolved_type (NodeId refId, NodeId defId); bool lookup_resolved_type (NodeId refId, NodeId *defId); + void insert_resolved_label (NodeId refId, NodeId defId); + bool lookup_resolved_label (NodeId refId, NodeId *defId); + // proxy for scoping Scope &get_name_scope () { return name_scope; } Scope &get_type_scope () { return type_scope; } + Scope &get_label_scope () { return label_scope; } NodeId get_global_type_node_id () { return global_type_node_id; } @@ -320,6 +326,12 @@ public: } } + void iterate_label_ribs (std::function<void (Rib *)> cb) + { + for (auto it = label_ribs.begin (); it != label_ribs.end (); it++) + cb (it->second); + } + private: Resolver (); @@ -332,6 +344,7 @@ private: Scope name_scope; Scope type_scope; + Scope label_scope; NodeId global_type_node_id; NodeId unit_ty_node_id; @@ -339,6 +352,7 @@ private: // map a AST Node to a Rib std::map<NodeId, Rib *> name_ribs; std::map<NodeId, Rib *> type_ribs; + std::map<NodeId, Rib *> label_ribs; // map any Node to its Definition // ie any name or type usage @@ -354,6 +368,7 @@ private: // we need two namespaces one for names and ones for types std::map<NodeId, NodeId> resolved_names; std::map<NodeId, NodeId> resolved_types; + std::map<NodeId, NodeId> resolved_labels; // map of resolved names mutability flag std::map<NodeId, bool> decl_mutability; diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index 7b0ccf9..50e8728 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -425,6 +425,12 @@ public: Location) = 0; + // infinite loop expressions + virtual Bexpression *loop_expression (Bblock *body, Location); + + // exit expressions + virtual Bexpression *exit_expression (Bexpression *condition, Location); + // Create a switch statement where the case values are constants. // CASES and STATEMENTS must have the same number of entries. If // VALUE matches any of the list in CASES[i], which will all be diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 0729b1e..82ebb98 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -326,6 +326,10 @@ public: Bstatement *except_stmt, Bstatement *finally_stmt, Location); + Bexpression *loop_expression (Bblock *body, Location); + + Bexpression *exit_expression (Bexpression *condition, Location); + // Blocks. Bblock *block (Bfunction *, Bblock *, const std::vector<Bvariable *> &, @@ -2201,6 +2205,25 @@ Gcc_backend::if_statement (Bfunction *, Bexpression *condition, return this->make_statement (ret); } +// Loops + +Bexpression * +Gcc_backend::loop_expression (Bblock *body, Location locus) +{ + tree loop_expr_tree = fold_build1_loc (locus.gcc_location (), LOOP_EXPR, + void_type_node, body->get_tree ()); + return this->make_expression (loop_expr_tree); +} + +Bexpression * +Gcc_backend::exit_expression (Bexpression *condition, Location locus) +{ + tree cond_tree = condition->get_tree (); + tree exit_expr_tree = fold_build1_loc (locus.gcc_location (), EXIT_EXPR, + void_type_node, cond_tree); + return this->make_expression (exit_expr_tree); +} + // Switch. Bstatement * diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 2d15a59..b8742fb 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -21,6 +21,8 @@ #include "rust-diagnostics.h" #include "diagnostic.h" #include "input.h" +#include <fstream> +#include <sstream> #include "target.h" #include "tm.h" @@ -46,6 +48,13 @@ rust_get_backend (); namespace Rust { +const char *kLexDumpFile = "gccrs.lex.dump"; +const char *kASTDumpFile = "gccrs.ast.dump"; +const char *kASTExpandedDumpFile = "gccrs.ast-expanded.dump"; +const char *kHIRDumpFile = "gccrs.hir.dump"; +const char *kHIRTypeResolutionDumpFile = "gccrs.type-resolution.dump"; +const char *kTargetOptionsDumpFile = "gccrs.target-options.dump"; + // Implicitly enable a target_feature (and recursively enable dependencies). void Session::implicitly_enable_feature (std::string feature_name) @@ -309,9 +318,7 @@ Session::init () * itself. */ void Session::init_options () -{ - options.dump_option = CompileOptions::NO_DUMP; -} +{} // Handle option selection. bool @@ -357,62 +364,51 @@ Session::handle_option ( bool Session::enable_dump (std::string arg) { - /* FIXME: change dumping algorithm when new non-inhibiting dump system is - * created */ - if (arg == "all") + if (arg.empty ()) { rust_error_at ( Location (), - "dumping all is not supported as of now. choose %<lex%>, %<parse%>, " + "dump option was not given a name. choose %<lex%>, %<parse%>, " "%<register_plugins%>, %<injection%>, %<expansion%>, %<resolution%>," - " %<target_options%>, or %<hir%>"); + " %<target_options%>, %<hir%>, or %<all%>"); return false; } + + if (arg == "all") + { + options.enable_all_dump_options (); + } else if (arg == "lex") { - options.dump_option = CompileOptions::LEXER_DUMP; + options.enable_dump_option (CompileOptions::LEXER_DUMP); } else if (arg == "parse") { - options.dump_option = CompileOptions::PARSER_AST_DUMP; + options.enable_dump_option (CompileOptions::PARSER_AST_DUMP); } else if (arg == "register_plugins") { - options.dump_option = CompileOptions::REGISTER_PLUGINS_DUMP; + options.enable_dump_option (CompileOptions::REGISTER_PLUGINS_DUMP); } else if (arg == "injection") { - options.dump_option = CompileOptions::INJECTION_DUMP; + options.enable_dump_option (CompileOptions::INJECTION_DUMP); } else if (arg == "expansion") { - options.dump_option = CompileOptions::EXPANSION_DUMP; + options.enable_dump_option (CompileOptions::EXPANSION_DUMP); } else if (arg == "resolution") { - options.dump_option = CompileOptions::RESOLUTION_DUMP; + options.enable_dump_option (CompileOptions::RESOLUTION_DUMP); } else if (arg == "target_options") { - // special case - dump all target options, and then quit compilation - // nope, option handling called before init, so have to make this an - // actual compile option - // options.target_data.dump_target_options(); - // return false; - options.dump_option = CompileOptions::TARGET_OPTION_DUMP; + options.enable_dump_option (CompileOptions::TARGET_OPTION_DUMP); } else if (arg == "hir") { - options.dump_option = CompileOptions::HIR_DUMP; - } - else if (arg == "") - { - rust_error_at ( - Location (), - "dump option was not given a name. choose " - "%<lex%>, %<parse%>, %<register_plugins%>, %<injection%>, " - "%<expansion%>, %<resolution%>, %<target_options%>, or %<hir%>"); - return false; + options.enable_dump_option (CompileOptions::HIR_DUMP); } else { @@ -465,24 +461,22 @@ Session::parse_file (const char *filename) auto mappings = Analysis::Mappings::get (); mappings->insert_ast_crate (&parsed_crate); - // give a chance to give some debug - switch (options.dump_option) + if (options.dump_option_enabled (CompileOptions::LEXER_DUMP)) + { + dump_lex (parser); + } + if (options.dump_option_enabled (CompileOptions::PARSER_AST_DUMP)) + { + dump_ast (parser, parsed_crate); + } + if (options.dump_option_enabled (CompileOptions::TARGET_OPTION_DUMP)) { - case CompileOptions::LEXER_DUMP: - parser.debug_dump_lex_output (); - // TODO: rewrite lexer dump or something so that it allows for the crate - // to already be parsed - break; - case CompileOptions::PARSER_AST_DUMP: - parser.debug_dump_ast_output (parsed_crate); - break; - case CompileOptions::TARGET_OPTION_DUMP: options.target_data.dump_target_options (); - return; - default: - break; } + if (saw_errors ()) + return; + /* basic pipeline: * - lex * - parse @@ -502,8 +496,7 @@ Session::parse_file (const char *filename) // register plugins pipeline stage register_plugins (parsed_crate); fprintf (stderr, "\033[0;31mSUCCESSFULLY REGISTERED PLUGINS \n\033[0m"); - - if (options.dump_option == CompileOptions::REGISTER_PLUGINS_DUMP) + if (options.dump_option_enabled (CompileOptions::REGISTER_PLUGINS_DUMP)) { // TODO: what do I dump here? } @@ -511,8 +504,7 @@ Session::parse_file (const char *filename) // injection pipeline stage injection (parsed_crate); fprintf (stderr, "\033[0;31mSUCCESSFULLY FINISHED INJECTION \n\033[0m"); - - if (options.dump_option == CompileOptions::INJECTION_DUMP) + if (options.dump_option_enabled (CompileOptions::INJECTION_DUMP)) { // TODO: what do I dump here? injected crate names? } @@ -520,18 +512,17 @@ Session::parse_file (const char *filename) // expansion pipeline stage expansion (parsed_crate); fprintf (stderr, "\033[0;31mSUCCESSFULLY FINISHED EXPANSION \n\033[0m"); - - if (options.dump_option == CompileOptions::EXPANSION_DUMP) + if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP)) { // dump AST with expanded stuff fprintf (stderr, "BEGIN POST-EXPANSION AST DUMP\n"); - parser.debug_dump_ast_output (parsed_crate); + dump_ast_expanded (parser, parsed_crate); fprintf (stderr, "END POST-EXPANSION AST DUMP\n"); } // resolution pipeline stage Resolver::NameResolution::Resolve (parsed_crate); - if (options.dump_option == CompileOptions::RESOLUTION_DUMP) + if (options.dump_option_enabled (CompileOptions::RESOLUTION_DUMP)) { // TODO: what do I dump here? resolved names? AST with resolved names? } @@ -541,10 +532,9 @@ Session::parse_file (const char *filename) // lower AST to HIR HIR::Crate hir = HIR::ASTLowering::Resolve (parsed_crate); - if (options.dump_option == CompileOptions::HIR_DUMP) + if (options.dump_option_enabled (CompileOptions::HIR_DUMP)) { - fprintf (stderr, "%s", hir.as_string ().c_str ()); - return; + dump_hir (hir); } if (saw_errors ()) @@ -552,11 +542,9 @@ Session::parse_file (const char *filename) // type resolve Resolver::TypeResolution::Resolve (hir); - if (options.dump_option == CompileOptions::TYPE_RESOLUTION_DUMP) + if (options.dump_option_enabled (CompileOptions::TYPE_RESOLUTION_DUMP)) { - auto buf = Resolver::TypeResolverDump::go (hir); - fprintf (stderr, "%s\n", buf.c_str ()); - return; + dump_type_resolution (hir); } // scan unused has to be done after type resolution since methods are resolved @@ -799,22 +787,114 @@ Session::expansion (AST::Crate &crate) } void +Session::dump_lex (Parser<Lexer> &parser) const +{ + std::ofstream out; + out.open (kLexDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kLexDumpFile); + return; + } + + // TODO: rewrite lexer dump or something so that it allows for the crate + // to already be parsed + parser.debug_dump_lex_output (out); + out.close (); +} + +void +Session::dump_ast (Parser<Lexer> &parser, AST::Crate &crate) const +{ + std::ofstream out; + out.open (kASTDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kASTDumpFile); + return; + } + + parser.debug_dump_ast_output (crate, out); + out.close (); +} + +void +Session::dump_ast_expanded (Parser<Lexer> &parser, AST::Crate &crate) const +{ + std::ofstream out; + out.open (kASTExpandedDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kASTExpandedDumpFile); + return; + } + + parser.debug_dump_ast_output (crate, out); + out.close (); +} + +void +Session::dump_hir (HIR::Crate &hir) const +{ + std::ofstream out; + out.open (kHIRDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kHIRDumpFile); + return; + } + + out << hir.as_string (); + out.close (); +} + +void +Session::dump_type_resolution (HIR::Crate &hir) const +{ + std::ofstream out; + out.open (kHIRTypeResolutionDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kHIRTypeResolutionDumpFile); + return; + } + + Resolver::TypeResolverDump::go (hir, out); + out.close (); +} + +void TargetOptions::dump_target_options () const { - fprintf (stderr, - "\033[0;31m--PREPARING TO DUMP ALL TARGET OPTIONS--\n\033[0m"); + std::ofstream out; + out.open (kTargetOptionsDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kTargetOptionsDumpFile); + return; + } + + if (features.empty ()) + { + out << "No target options available!\n"; + } + for (const auto &pairs : features) { for (const auto &value : pairs.second) - fprintf (stderr, "%s: \"%s\"\n", pairs.first.c_str (), value.c_str ()); + out << pairs.first + ": \"" + value + "\"\n"; if (pairs.second.empty ()) - fprintf (stderr, "%s\n", pairs.first.c_str ()); + out << pairs.first + "\n"; } - if (features.empty ()) - fprintf (stderr, "No target options available!\n"); - fprintf (stderr, "\033[0;31m--END OF TARGET OPTION DUMP--\n\033[0m"); + out.close (); } void diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h index 07d5461..b7e081b 100644 --- a/gcc/rust/rust-session-manager.h +++ b/gcc/rust/rust-session-manager.h @@ -116,8 +116,8 @@ public: // Dump all target options to stderr. void dump_target_options () const; - /* Creates derived values and implicit enables after all target info is added - * (e.g. "unix"). */ + /* Creates derived values and implicit enables after all target info is + * added (e.g. "unix"). */ void init_derived_values (); /* Enables all requirements for the feature given, and will enable feature @@ -162,13 +162,8 @@ public: // Defines compiler options (e.g. dump, etc.). struct CompileOptions { - // TODO: use bitfield for smaller memory requirements? - - /* FIXME: this is set up for "instead of" dumping - in future, dumps should - * not inhibit compilation */ - enum DumpOptions + enum DumpOption { - NO_DUMP, LEXER_DUMP, PARSER_AST_DUMP, REGISTER_PLUGINS_DUMP, @@ -178,8 +173,9 @@ struct CompileOptions TARGET_OPTION_DUMP, HIR_DUMP, TYPE_RESOLUTION_DUMP, + }; - } dump_option; + std::set<DumpOption> dump_options; /* configuration options - actually useful for conditional compilation and * whatever data related to target arch, features, os, family, env, endian, @@ -188,6 +184,26 @@ struct CompileOptions bool enable_test = false; bool debug_assertions = false; bool proc_macro = false; + + bool dump_option_enabled (DumpOption option) const + { + return dump_options.find (option) != dump_options.end (); + } + + void enable_dump_option (DumpOption option) { dump_options.insert (option); } + + void enable_all_dump_options () + { + enable_dump_option (DumpOption::LEXER_DUMP); + enable_dump_option (DumpOption::PARSER_AST_DUMP); + enable_dump_option (DumpOption::REGISTER_PLUGINS_DUMP); + enable_dump_option (DumpOption::INJECTION_DUMP); + enable_dump_option (DumpOption::EXPANSION_DUMP); + enable_dump_option (DumpOption::RESOLUTION_DUMP); + enable_dump_option (DumpOption::TARGET_OPTION_DUMP); + enable_dump_option (DumpOption::HIR_DUMP); + enable_dump_option (DumpOption::TYPE_RESOLUTION_DUMP); + } }; /* Defines a compiler session. This is for a single compiler invocation, so @@ -219,6 +235,12 @@ private: void parse_file (const char *filename); bool enable_dump (std::string arg); + void dump_lex (Parser<Lexer> &parser) const; + void dump_ast (Parser<Lexer> &parser, AST::Crate &crate) const; + void dump_ast_expanded (Parser<Lexer> &parser, AST::Crate &crate) const; + void dump_hir (HIR::Crate &crate) const; + void dump_type_resolution (HIR::Crate &crate) const; + void debug_dump_load_crates (Parser<Lexer> &parser); void implicitly_enable_feature (std::string feature_name); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index e6cca19..87aeae6 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -32,14 +32,15 @@ namespace Resolver { class TypeCheckExpr : public TypeCheckBase { public: - static TyTy::TyBase *Resolve (HIR::Expr *expr, bool is_final_expr = false) + static TyTy::TyBase *Resolve (HIR::Expr *expr, bool inside_loop) { - TypeCheckExpr resolver (is_final_expr); + TypeCheckExpr resolver (inside_loop); expr->accept_vis (resolver); if (resolver.infered == nullptr) { - rust_error_at (expr->get_locus_slow (), "failed to resolve expression"); + rust_error_at (expr->get_locus_slow (), + "failed to type resolve expression"); return new TyTy::ErrorType (expr->get_mappings ().get_hirid ()); } @@ -52,7 +53,8 @@ public: void visit (HIR::TupleIndexExpr &expr) { - auto resolved = TypeCheckExpr::Resolve (expr.get_tuple_expr ().get ()); + auto resolved + = TypeCheckExpr::Resolve (expr.get_tuple_expr ().get (), inside_loop); if (resolved == nullptr) { rust_error_at (expr.get_tuple_expr ()->get_locus_slow (), @@ -128,7 +130,7 @@ public: std::vector<HirId> fields; for (auto &elem : expr.get_tuple_elems ()) { - auto field_ty = TypeCheckExpr::Resolve (elem.get ()); + auto field_ty = TypeCheckExpr::Resolve (elem.get (), false); fields.push_back (field_ty->get_ref ()); } infered = new TyTy::TupleType (expr.get_mappings ().get_hirid (), fields); @@ -136,10 +138,16 @@ public: void visit (HIR::ReturnExpr &expr) { + if (!expr.has_return_expr ()) + { + infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ()); + return; + } + auto fn_return_tyty = context->peek_return_type (); rust_assert (fn_return_tyty != nullptr); - auto expr_ty = TypeCheckExpr::Resolve (expr.get_expr ()); + auto expr_ty = TypeCheckExpr::Resolve (expr.get_expr (), false); if (expr_ty == nullptr) { rust_error_at (expr.get_locus (), @@ -155,58 +163,12 @@ public: void visit (HIR::CallExpr &expr) { - auto fn = expr.get_fnexpr (); - auto fn_node_id = fn->get_mappings ().get_nodeid (); - - // then lookup the reference_node_id - NodeId ref_node_id = UNKNOWN_NODEID; - if (resolver->lookup_resolved_name (fn_node_id, &ref_node_id)) - { - Definition def; - if (!resolver->lookup_definition (ref_node_id, &def)) - { - rust_error_at (expr.get_locus (), - "unknown reference for resolved name"); - return; - } - ref_node_id = def.parent; - } - else if (!resolver->lookup_resolved_type (fn_node_id, &ref_node_id)) - { - rust_error_at (expr.get_locus (), - "Failed to lookup type reference for node: %s", - expr.as_string ().c_str ()); - return; - } - - if (ref_node_id == UNKNOWN_NODEID) - { - rust_error_at (expr.get_locus (), "unresolved node: %s", - expr.as_string ().c_str ()); - return; - } - - // node back to HIR - HirId ref; - if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), - ref_node_id, &ref)) - { - rust_error_at (expr.get_locus (), "reverse lookup failure for node %u", - ref_node_id); - return; - } - - // check if this has a type - TyTy::TyBase *lookup; - if (!context->lookup_type (ref, &lookup)) - { - rust_error_at (mappings->lookup_location (ref), - "failed to lookup type for CallExpr: %s", - expr.as_string ().c_str ()); - return; - } + TyTy::TyBase *function_tyty + = TypeCheckExpr::Resolve (expr.get_fnexpr (), false); + if (function_tyty == nullptr) + return; - infered = TyTy::TypeCheckCallExpr::go (lookup, expr, context); + infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, context); if (infered == nullptr) { rust_error_at (expr.get_locus (), "failed to lookup type to CallExpr"); @@ -218,7 +180,8 @@ public: void visit (HIR::MethodCallExpr &expr) { - auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ().get ()); + auto receiver_tyty + = TypeCheckExpr::Resolve (expr.get_receiver ().get (), false); if (receiver_tyty == nullptr) { rust_error_at (expr.get_receiver ()->get_locus_slow (), @@ -277,11 +240,13 @@ public: void visit (HIR::AssignmentExpr &expr) { - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); + infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ()); - infered = lhs->combine (rhs); - if (infered == nullptr) + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs (), false); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs (), false); + + auto result = lhs->combine (rhs); + if (result == nullptr) { rust_error_at (expr.get_locus (), "failure in TypeInference AssignmentExpr"); @@ -320,11 +285,10 @@ public: return; } - // FIXME free the old one context->insert_type ( Analysis::NodeMapping (expr.get_lhs ()->get_mappings ().get_crate_num (), ref_node_id, ref, UNKNOWN_LOCAL_DEFID), - infered->clone ()); + result->clone ()); } void visit (HIR::IdentifierExpr &expr) @@ -485,8 +449,8 @@ public: void visit (HIR::ArithmeticOrLogicalExpr &expr) { - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs (), false); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs (), false); bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ()); bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ()); @@ -506,8 +470,8 @@ public: void visit (HIR::ComparisonExpr &expr) { - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs (), false); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs (), false); auto result = lhs->combine (rhs); if (result == nullptr || result->get_kind () == TyTy::TypeKind::ERROR) @@ -521,8 +485,8 @@ public: void visit (HIR::LazyBooleanExpr &expr) { - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs (), false); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs (), false); // we expect the lhs and rhs must be bools at this point TyTy::BoolType elhs (expr.get_mappings ().get_hirid ()); @@ -542,7 +506,7 @@ public: void visit (HIR::NegationExpr &expr) { - auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ()); + auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr (), false); // https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators switch (expr.get_negation_type ()) @@ -591,79 +555,31 @@ public: void visit (HIR::IfExpr &expr) { - TypeCheckExpr::Resolve (expr.get_if_condition ()); - auto blk_expr = TypeCheckExpr::Resolve (expr.get_if_block ()); - - if (is_final_expr - && context->peek_return_type ()->get_kind () != TyTy::TypeKind::UNIT) - { - auto expected_ty = context->peek_return_type (); - infered = expected_ty->combine (blk_expr); - return; - } + TypeCheckExpr::Resolve (expr.get_if_condition (), false); + TypeCheckExpr::Resolve (expr.get_if_block (), inside_loop); infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ()); } void visit (HIR::IfExprConseqElse &expr) { - // check and resolve all types in the conditional var - TypeCheckExpr::Resolve (expr.get_if_condition ()); + TypeCheckExpr::Resolve (expr.get_if_condition (), false); + auto if_blk_resolved + = TypeCheckExpr::Resolve (expr.get_if_block (), inside_loop); + auto else_blk_resolved + = TypeCheckExpr::Resolve (expr.get_else_block (), inside_loop); - auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ()); - auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_else_block ()); - - TyTy::TyBase *if_block_tyty = nullptr; - if (expr.get_if_block ()->has_expr ()) - if_block_tyty - = TypeCheckExpr::Resolve (expr.get_if_block ()->expr.get ()); - else - if_block_tyty = if_blk_resolved; - - TyTy::TyBase *else_block_tyty = nullptr; - if (expr.get_else_block ()->has_expr ()) - else_block_tyty - = TypeCheckExpr::Resolve (expr.get_else_block ()->expr.get ()); - else - else_block_tyty = else_blk_resolved; - - if (context->peek_return_type ()->get_kind () != TyTy::TypeKind::UNIT) - { - // this must combine to what the type is expected - // this might be a parameter or the last expr in an if + else in a - // BlockExpr then it must resolve to fn return type else its a unit-type - auto expected_ty - = is_final_expr - ? context->peek_return_type () - : new TyTy::UnitType (expr.get_mappings ().get_hirid ()); - - auto if_blk_combined = expected_ty->combine (if_block_tyty); - auto else_blk_combined = expected_ty->combine (else_block_tyty); - - infered = if_blk_combined->combine (else_blk_combined); - return; - } - - infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ()); + infered = if_blk_resolved->combine (else_blk_resolved); } void visit (HIR::IfExprConseqIf &expr) { - TypeCheckExpr::Resolve (expr.get_if_condition ()); - auto if_blk = TypeCheckExpr::Resolve (expr.get_if_block ()); - auto elif_blk = TypeCheckExpr::Resolve (expr.get_conseq_if_expr ()); - - if (is_final_expr - && context->peek_return_type ()->get_kind () != TyTy::TypeKind::UNIT) - { - auto expected_ty = context->peek_return_type (); - - infered = expected_ty->combine (if_blk); - infered = infered->combine (elif_blk); - return; - } + TypeCheckExpr::Resolve (expr.get_if_condition (), false); + auto if_blk = TypeCheckExpr::Resolve (expr.get_if_block (), inside_loop); + auto else_blk + = TypeCheckExpr::Resolve (expr.get_conseq_if_expr (), inside_loop); - infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ()); + infered = if_blk->combine (else_blk); } void visit (HIR::BlockExpr &expr); @@ -679,8 +595,8 @@ public: return; } - auto resolved_index_expr - = size_ty->combine (TypeCheckExpr::Resolve (expr.get_index_expr ())); + auto resolved_index_expr = size_ty->combine ( + TypeCheckExpr::Resolve (expr.get_index_expr (), false)); if (resolved_index_expr == nullptr) { rust_error_at (expr.get_index_expr ()->get_locus_slow (), @@ -727,7 +643,7 @@ public: { std::vector<TyTy::TyBase *> types; elems.iterate ([&] (HIR::Expr *e) mutable -> bool { - types.push_back (TypeCheckExpr::Resolve (e)); + types.push_back (TypeCheckExpr::Resolve (e, false)); return true; }); @@ -743,7 +659,8 @@ public: void visit (HIR::ArrayElemsCopied &elems) { - infered_array_elems = TypeCheckExpr::Resolve (elems.get_elem_to_copy ()); + infered_array_elems + = TypeCheckExpr::Resolve (elems.get_elem_to_copy (), false); } void visit (HIR::StructExprStructFields &struct_expr) @@ -753,13 +670,17 @@ public: void visit (HIR::GroupedExpr &expr) { - infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ().get ()); + printf ("inside grouped expr: \n%s\n inside it is: \n%s\n", + expr.as_string ().c_str (), + expr.get_expr_in_parens ()->as_string ().c_str ()); + + infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ().get (), false); } void visit (HIR::FieldAccessExpr &expr) { auto struct_base - = TypeCheckExpr::Resolve (expr.get_receiver_expr ().get ()); + = TypeCheckExpr::Resolve (expr.get_receiver_expr ().get (), false); bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT; if (!is_valid_type) @@ -788,16 +709,33 @@ public: NodeId ast_node_id = expr.get_mappings ().get_nodeid (); // then lookup the reference_node_id - NodeId ref_node_id; - if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + NodeId ref_node_id = UNKNOWN_NODEID; + if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) { - if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) + // these ref_node_ids will resolve to a pattern declaration but we are + // interested in the definition that this refers to get the parent id + Definition def; + if (!resolver->lookup_definition (ref_node_id, &def)) { rust_error_at (expr.get_locus (), - "Failed to lookup reference for node: %s", - expr.as_string ().c_str ()); + "unknown reference for resolved name"); return; } + ref_node_id = def.parent; + } + else if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) + { + rust_error_at (expr.get_locus (), + "Failed to lookup type reference for node: %s", + expr.as_string ().c_str ()); + return; + } + + if (ref_node_id == UNKNOWN_NODEID) + { + rust_error_at (expr.get_locus (), "unresolved node: %s", + expr.as_string ().c_str ()); + return; } // node back to HIR @@ -813,13 +751,52 @@ public: { rust_error_at (expr.get_locus (), "failed to resolve PathInExpression type"); + return; + } + } + + void visit (HIR::LoopExpr &expr) + { + context->push_new_loop_context (expr.get_mappings ().get_hirid ()); + TypeCheckExpr::Resolve (expr.get_loop_block ().get (), true); + TyTy::TyBase *loop_context_type = context->pop_loop_context (); + + bool loop_context_type_infered + = (loop_context_type->get_kind () != TyTy::TypeKind::INFER) + || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER) + && (((TyTy::InferType *) loop_context_type)->get_infer_kind () + != TyTy::InferType::GENERAL)); + + infered = loop_context_type_infered + ? loop_context_type + : new TyTy::UnitType (expr.get_mappings ().get_hirid ()); + } + + void visit (HIR::BreakExpr &expr) + { + if (!inside_loop) + { + rust_error_at (expr.get_locus (), "cannot `break` outside of a loop"); + return; } + + if (expr.has_break_expr ()) + { + TyTy::TyBase *break_expr_tyty + = TypeCheckExpr::Resolve (expr.get_expr ().get (), false); + + TyTy::TyBase *loop_context = context->peek_loop_context (); + TyTy::TyBase *combined = loop_context->combine (break_expr_tyty); + context->swap_head_loop_context (combined); + } + + infered = new TyTy::UnitType (expr.get_mappings ().get_hirid ()); } private: - TypeCheckExpr (bool is_final_expr) + TypeCheckExpr (bool inside_loop) : TypeCheckBase (), infered (nullptr), infered_array_elems (nullptr), - is_final_expr (is_final_expr) + inside_loop (inside_loop) {} bool @@ -871,7 +848,7 @@ private: TyTy::TyBase *infered; TyTy::TyBase *infered_array_elems; - bool is_final_expr; + bool inside_loop; }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index c8d161a..3e835b7 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -40,7 +40,8 @@ public: void visit (HIR::ConstantItem &constant) { TyTy::TyBase *type = TypeCheckType::Resolve (constant.get_type ()); - TyTy::TyBase *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); + TyTy::TyBase *expr_type + = TypeCheckExpr::Resolve (constant.get_expr (), false); context->insert_type (constant.get_mappings (), type->combine (expr_type)); } @@ -170,23 +171,12 @@ public: auto expected_ret_tyty = resolve_fn_type->return_type (); context->push_return_type (expected_ret_tyty); - TypeCheckExpr::Resolve (function.function_body.get ()); - if (function.function_body->has_expr ()) - { - auto resolved - = TypeCheckExpr::Resolve (function.function_body->expr.get ()); + auto result = TypeCheckExpr::Resolve (function.function_body.get (), false); + auto ret_resolved = expected_ret_tyty->combine (result); + if (ret_resolved == nullptr) + return; - auto ret_resolved = expected_ret_tyty->combine (resolved); - if (ret_resolved == nullptr) - { - rust_error_at (function.function_body->expr->get_locus_slow (), - "failed to resolve final expression"); - return; - } - - context->peek_return_type ()->append_reference ( - ret_resolved->get_ref ()); - } + context->peek_return_type ()->append_reference (ret_resolved->get_ref ()); context->pop_return_type (); } @@ -213,23 +203,13 @@ public: auto expected_ret_tyty = resolve_fn_type->return_type (); context->push_return_type (expected_ret_tyty); - TypeCheckExpr::Resolve (method.get_function_body ().get ()); - if (method.get_function_body ()->has_expr ()) - { - auto resolved - = TypeCheckExpr::Resolve (method.get_function_body ()->expr.get ()); + auto result + = TypeCheckExpr::Resolve (method.get_function_body ().get (), false); + auto ret_resolved = expected_ret_tyty->combine (result); + if (ret_resolved == nullptr) + return; - auto ret_resolved = expected_ret_tyty->combine (resolved); - if (ret_resolved == nullptr) - { - rust_error_at (method.get_function_body ()->expr->get_locus_slow (), - "failed to resolve final expression"); - return; - } - - context->peek_return_type ()->append_reference ( - ret_resolved->get_ref ()); - } + context->peek_return_type ()->append_reference (ret_resolved->get_ref ()); context->pop_return_type (); } diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 06be1ac..f54956c 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -75,23 +75,12 @@ public: auto expected_ret_tyty = resolve_fn_type->return_type (); context->push_return_type (expected_ret_tyty); - TypeCheckExpr::Resolve (function.function_body.get ()); - if (function.function_body->has_expr ()) - { - auto resolved - = TypeCheckExpr::Resolve (function.function_body->expr.get ()); - - auto ret_resolved = expected_ret_tyty->combine (resolved); - if (ret_resolved == nullptr) - { - rust_error_at (function.function_body->expr->get_locus_slow (), - "failed to resolve final expression"); - return; - } - - context->peek_return_type ()->append_reference ( - ret_resolved->get_ref ()); - } + auto result = TypeCheckExpr::Resolve (function.function_body.get (), false); + auto ret_resolved = expected_ret_tyty->combine (result); + if (ret_resolved == nullptr) + return; + + context->peek_return_type ()->append_reference (ret_resolved->get_ref ()); context->pop_return_type (); } diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h index e04284e..195e483 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h @@ -30,21 +30,21 @@ namespace Resolver { class TypeCheckStmt : public TypeCheckBase { public: - static TyTy::TyBase *Resolve (HIR::Stmt *stmt, bool is_final_stmt) + static TyTy::TyBase *Resolve (HIR::Stmt *stmt, bool inside_loop) { - TypeCheckStmt resolver (is_final_stmt); + TypeCheckStmt resolver (inside_loop); stmt->accept_vis (resolver); return resolver.infered; } void visit (HIR::ExprStmtWithBlock &stmt) { - infered = TypeCheckExpr::Resolve (stmt.get_expr (), is_final_stmt); + infered = TypeCheckExpr::Resolve (stmt.get_expr (), inside_loop); } void visit (HIR::ExprStmtWithoutBlock &stmt) { - infered = TypeCheckExpr::Resolve (stmt.get_expr (), is_final_stmt); + infered = TypeCheckExpr::Resolve (stmt.get_expr (), inside_loop); } void visit (HIR::LetStmt &stmt) @@ -55,7 +55,7 @@ public: if (stmt.has_init_expr ()) { init_expr_ty - = TypeCheckExpr::Resolve (stmt.get_init_expr (), is_final_stmt); + = TypeCheckExpr::Resolve (stmt.get_init_expr (), inside_loop); if (init_expr_ty == nullptr) return; @@ -106,13 +106,13 @@ public: } private: - TypeCheckStmt (bool is_final_stmt) - : TypeCheckBase (), infered (nullptr), is_final_stmt (is_final_stmt) + TypeCheckStmt (bool inside_loop) + : TypeCheckBase (), infered (nullptr), inside_loop (inside_loop) {} TyTy::TyBase *infered; - bool is_final_stmt; -}; // namespace Resolver + bool inside_loop; +}; } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h index 61823bf..6d4c876 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h +++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h @@ -86,7 +86,7 @@ public: void visit (HIR::StaticItem &var) { TyTy::TyBase *type = TypeCheckType::Resolve (var.get_type ()); - TyTy::TyBase *expr_type = TypeCheckExpr::Resolve (var.get_expr ()); + TyTy::TyBase *expr_type = TypeCheckExpr::Resolve (var.get_expr (), false); context->insert_type (var.get_mappings (), type->combine (expr_type)); } @@ -94,7 +94,8 @@ public: void visit (HIR::ConstantItem &constant) { TyTy::TyBase *type = TypeCheckType::Resolve (constant.get_type ()); - TyTy::TyBase *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); + TyTy::TyBase *expr_type + = TypeCheckExpr::Resolve (constant.get_expr (), false); context->insert_type (constant.get_mappings (), type->combine (expr_type)); } diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 681d023..00a92b0 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -109,10 +109,11 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) expr.iterate_stmts ([&] (HIR::Stmt *s) mutable -> bool { bool is_final_stmt = expr.is_final_stmt (s); - bool is_final_expr = is_final_stmt && !expr.has_expr (); + bool is_final_expr + = is_final_stmt && (!expr.has_expr () || !expr.tail_expr_reachable ()); - auto infered = TypeCheckStmt::Resolve (s, is_final_expr); - if (infered == nullptr) + auto resolved = TypeCheckStmt::Resolve (s, inside_loop); + if (resolved == nullptr) { rust_error_at (s->get_locus_slow (), "failure to resolve type"); return false; @@ -121,7 +122,12 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) if (is_final_expr) { delete block_tyty; - block_tyty = infered; + block_tyty = resolved; + } + else if (resolved->get_kind () != TyTy::TypeKind::UNIT) + { + rust_error_at (s->get_locus_slow (), "expected () got %s", + infered->as_string ().c_str ()); } return true; @@ -131,7 +137,8 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) { delete block_tyty; - block_tyty = TypeCheckExpr::Resolve (expr.get_final_expr ().get (), true); + block_tyty + = TypeCheckExpr::Resolve (expr.get_final_expr ().get (), inside_loop); } infered = block_tyty->clone (); @@ -154,7 +161,8 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr) if (struct_expr.has_struct_base ()) { TyTy::TyBase *base_resolved - = TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get ()); + = TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get (), + false); resolved = struct_path_resolved->combine (base_resolved); if (resolved == nullptr) { @@ -320,7 +328,7 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field) } size_t field_index; - TyTy::TyBase *value = TypeCheckExpr::Resolve (field.get_value ()); + TyTy::TyBase *value = TypeCheckExpr::Resolve (field.get_value (), false); TyTy::StructFieldType *field_type = struct_path_resolved->get_field (field.field_name, &field_index); if (field_type == nullptr) @@ -349,7 +357,7 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field) } size_t field_index; - TyTy::TyBase *value = TypeCheckExpr::Resolve (field.get_value ()); + TyTy::TyBase *value = TypeCheckExpr::Resolve (field.get_value (), false); TyTy::StructFieldType *field_type = struct_path_resolved->get_field (field_name, &field_index); if (field_type == nullptr) @@ -389,7 +397,7 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field) // existing code to figure out the type HIR::IdentifierExpr expr (field.get_mappings (), field.get_field_name (), field.get_locus ()); - TyTy::TyBase *value = TypeCheckExpr::Resolve (&expr); + TyTy::TyBase *value = TypeCheckExpr::Resolve (&expr, false); resolved_field = field_type->get_field_type ()->combine (value); if (resolved_field != nullptr) diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index d033878..531d241 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -56,6 +56,28 @@ public: } } + void push_new_loop_context (HirId id) + { + TyTy::TyBase *infer_var + = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL); + loop_type_stack.push_back (infer_var); + } + + TyTy::TyBase *peek_loop_context () { return loop_type_stack.back (); } + + TyTy::TyBase *pop_loop_context () + { + auto back = peek_loop_context (); + loop_type_stack.pop_back (); + return back; + } + + void swap_head_loop_context (TyTy::TyBase *val) + { + loop_type_stack.pop_back (); + loop_type_stack.push_back (val); + } + private: TypeCheckContext (); @@ -63,6 +85,7 @@ private: std::map<HirId, TyTy::TyBase *> resolved; std::vector<std::unique_ptr<TyTy::TyBase> > builtins; std::vector<TyTy::TyBase *> return_type_stack; + std::vector<TyTy::TyBase *> loop_type_stack; }; class TypeResolution diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h index 9d882fb..17774a7 100644 --- a/gcc/rust/typecheck/rust-tycheck-dump.h +++ b/gcc/rust/typecheck/rust-tycheck-dump.h @@ -28,13 +28,13 @@ namespace Resolver { class TypeResolverDump : public TypeCheckBase { public: - static std::string go (HIR::Crate &crate) + static void go (HIR::Crate &crate, std::ofstream &out) { TypeResolverDump dumper; for (auto &item : crate.items) item->accept_vis (dumper); - return dumper.dump; + out << dumper.dump; } void visit (HIR::InherentImpl &impl_block) override diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 8b04209..e12d5ff 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -501,7 +501,7 @@ TypeCheckCallExpr::visit (ADTType &type) StructFieldType *field = type.get_field (i); TyBase *field_tyty = field->get_field_type (); - TyBase *arg = Resolver::TypeCheckExpr::Resolve (p); + TyBase *arg = Resolver::TypeCheckExpr::Resolve (p, false); if (arg == nullptr) { rust_error_at (p->get_locus_slow (), "failed to resolve argument type"); @@ -542,7 +542,7 @@ TypeCheckCallExpr::visit (FnType &type) size_t i = 0; call.iterate_params ([&] (HIR::Expr *param) mutable -> bool { auto fnparam = type.param_at (i); - auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param); + auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param, false); if (argument_expr_tyty == nullptr) { rust_error_at (param->get_locus_slow (), @@ -593,7 +593,7 @@ TypeCheckMethodCallExpr::visit (FnType &type) size_t i = 1; call.iterate_params ([&] (HIR::Expr *param) mutable -> bool { auto fnparam = type.param_at (i); - auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param); + auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param, false); if (argument_expr_tyty == nullptr) { rust_error_at (param->get_locus_slow (), diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 8a15631..4a1d4f7 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -460,6 +460,12 @@ Mappings::walk_local_defids_for_crate (CrateNum crateNum, } } +void +Mappings::insert_node_to_hir (CrateNum crate, NodeId id, HirId ref) +{ + nodeIdToHirMappings[crate][id] = ref; +} + bool Mappings::lookup_node_to_hir (CrateNum crate, NodeId id, HirId *ref) { diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 0d625f6..b7dbd45 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -136,6 +136,7 @@ public: void walk_local_defids_for_crate (CrateNum crateNum, std::function<bool (HIR::Item *)> cb); + void insert_node_to_hir (CrateNum crate, NodeId id, HirId ref); bool lookup_node_to_hir (CrateNum crate, NodeId id, HirId *ref); void insert_location (CrateNum crate, HirId id, Location locus); diff --git a/gcc/testsuite/rust.test/compilable/block_expr2.rs b/gcc/testsuite/rust.test/compilable/block_expr2.rs new file mode 100644 index 0000000..a66ca7b --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/block_expr2.rs @@ -0,0 +1,14 @@ +fn test() -> i32 { + 123 +} + +fn main() { + let a = { test() }; + let b = { + if a > 10 { + a - 1 + } else { + a + 1 + } + }; +} diff --git a/gcc/testsuite/rust.test/compilable/block_expr3.rs b/gcc/testsuite/rust.test/compilable/block_expr3.rs new file mode 100644 index 0000000..a8b2f27 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/block_expr3.rs @@ -0,0 +1,13 @@ +fn main() { + let x = 111; + + let a = { + if x == 10 { + 123 + } else if x < 10 { + 456 + } else { + 789 + } + }; +} diff --git a/gcc/testsuite/rust.test/compilable/block_expr_parser_bug.rs b/gcc/testsuite/rust.test/compilable/block_expr_parser_bug.rs new file mode 100644 index 0000000..e583008 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/block_expr_parser_bug.rs @@ -0,0 +1,4 @@ +fn main() { + let a = 123; + let b = if a > 10 { a - 1 } else { a + 1 }; +} diff --git a/gcc/testsuite/rust.test/compilable/compound_assignment_expr1.rs b/gcc/testsuite/rust.test/compilable/compound_assignment_expr1.rs index add4a5f..1ff0d24 100644 --- a/gcc/testsuite/rust.test/compilable/compound_assignment_expr1.rs +++ b/gcc/testsuite/rust.test/compilable/compound_assignment_expr1.rs @@ -16,8 +16,7 @@ fn main() { d /= 4; e %= 5; f &= 6; - // https://github.com/Rust-GCC/gccrs/issues/173 - // g |= 7; + g |= 7; h ^= 8; i <<= 9; j >>= 10; diff --git a/gcc/testsuite/rust.test/compilable/function_reference3.rs b/gcc/testsuite/rust.test/compilable/function_reference3.rs new file mode 100644 index 0000000..32f4728 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/function_reference3.rs @@ -0,0 +1,18 @@ +struct Foo { + a: fn(i32) -> i32, + b: i32, +} + +fn test(a: i32) -> i32 { + a + 1 +} + +fn main() { + let a = test(1); + + let b: fn(i32) -> i32 = test; + let c = b(1); + + let d = Foo { a: test, b: c }; + let e = (d.a)(d.b); +} diff --git a/gcc/testsuite/rust.test/compilable/if_elif_else_expr1.rs b/gcc/testsuite/rust.test/compilable/if_elif_else_expr1.rs new file mode 100644 index 0000000..eda6d17 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/if_elif_else_expr1.rs @@ -0,0 +1,13 @@ +fn test(x: i32) -> i32 { + if x == 10 { + 123 + } else if x < 10 { + 456 + } else { + 789 + } +} + +fn main() { + let a = test(1); +} diff --git a/gcc/testsuite/rust.test/compilable/loop1.rs b/gcc/testsuite/rust.test/compilable/loop1.rs new file mode 100644 index 0000000..a8ee2f5 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/loop1.rs @@ -0,0 +1,10 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + loop { + let c = a + b; + a = b; + b = c; + } +} diff --git a/gcc/testsuite/rust.test/compilable/loop2.rs b/gcc/testsuite/rust.test/compilable/loop2.rs new file mode 100644 index 0000000..3de3ea8 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/loop2.rs @@ -0,0 +1,14 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + // first number in Fibonacci sequence over 10: + loop { + if b > 10 { + break; + } + let c = a + b; + a = b; + b = c; + } +} diff --git a/gcc/testsuite/rust.test/compilable/loop3.rs b/gcc/testsuite/rust.test/compilable/loop3.rs new file mode 100644 index 0000000..76fadfb --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/loop3.rs @@ -0,0 +1,14 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + // first number in Fibonacci sequence over 10: + loop { + if b > 10 { + return; + } + let c = a + b; + a = b; + b = c; + } +} diff --git a/gcc/testsuite/rust.test/compilable/loop4.rs b/gcc/testsuite/rust.test/compilable/loop4.rs new file mode 100644 index 0000000..f7b5935 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/loop4.rs @@ -0,0 +1,7 @@ +fn main() { + 'outer: loop { + 'inner: loop { + break 'outer; + } + } +} diff --git a/gcc/testsuite/rust.test/compilable/loop5.rs b/gcc/testsuite/rust.test/compilable/loop5.rs new file mode 100644 index 0000000..4004cd3 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/loop5.rs @@ -0,0 +1,14 @@ +fn main() { + let mut a = 1; + let mut b = 1; + + // first number in Fibonacci sequence over 10: + let _fib = loop { + if b > 10 { + break b; + } + let c = a + b; + a = b; + b = c; + }; +} diff --git a/gcc/testsuite/rust.test/fail_compilation/break1.rs b/gcc/testsuite/rust.test/fail_compilation/break1.rs new file mode 100644 index 0000000..401a575 --- /dev/null +++ b/gcc/testsuite/rust.test/fail_compilation/break1.rs @@ -0,0 +1,5 @@ +fn main() { + let a; + a = 1; + break a; +} |