aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorSimplyTheOther <simplytheother@gmail.com>2021-02-11 12:15:39 +0800
committerSimplyTheOther <simplytheother@gmail.com>2021-02-11 12:15:39 +0800
commit7d4ed9d38c7a636408a262f70aa69d2a34e2169d (patch)
tree915c10b77703d0ef8d074775ddea95eb0f728cab /gcc
parentcfd1d805ff5921480d9badd7d215e1b1deb33aca (diff)
parent0c7d0135663b6f0d94e0ffd931366ba2b32f8b2c (diff)
downloadgcc-7d4ed9d38c7a636408a262f70aa69d2a34e2169d.zip
gcc-7d4ed9d38c7a636408a262f70aa69d2a34e2169d.tar.gz
gcc-7d4ed9d38c7a636408a262f70aa69d2a34e2169d.tar.bz2
Merge branch 'master' of https://github.com/redbrain/gccrs
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/ast/rust-ast.h13
-rw-r--r--gcc/rust/ast/rust-expr.h15
-rw-r--r--gcc/rust/backend/rust-compile-context.h28
-rw-r--r--gcc/rust/backend/rust-compile-expr.h231
-rw-r--r--gcc/rust/backend/rust-compile.cc83
-rw-r--r--gcc/rust/hir/rust-ast-lower-base.h41
-rw-r--r--gcc/rust/hir/rust-ast-lower-block.h21
-rw-r--r--gcc/rust/hir/rust-ast-lower-expr.h30
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h36
-rw-r--r--gcc/rust/hir/tree/rust-hir-item.h3
-rw-r--r--gcc/rust/hir/tree/rust-hir-type.h2
-rw-r--r--gcc/rust/hir/tree/rust-hir.h26
-rw-r--r--gcc/rust/parse/rust-parse-impl.h127
-rw-r--r--gcc/rust/parse/rust-parse.h72
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h56
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.h3
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-unused.h1
-rw-r--r--gcc/rust/resolve/rust-ast-resolve.cc37
-rw-r--r--gcc/rust/resolve/rust-name-resolver.h15
-rw-r--r--gcc/rust/rust-backend.h6
-rw-r--r--gcc/rust/rust-gcc.cc23
-rw-r--r--gcc/rust/rust-session-manager.cc212
-rw-r--r--gcc/rust/rust-session-manager.h40
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h269
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.h46
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-item.h23
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-stmt.h18
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-toplevel.h5
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.cc26
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.h23
-rw-r--r--gcc/rust/typecheck/rust-tycheck-dump.h4
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc6
-rw-r--r--gcc/rust/util/rust-hir-map.cc6
-rw-r--r--gcc/rust/util/rust-hir-map.h1
-rw-r--r--gcc/testsuite/rust.test/compilable/block_expr2.rs14
-rw-r--r--gcc/testsuite/rust.test/compilable/block_expr3.rs13
-rw-r--r--gcc/testsuite/rust.test/compilable/block_expr_parser_bug.rs4
-rw-r--r--gcc/testsuite/rust.test/compilable/compound_assignment_expr1.rs3
-rw-r--r--gcc/testsuite/rust.test/compilable/function_reference3.rs18
-rw-r--r--gcc/testsuite/rust.test/compilable/if_elif_else_expr1.rs13
-rw-r--r--gcc/testsuite/rust.test/compilable/loop1.rs10
-rw-r--r--gcc/testsuite/rust.test/compilable/loop2.rs14
-rw-r--r--gcc/testsuite/rust.test/compilable/loop3.rs14
-rw-r--r--gcc/testsuite/rust.test/compilable/loop4.rs7
-rw-r--r--gcc/testsuite/rust.test/compilable/loop5.rs14
-rw-r--r--gcc/testsuite/rust.test/fail_compilation/break1.rs5
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;
+}