Skip to content

Commit

Permalink
Rollup merge of #115313 - gurry:issue-114918-cycle-detected, r=compil…
Browse files Browse the repository at this point in the history
…er-errors

Make `get_return_block()` return `Some` only for HIR nodes in body

Fixes #114918

The issue occurred while compiling the following input:

```rust
fn uwu() -> [(); { () }] {
    loop {}
}
```

It was caused by the code below trying to suggest a missing return type which resulted in a const eval cycle: https://github.com/rust-lang/rust/blob/1bd043098e05839afb557bd7a2858cb09a4054ca/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs#L68-L75

The root cause was `get_return_block()` returning an `Fn` node for a node in the return type (i.e. the second `()` in the return type `[(); { () }]` of the input) although it is supposed to do so only for nodes that lie in the body of the function and return `None` otherwise (at least as per my understanding).

The PR fixes the issue by fixing this behaviour of `get_return_block()`.
  • Loading branch information
matthiaskrgr committed Aug 30, 2023
2 parents 23f8625 + 136f057 commit 2128efd
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 1 deletion.
13 changes: 12 additions & 1 deletion compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -715,14 +717,23 @@ 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(_) => {
return None;
}
_ => {}
}

prev_hir_id = Some(hir_id);
}
None
}
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/typeck/issue-114918/const-in-fn-return-type.rs
Original file line number Diff line number Diff line change
@@ -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() {}
9 changes: 9 additions & 0 deletions tests/ui/typeck/issue-114918/const-in-fn-return-type.stderr
Original file line number Diff line number Diff line change
@@ -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`.
20 changes: 20 additions & 0 deletions tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
12 changes: 12 additions & 0 deletions tests/ui/typeck/issue-114918/const-in-struct-type-arg.rs
Original file line number Diff line number Diff line change
@@ -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
}
9 changes: 9 additions & 0 deletions tests/ui/typeck/issue-114918/const-in-struct-type-arg.stderr
Original file line number Diff line number Diff line change
@@ -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`.
13 changes: 13 additions & 0 deletions tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 2128efd

Please sign in to comment.