diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2023-08-30 07:18:11 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-08-30 07:18:11 +0200 |
| commit | 2128efd87fcbd165e0885512c0f5d830092bb1a4 (patch) | |
| tree | 45c8040f91e41c687a6be35256ae7fb3539625f5 | |
| parent | 23f86255ef7cf044c50348d7fa937ca63f94896b (diff) | |
| parent | 136f0579d8a6cfacbdbfbac4c6a10b8447fcdf9e (diff) | |
| download | rust-2128efd87fcbd165e0885512c0f5d830092bb1a4.tar.gz rust-2128efd87fcbd165e0885512c0f5d830092bb1a4.zip | |
Rollup merge of #115313 - gurry:issue-114918-cycle-detected, r=compiler-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()`.
9 files changed, 103 insertions, 1 deletions
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 467962b39bb..81de70c03d4 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 00000000000..d939633290e --- /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 00000000000..88ed96e148c --- /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 00000000000..a1b9a7eba4d --- /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 00000000000..9843651b1e6 --- /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 00000000000..9eee4ab3d4c --- /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 00000000000..3307e76d957 --- /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 00000000000..8e2eec34911 --- /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 00000000000..6bc0de77a62 --- /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`. |
