about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs38
-rw-r--r--src/test/ui/proc-macro/signature.stderr5
-rw-r--r--src/test/ui/unsized/unsized-fn-param.stderr16
-rw-r--r--src/test/ui/unsized/unsized3.rs1
-rw-r--r--src/test/ui/unsized/unsized3.stderr35
5 files changed, 77 insertions, 18 deletions
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index ede2ed5169f..dc49ff90f34 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1629,7 +1629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
-        for error in errors {
+        'outer: for error in errors {
             // Only if the cause is somewhere inside the expression we want try to point at arg.
             // Otherwise, it means that the cause is somewhere else and we should not change
             // anything because we can break the correct span.
@@ -1671,10 +1671,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     _ => continue,
                 };
             let self_ = self.resolve_vars_if_possible(self_);
+            let ty_matches_self = |ty: Ty<'tcx>| ty.walk().any(|arg| arg == self_);
+
+            let typeck_results = self.typeck_results.borrow();
+
+            for (idx, arg) in args.iter().enumerate() {
+                // Don't adjust the span if we already have a more precise span
+                // within one of the args.
+                if arg.span.contains(error.obligation.cause.span) {
+                    let references_arg =
+                        typeck_results.expr_ty_opt(arg).map_or(false, &ty_matches_self)
+                            || expected_tys.get(idx).copied().map_or(false, &ty_matches_self);
+                    if references_arg && !arg.span.from_expansion() {
+                        error.obligation.cause.map_code(|parent_code| {
+                            ObligationCauseCode::FunctionArgumentObligation {
+                                arg_hir_id: args[idx].hir_id,
+                                call_hir_id: expr.hir_id,
+                                parent_code,
+                            }
+                        })
+                    }
+                    continue 'outer;
+                }
+            }
 
             // Collect the argument position for all arguments that could have caused this
             // `FulfillmentError`.
-            let typeck_results = self.typeck_results.borrow();
             let mut referenced_in: Vec<_> = std::iter::zip(expected_tys, args)
                 .enumerate()
                 .flat_map(|(idx, (expected_ty, arg))| {
@@ -1688,7 +1710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let ty = self.resolve_vars_if_possible(ty);
                     // We walk the argument type because the argument's type could have
                     // been `Option<T>`, but the `FulfillmentError` references `T`.
-                    if ty.walk().any(|arg| arg == self_) { Some(i) } else { None }
+                    if ty_matches_self(ty) { Some(i) } else { None }
                 })
                 .collect();
 
@@ -1699,18 +1721,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             referenced_in.sort_unstable();
             referenced_in.dedup();
 
