about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs64
-rw-r--r--tests/crashes/128810.rs25
-rw-r--r--tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs34
-rw-r--r--tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr113
-rw-r--r--tests/ui/typeck/const-in-fn-call-generics.rs16
-rw-r--r--tests/ui/typeck/const-in-fn-call-generics.stderr9
6 files changed, 199 insertions, 62 deletions
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index edab6b5ebde..da08027d66b 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -554,53 +554,43 @@ impl<'hir> Map<'hir> {
     /// }
     /// ```
     pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
-        let mut iter = self.parent_iter(id).peekable();
-        let mut ignore_tail = false;
-        if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
-            // When dealing with `return` statements, we don't care about climbing only tail
-            // expressions.
-            ignore_tail = true;
-        }
+        let enclosing_body_owner = self.tcx.local_def_id_to_hir_id(self.enclosing_body_owner(id));
+
+        // Return `None` if the `id` expression is not the returned value of the enclosing body
+        let mut iter = [id].into_iter().chain(self.parent_id_iter(id)).peekable();
+        while let Some(cur_id) = iter.next() {
+            if enclosing_body_owner == cur_id {
+                break;
+            }
+
+            // A return statement is always the value returned from the enclosing body regardless of
+            // what the parent expressions are.
+            if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(cur_id) {
+                break;
+            }
 
-        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 {
-                    Node::Block(Block { expr: None, .. }) => return None,
-                    // The current node is not the tail expression of its parent.
-                    Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
+            // If the current expression's value doesnt get used as the parent expressions value then return `None`
+            if let Some(&parent_id) = iter.peek() {
+                match self.tcx.hir_node(parent_id) {
+                    // The current node is not the tail expression of the block expression parent expr.
+                    Node::Block(Block { expr: Some(e), .. }) if cur_id != e.hir_id => return None,
                     Node::Block(Block { expr: Some(e), .. })
                         if matches!(e.kind, ExprKind::If(_, _, None)) =>
                     {
                         return None;
                     }
+
+                    // The current expression's value does not pass up through these parent expressions
+                    Node::Block(Block { expr: None, .. })
+                    | Node::Expr(Expr { kind: ExprKind::Loop(..), .. })
+                    | Node::LetStmt(..) => return None,
+
                     _ => {}
                 }
             }
-            match node {
-                Node::Item(_)
-                | Node::ForeignItem(_)
-                | Node::TraitItem(_)
-                | Node::Expr(Expr { kind: ExprKind::Closure(_), .. })
-                | 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::LetStmt(_) => {
-                    return None;
-                }
-                _ => {}
-            }
-
-            prev_hir_id = Some(hir_id);
         }
-        None
+
+        Some(enclosing_body_owner)
     }
 
     /// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
diff --git a/tests/crashes/128810.rs b/tests/crashes/128810.rs
deleted file mode 100644
index 68214ff010c..00000000000
--- a/tests/crashes/128810.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-//@ known-bug: rust-lang/rust#128810
-
-#![feature(fn_delegation)]
-
-use std::marker::PhantomData;
-
-pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
-
-impl<'a> InvariantRef<'a, ()> {
-    pub const NEW: Self = InvariantRef::new(&());
-}
-
-trait Trait {
-    fn foo(&self) -> u8 { 0 }
-    fn bar(&self) -> u8 { 1 }
-    fn meh(&self) -> u8 { 2 }
-}
-
-struct Z(u8);
-
-impl Trait for Z {
-    reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
-}
-
-fn main() { }
diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs
new file mode 100644
index 00000000000..0a7ec5ab5c1
--- /dev/null
+++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs
@@ -0,0 +1,34 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+use std::marker::PhantomData;
+
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a> InvariantRef<'a, ()> {
+    pub const NEW: Self = InvariantRef::new(&());
+    //~^ ERROR: no function or associated item named `new` found
+}
+
+trait Trait {
+    fn foo(&self) -> u8 { 0 }
+    fn bar(&self) -> u8 { 1 }
+    fn meh(&self) -> u8 { 2 }
+}
+
+struct Z(u8);
+
+impl Trait for Z {
+    reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+    //~^ ERROR: use of undeclared lifetime name `'a`
+    //~| ERROR: use of undeclared lifetime name `'a`
+    //~| ERROR: use of undeclared lifetime name `'a`
+    //~| ERROR: the trait bound `u8: Trait` is not satisfied
+    //~| ERROR: the trait bound `u8: Trait` is not satisfied
+    //~| ERROR: the trait bound `u8: Trait` is not satisfied
+    //~| ERROR: mismatched types
+    //~| ERROR: mismatched types
+    //~| ERROR: mismatched types
+}
+
+fn main() { }
diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr
new file mode 100644
index 00000000000..2ce3b388073
--- /dev/null
+++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr
@@ -0,0 +1,113 @@
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                                    ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL |     reuse <u8 as Trait>::{foo'a, , bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                              +++
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> Trait for Z {
+   |     ++++
+
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                                    ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL |     reuse <u8 as Trait>::{foo, bar'a, , meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                   +++
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> Trait for Z {
+   |     ++++
+
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                                    ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh'a, } { &const { InvariantRef::<'a>::NEW } }
+   |                                        +++
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> Trait for Z {
+   |     ++++
+
+error[E0599]: no function or associated item named `new` found for struct `InvariantRef` in the current scope
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41
+   |
+LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+   | -------------------------------------- function or associated item `new` not found for this struct
+...
+LL |     pub const NEW: Self = InvariantRef::new(&());
+   |                                         ^^^ function or associated item not found in `InvariantRef<'_, _>`
+
+error[E0308]: mismatched types
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+   |
+   = note: expected type `u8`
+            found struct `InvariantRef<'_, ()>`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |            ^^ the trait `Trait` is not implemented for `u8`
+   |
+   = help: the trait `Trait` is implemented for `Z`
+
+error[E0308]: mismatched types
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+   |
+   = note: expected type `u8`
+            found struct `InvariantRef<'_, ()>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |            ^^ the trait `Trait` is not implemented for `u8`
+   |
+   = help: the trait `Trait` is implemented for `Z`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0308]: mismatched types
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+   |
+   = note: expected type `u8`
+            found struct `InvariantRef<'_, ()>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |            ^^ the trait `Trait` is not implemented for `u8`
+   |
+   = help: the trait `Trait` is implemented for `Z`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0261, E0277, E0308, E0599.
+For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/typeck/const-in-fn-call-generics.rs b/tests/ui/typeck/const-in-fn-call-generics.rs
new file mode 100644
index 00000000000..675dbcc3054
--- /dev/null
+++ b/tests/ui/typeck/const-in-fn-call-generics.rs
@@ -0,0 +1,16 @@
+fn generic<const N: u32>() {}
+
+trait Collate<const A: u32> {
+    type Pass;
+    fn collate(self) -> Self::Pass;
+}
+
+impl<const B: u32> Collate<B> for i32 {
+    type Pass = ();
+    fn collate(self) -> Self::Pass {
+        generic::<{ true }>()
+        //~^ ERROR: mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/const-in-fn-call-generics.stderr b/tests/ui/typeck/const-in-fn-call-generics.stderr
new file mode 100644
index 00000000000..12dd454188c
--- /dev/null
+++ b/tests/ui/typeck/const-in-fn-call-generics.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/const-in-fn-call-generics.rs:11:21
+   |
+LL |         generic::<{ true }>()
+   |                     ^^^^ expected `u32`, found `bool`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.