From: Philip Herron <[email protected]>

Tail expressions were always ignoring the context here and returning
unit-type. This patch respects the label context here properly.

Fixes Rust-GCC#4538

gcc/rust/ChangeLog:

        * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): respect 
context for labels

gcc/testsuite/ChangeLog:

        * rust/compile/issue-4538.rs: New test.

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


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

The commit has NOT been mentioned in any issue.

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

 .../typecheck/rust-hir-type-check-expr.cc     | 46 ++++++++++++++-----
 gcc/testsuite/rust/compile/issue-4538.rs      | 22 +++++++++
 2 files changed, 57 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-4538.rs

diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc 
b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index 8ed04d635..62f419766 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -692,6 +692,7 @@ TypeCheckExpr::visit (HIR::UnsafeBlockExpr &expr)
 void
 TypeCheckExpr::visit (HIR::BlockExpr &expr)
 {
+  bool has_label = expr.has_label ();
   if (expr.has_label ())
     context->push_new_loop_context (expr.get_mappings ().get_hirid (),
                                    expr.get_locus ());
@@ -718,6 +719,8 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr)
        {
          rust_error_at (s->get_locus (), "failure to resolve type");
          context->pop_expected_type ();
+         if (has_label)
+           context->pop_loop_context ();
          return;
        }
 
@@ -732,27 +735,48 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr)
 
   context->pop_expected_type ();
 
+  TyTy::BaseType *tail_expr_type = nullptr;
   if (expr.has_expr ())
     {
       context->push_expected_type (outer_expected);
-      infered = TypeCheckExpr::Resolve (expr.get_final_expr ())->clone ();
+      tail_expr_type = TypeCheckExpr::Resolve (expr.get_final_expr ());
       context->pop_expected_type ();
     }
-  else if (expr.is_tail_reachable ())
-    infered = TyTy::TupleType::get_unit_type ();
-  else if (expr.has_label ())
+
+  TyTy::BaseType *label_context_type = nullptr;
+  bool label_context_type_infered = false;
+  if (has_label)
     {
-      TyTy::BaseType *loop_context_type = context->pop_loop_context ();
+      label_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 ()
+      label_context_type_infered
+       = (label_context_type->get_kind () != TyTy::TypeKind::INFER)
+         || ((label_context_type->get_kind () == TyTy::TypeKind::INFER)
+             && (((TyTy::InferType *) label_context_type)->get_infer_kind ()
                  != TyTy::InferType::GENERAL));
+    }
 
-      infered = loop_context_type_infered ? loop_context_type
-                                         : TyTy::TupleType::get_unit_type ();
+  if (tail_expr_type != nullptr)
+    {
+      if (label_context_type_infered)
+       {
+         if (tail_expr_type->get_kind () == TyTy::TypeKind::NEVER)
+           infered = label_context_type;
+         else
+           infered = unify_site (
+             expr.get_mappings ().get_hirid (),
+             TyTy::TyWithLocation (label_context_type),
+             TyTy::TyWithLocation (tail_expr_type,
+                                   expr.get_final_expr ().get_locus ()),
+             expr.get_locus ());
+       }
+      else
+       infered = tail_expr_type;
     }
+  else if (label_context_type_infered)
+    infered = label_context_type;
+  else if (expr.is_tail_reachable ())
+    infered = TyTy::TupleType::get_unit_type ();
   else
     {
       // FIXME this seems wrong
diff --git a/gcc/testsuite/rust/compile/issue-4538.rs 
b/gcc/testsuite/rust/compile/issue-4538.rs
new file mode 100644
index 000000000..fedc4f193
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-4538.rs
@@ -0,0 +1,22 @@
+#![feature(no_core)]
+#![no_core]
+
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+fn dump_number(num: i32) {
+    unsafe {
+        let a = "%i\n\0";
+        let c = a as *const str as *const i8;
+        printf(c, num);
+    }
+}
+
+fn main() -> i32 {
+    let c = 'block_c: {
+        break 'block_c 555;
+    };
+    dump_number(c);
+    0
+}

base-commit: 520f9e075285ee1759f99f88a0fa3b3506e95615
-- 
2.54.0

Reply via email to