-            if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
+            if let &[idx] = &referenced_in[..] {
                 // Do not point at the inside of a macro.
                 // That would often result in poor error messages.
-                if args[ref_in].span.from_expansion() {
-                    return;
+                if args[idx].span.from_expansion() {
+                    continue;
                 }
                 // We make sure that only *one* argument matches the obligation failure
                 // and we assign the obligation's span to its expression's.
-                error.obligation.cause.span = args[ref_in].span;
+                error.obligation.cause.span = args[idx].span;
                 error.obligation.cause.map_code(|parent_code| {
                     ObligationCauseCode::FunctionArgumentObligation {
-                        arg_hir_id: args[ref_in].hir_id,
+                        arg_hir_id: args[idx].hir_id,
                         call_hir_id: expr.hir_id,
                         parent_code,
                     }
diff --git a/src/test/ui/proc-macro/signature.stderr b/src/test/ui/proc-macro/signature.stderr
index 78b0beff0da..a6bd98ddb19 100644
--- a/src/test/ui/proc-macro/signature.stderr
+++ b/src/test/ui/proc-macro/signature.stderr
@@ -5,10 +5,7 @@ LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
 LL | |
 LL | |     loop {}
 LL | | }
-   | | ^
-   | | |
-   | |_call the function in a closure: `|| unsafe { /* code */ }`
-   |   required by a bound introduced by this call
+   | |_^ call the function in a closure: `|| unsafe { /* code */ }`
    |
    = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
    = note: unsafe function cannot be called generically without an unsafe block
diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr
index 3eecca0fa09..edf0b895965 100644
--- a/src/test/ui/unsized/unsized-fn-param.stderr
+++ b/src/test/ui/unsized/unsized-fn-param.stderr
@@ -2,7 +2,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
   --> $DIR/unsized-fn-param.rs:11:11
    |
 LL |     foo11("bar", &"baz");
-   |           ^^^^^ doesn't have a size known at compile-time
+   |     ----- ^^^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `str`
    = note: required for the cast to the object type `dyn AsRef<Path>`
@@ -15,7 +17,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
   --> $DIR/unsized-fn-param.rs:13:19
    |
 LL |     foo12(&"bar", "baz");
-   |                   ^^^^^ doesn't have a size known at compile-time
+   |     -----         ^^^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `str`
    = note: required for the cast to the object type `dyn AsRef<Path>`
@@ -28,7 +32,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
   --> $DIR/unsized-fn-param.rs:16:11
    |
 LL |     foo21("bar", &"baz");
-   |           ^^^^^ doesn't have a size known at compile-time
+   |     ----- ^^^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `str`
    = note: required for the cast to the object type `dyn AsRef<str>`
@@ -41,7 +47,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
   --> $DIR/unsized-fn-param.rs:18:19
    |
 LL |     foo22(&"bar", "baz");
-   |                   ^^^^^ doesn't have a size known at compile-time
+   |     -----         ^^^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `str`
    = note: required for the cast to the object type `dyn AsRef<str>`
diff --git a/src/test/ui/unsized/unsized3.rs b/src/test/ui/unsized/unsized3.rs
index 39b6583bc4e..af76aca2c29 100644
--- a/src/test/ui/unsized/unsized3.rs
+++ b/src/test/ui/unsized/unsized3.rs
@@ -44,6 +44,7 @@ fn f9<X: ?Sized>(x1: Box<S<X>>) {
 fn f10<X: ?Sized>(x1: Box<S<X>>) {
     f5(&(32, *x1));
     //~^ ERROR the size for values of type
+    //~| ERROR the size for values of type
 }
 
 pub fn main() {}
diff --git a/src/test/ui/unsized/unsized3.stderr b/src/test/ui/unsized/unsized3.stderr
index 65bdc4c2ea3..d64091b15eb 100644
--- a/src/test/ui/unsized/unsized3.stderr
+++ b/src/test/ui/unsized/unsized3.stderr
@@ -101,6 +101,29 @@ LL + fn f9<X>(x1: Box<S<X>>) {
    |
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
+  --> $DIR/unsized3.rs:45:9
+   |
+LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
+   |        - this type parameter needs to be `std::marker::Sized`
+LL |     f5(&(32, *x1));
+   |     --  ^^^^^^^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required because it appears within the type `S<X>`
+  --> $DIR/unsized3.rs:28:8
+   |
+LL | struct S<X: ?Sized> {
+   |        ^
+   = note: required because it appears within the type `({integer}, S<X>)`
+   = note: tuples must have a statically known size to be initialized
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn f10<X: ?Sized>(x1: Box<S<X>>) {
+LL + fn f10<X>(x1: Box<S<X>>) {
+   |
+
+error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:45:8
    |
 LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
@@ -116,13 +139,21 @@ note: required because it appears within the type `S<X>`
 LL | struct S<X: ?Sized> {
    |        ^
    = note: required because it appears within the type `({integer}, S<X>)`
-   = note: tuples must have a statically known size to be initialized
+note: required by a bound in `f5`
+  --> $DIR/unsized3.rs:24:7
+   |
+LL | fn f5<Y>(x: &Y) {}
+   |       ^ required by this bound in `f5`
 help: consider removing the `?Sized` bound to make the type parameter `Sized`
    |
 LL - fn f10<X: ?Sized>(x1: Box<S<X>>) {
 LL + fn f10<X>(x1: Box<S<X>>) {
    |
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn f5<Y: ?Sized>(x: &Y) {}
+   |        ++++++++
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0277`.