From 136f0579d8a6cfacbdbfbac4c6a10b8447fcdf9e Mon Sep 17 00:00:00 2001
From: Gurinder Singh <frederick.the.fool@gmail.com>
Date: Wed, 30 Aug 2023 07:40:08 +0530
Subject: [PATCH] Make get_return_block() return Some only for HIR nodes in
 body

Fixes # 114918
---
 compiler/rustc_middle/src/hir/map/mod.rs      | 13 +++++++++++-
 .../issue-114918/const-in-fn-return-type.rs   | 10 ++++++++++
 .../const-in-fn-return-type.stderr            |  9 +++++++++
 .../const-in-impl-fn-return-type.rs           | 20 +++++++++++++++++++
 .../const-in-impl-fn-return-type.stderr       |  9 +++++++++
 .../issue-114918/const-in-struct-type-arg.rs  | 12 +++++++++++
 .../const-in-struct-type-arg.stderr           |  9 +++++++++
 .../const-in-trait-fn-return-type.rs          | 13 ++++++++++++
 .../const-in-trait-fn-return-type.stderr      |  9 +++++++++
 9 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/typeck/issue-114918/const-in-fn-return-type.rs
 create mode 100644 tests/ui/typeck/issue-114918/const-in-fn-return-type.stderr
 create mode 100644 tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs
 create mode 100644 tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr
 create mode 100644 tests/ui/typeck/issue-114918/const-in-struct-type-arg.rs
 create mode 100644 tests/ui/typeck/issue-114918/const-in-struct-type-arg.stderr
 create mode 100644 tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.rs
 create mode 100644 tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.stderr

diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 467962b39bb1b..81de70c03d4ae 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -701,6 +701,8 @@ impl<'hir> Map<'hir> {
             // expressions.
             ignore_tail = true;
         }
+
+        let mut prev_hir_id = None;
         while let Some((hir_id, node)) = iter.next() {
             if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
                 match next_node {
@@ -715,7 +717,14 @@ impl<'hir> Map<'hir> {
                 | Node::ForeignItem(_)
                 | Node::TraitItem(_)
                 | Node::Expr(Expr { kind: ExprKind::Closure { .. }, .. })
-                | Node::ImplItem(_) => return Some(hir_id),
+                | Node::ImplItem(_)
+                    // The input node `id` must be enclosed in the method's body as opposed
+                    // to some other place such as its return type (fixes #114918).
+                    // We verify that indirectly by checking that the previous node is the
+                    // current node's body
+                    if node.body_id().map(|b| b.hir_id) == prev_hir_id =>  {
+                        return Some(hir_id)
+                }
                 // Ignore `return`s on the first iteration
                 Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
                 | Node::Local(_) => {
@@ -723,6 +732,8 @@ impl<'hir> Map<'hir> {
                 }
                 _ => {}
             }
+
+            prev_hir_id = Some(hir_id);
         }
         None
     }
diff --git a/tests/ui/typeck/issue-114918/const-in-fn-return-type.rs b/tests/ui/typeck/issue-114918/const-in-fn-return-type.rs
new file mode 100644
index 0000000000000..d939633290e82
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-fn-return-type.rs
@@ -0,0 +1,10 @@
+// Regression test for #114918
+// Test that a const generic enclosed in a block within a return type
+// produces a type mismatch error instead of triggering a const eval cycle
+
+#[allow(unused_braces)]
+fn func() -> [u8; { () } ] { //~ ERROR mismatched types
+    loop {}
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/issue-114918/const-in-fn-return-type.stderr b/tests/ui/typeck/issue-114918/const-in-fn-return-type.stderr
new file mode 100644
index 0000000000000..88ed96e148cc2
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-fn-return-type.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/const-in-fn-return-type.rs:6:21
+   |
+LL | fn func() -> [u8; { () } ] {
+   |                     ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs
new file mode 100644
index 0000000000000..a1b9a7eba4da7
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs
@@ -0,0 +1,20 @@
+// Regression test for #114918
+// Test that a const generic enclosed in a block within the return type
+// of an impl fn produces a type mismatch error instead of triggering
+// a const eval cycle
+
+
+trait Trait {
+    fn func<const N: u32>() -> [ (); N ];
+}
+
+struct S {}
+
+#[allow(unused_braces)]
+impl Trait for S {
+    fn func<const N: u32>() -> [ (); { () }] { //~ ERROR mismatched types
+        N
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr
new file mode 100644
index 0000000000000..9843651b1e699
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/const-in-impl-fn-return-type.rs:15:40
+   |
+LL |     fn func<const N: u32>() -> [ (); { () }] {
+   |                                        ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/issue-114918/const-in-struct-type-arg.rs b/tests/ui/typeck/issue-114918/const-in-struct-type-arg.rs
new file mode 100644
index 0000000000000..9eee4ab3d4c38
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-struct-type-arg.rs
@@ -0,0 +1,12 @@
+// Regression test for #114918
+// Test that a const generic enclosed in a block in a struct's type arg
+// produces a type mismatch error instead of triggering a const eval cycle
+
+#[allow(unused_braces)]
+struct S<const N: usize> {
+        arr: [u8; N]
+}
+
+fn main() {
+    let s = S::<{ () }> { arr: [5, 6, 7]}; //~ ERROR mismatched types
+}
diff --git a/tests/ui/typeck/issue-114918/const-in-struct-type-arg.stderr b/tests/ui/typeck/issue-114918/const-in-struct-type-arg.stderr
new file mode 100644
index 0000000000000..3307e76d95755
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-struct-type-arg.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/const-in-struct-type-arg.rs:11:19
+   |
+LL |     let s = S::<{ () }> { arr: [5, 6, 7]};
+   |                   ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.rs b/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.rs
new file mode 100644
index 0000000000000..8e2eec3491141
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.rs
@@ -0,0 +1,13 @@
+// Regression test for #114918
+// Test that a const generic enclosed in a block within the return type
+// of a trait method produces a type mismatch error instead of triggering
+// a const eval cycle
+
+#[allow(unused_braces)]
+trait Trait {
+    fn func<const N: u32>() -> [ (); { () }] { //~ ERROR mismatched types
+        N
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.stderr b/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.stderr
new file mode 100644
index 0000000000000..6bc0de77a6267
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/const-in-trait-fn-return-type.rs:8:40
+   |
+LL |     fn func<const N: u32>() -> [ (); { () }] {
+   |                                        ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.