about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTrevor Gross <t.gross35@gmail.com>2024-08-24 21:03:30 -0500
committerGitHub <noreply@github.com>2024-08-24 21:03:30 -0500
commit00308920aec0795e9de1a3f80324ac93b502a483 (patch)
tree8c9e57d8f0b6c846ced5e805402b5aab6aa8a8a0
parentf167efad2f51088d86180ee89177b3d7c9e7c2f5 (diff)
parentf6767f7a68f42101e6820171c033565e0f3a807a (diff)
downloadrust-00308920aec0795e9de1a3f80324ac93b502a483.tar.gz
rust-00308920aec0795e9de1a3f80324ac93b502a483.zip
Rollup merge of #128467 - estebank:unsized-args, r=cjgillot
Detect `*` operator on `!Sized` expression

The suggestion is new:

```
error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:15:9
   |
LL |     let x = *"";
   |         ^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `str`
   = note: all local variables must have a statically known size
   = help: unsized locals are gated as an unstable feature
help: references to `!Sized` types like `&str` are `Sized`; consider not dereferencing the expression
   |
LL -     let x = *"";
LL +     let x = "";
   |
```

Fix #128199.
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs6
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs49
-rw-r--r--tests/ui/dst/dst-rvalue.stderr10
-rw-r--r--tests/ui/issues/issue-17651.stderr5
-rw-r--r--tests/ui/sized/unsized-binding.stderr5
-rw-r--r--tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs30
-rw-r--r--tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr74
-rw-r--r--tests/ui/suggestions/issue-84973-blacklist.stderr5
-rw-r--r--tests/ui/unsized/unsized6.stderr10
10 files changed, 187 insertions, 9 deletions
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index fec6efdc0f7..91778a36668 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -841,6 +841,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let ret_ty = ret_coercion.borrow().expected_ty();
         let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
         let mut span = return_expr.span;
+        let mut hir_id = return_expr.hir_id;
         // Use the span of the trailing expression for our cause,
         // not the span of the entire function
         if !explicit_return
@@ -848,6 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let Some(last_expr) = body.expr
         {
             span = last_expr.span;
+            hir_id = last_expr.hir_id;
         }
         ret_coercion.borrow_mut().coerce(
             self,
@@ -864,6 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.select_obligations_where_possible(|errors| {
                 self.point_at_return_for_opaque_ty_error(
                     errors,
+                    hir_id,
                     span,
                     return_expr_ty,
                     return_expr.span,
@@ -921,6 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn point_at_return_for_opaque_ty_error(
         &self,
         errors: &mut Vec<traits::FulfillmentError<'tcx>>,
+        hir_id: HirId,
         span: Span,
         return_expr_ty: Ty<'tcx>,
         return_span: Span,
@@ -935,7 +939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let new_cause = ObligationCause::new(
                     cause.span,
                     cause.body_id,
-                    ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, span))),
+                    ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, hir_id))),
                 );
                 *cause = new_cause;
             }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index d54e2ca0a74..a3277fb96d2 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -353,7 +353,7 @@ pub enum ObligationCauseCode<'tcx> {
     ReturnValue(HirId),
 
     /// Opaque return type of this function
-    OpaqueReturnType(Option<(Ty<'tcx>, Span)>),
+    OpaqueReturnType(Option<(Ty<'tcx>, HirId)>),
 
     /// Block implicit return
     BlockTailExpression(HirId, hir::MatchSource),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index a962be54c3d..228b75cd73c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -2727,6 +2727,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         let tcx = self.tcx;
         let predicate = predicate.upcast(tcx);
+        let suggest_remove_deref = |err: &mut Diag<'_, G>, expr: &hir::Expr<'_>| {
+            if let Some(pred) = predicate.as_trait_clause()
+                && tcx.is_lang_item(pred.def_id(), LangItem::Sized)
+                && let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind
+            {
+                err.span_suggestion_verbose(
+                    expr.span.until(inner.span),
+                    "references are always `Sized`, even if they point to unsized data; consider \
+                     not dereferencing the expression",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        };
         match *cause_code {
             ObligationCauseCode::ExprAssignable
             | ObligationCauseCode::MatchExpressionArm { .. }
@@ -2773,6 +2787,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)
                 if !span.is_dummy() =>
             {
+                if let ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, pos) = &cause_code {
+                    if let Node::Expr(expr) = tcx.parent_hir_node(*hir_id)
+                        && let hir::ExprKind::Call(_, args) = expr.kind
+                        && let Some(expr) = args.get(*pos)
+                    {
+                        suggest_remove_deref(err, &expr);
+                    } else if let Node::Expr(expr) = self.tcx.hir_node(*hir_id)
+                        && let hir::ExprKind::MethodCall(_, _, args, _) = expr.kind
+                        && let Some(expr) = args.get(*pos)
+                    {
+                        suggest_remove_deref(err, &expr);
+                    }
+                }
                 let item_name = tcx.def_path_str(item_def_id);
                 let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id));
                 let mut multispan = MultiSpan::from(span);
@@ -2970,6 +2997,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     ));
                     err.downgrade_to_delayed_bug();
                 }
+                let mut local = true;
                 match tcx.parent_hir_node(hir_id) {
                     Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
                         err.span_suggestion_verbose(
@@ -2978,7 +3006,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             "&",
                             Applicability::MachineApplicable,
                         );
-                        err.note("all local variables must have a statically known size");
                     }
                     Node::LetStmt(hir::LetStmt {
                         init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }),
@@ -2993,7 +3020,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             "&",
                             Applicability::MachineApplicable,
                         );
-                        err.note("all local variables must have a statically known size");
+                    }
+                    Node::LetStmt(hir::LetStmt { init: Some(expr), .. }) => {
+                        // When encountering an assignment of an unsized trait, like `let x = *"";`,
+                        // we check if the RHS is a deref operation, to suggest removing it.
+                        suggest_remove_deref(err, &expr);
                     }
                     Node::Param(param) => {
                         err.span_suggestion_verbose(
@@ -3003,10 +3034,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             "&",
                             Applicability::MachineApplicable,
                         );
+                        local = false;
                     }
-                    _ => {
-                        err.note("all local variables must have a statically known size");
-                    }
+                    _ => {}
+                }
+                if local {
+                    err.note("all local variables must have a statically known size");
                 }
                 if !tcx.features().unsized_locals {
                     err.help("unsized locals are gated as an unstable feature");
@@ -3529,14 +3562,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 );
             }
             ObligationCauseCode::OpaqueReturnType(expr_info) => {
-                if let Some((expr_ty, expr_span)) = expr_info {
+                if let Some((expr_ty, hir_id)) = expr_info {
                     let expr_ty = self.tcx.short_ty_string(expr_ty, &mut long_ty_file);
+                    let expr = self.infcx.tcx.hir().expect_expr(hir_id);
                     err.span_label(
-                        expr_span,
+                        expr.span,
                         with_forced_trimmed_paths!(format!(
                             "return type was inferred to be `{expr_ty}` here",
                         )),
                     );
+                    suggest_remove_deref(err, &expr);
                 }
             }
         }
diff --git a/tests/ui/dst/dst-rvalue.stderr b/tests/ui/dst/dst-rvalue.stderr
index 8d0a82b707d..d8c529617f7 100644
--- a/tests/ui/dst/dst-rvalue.stderr
+++ b/tests/ui/dst/dst-rvalue.stderr
@@ -9,6 +9,11 @@ LL |     let _x: Box<str> = Box::new(*"hello world");
    = help: the trait `Sized` is not implemented for `str`
 note: required by a bound in `Box::<T>::new`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let _x: Box<str> = Box::new(*"hello world");
+LL +     let _x: Box<str> = Box::new("hello world");
+   |
 
 error[E0277]: the size for values of type `[isize]` cannot be known at compilation time
   --> $DIR/dst-rvalue.rs:8:37
@@ -21,6 +26,11 @@ LL |     let _x: Box<[isize]> = Box::new(*array);
    = help: the trait `Sized` is not implemented for `[isize]`
 note: required by a bound in `Box::<T>::new`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let _x: Box<[isize]> = Box::new(*array);
+LL +     let _x: Box<[isize]> = Box::new(array);
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-17651.stderr b/tests/ui/issues/issue-17651.stderr
index 0c95a3c0c40..9519507320d 100644
--- a/tests/ui/issues/issue-17651.stderr
+++ b/tests/ui/issues/issue-17651.stderr
@@ -9,6 +9,11 @@ LL |     (|| Box::new(*(&[0][..])))();
    = help: the trait `Sized` is not implemented for `[{integer}]`
 note: required by a bound in `Box::<T>::new`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     (|| Box::new(*(&[0][..])))();
+LL +     (|| Box::new((&[0][..])))();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/sized/unsized-binding.stderr b/tests/ui/sized/unsized-binding.stderr
index 7c3276032c2..8de236cd0b6 100644
--- a/tests/ui/sized/unsized-binding.stderr
+++ b/tests/ui/sized/unsized-binding.stderr
@@ -7,6 +7,11 @@ LL |     let x = *"";
    = help: the trait `Sized` is not implemented for `str`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let x = *"";
+LL +     let x = "";
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs
new file mode 100644
index 00000000000..35abbb80d99
--- /dev/null
+++ b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs
@@ -0,0 +1,30 @@
+fn foo() -> impl Sized {
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+    *"" //~ HELP consider not dereferencing the expression
+}
+fn bar(_: impl Sized) {}
+struct S;
+
+impl S {
+    fn baz(&self, _: impl Sized) {}
+}
+
+fn main() {
+    let _ = foo();
+    let x = *"";
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    //~| HELP consider not dereferencing the expression
+    //~| HELP the trait `Sized` is not implemented for `str`
+    //~| HELP unsized locals are gated as an unstable feature
+    bar(x);
+    S.baz(x);
+    bar(*"");
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    //~| HELP consider not dereferencing the expression
+    //~| HELP the trait `Sized` is not implemented for `str`
+    S.baz(*"");
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    //~| HELP consider not dereferencing the expression
+    //~| HELP the trait `Sized` is not implemented for `str`
+}
diff --git a/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr
new file mode 100644
index 00000000000..9b7258aff12
--- /dev/null
+++ b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr
@@ -0,0 +1,74 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:1:13
+   |
+LL | fn foo() -> impl Sized {
+   |             ^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL |     *""
+   |     --- return type was inferred to be `str` here
+   |
+   = help: the trait `Sized` is not implemented for `str`
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     *""
+LL +     ""
+   |
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:15:9
+   |
+LL |     let x = *"";
+   |         ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let x = *"";
+LL +     let x = "";
+   |
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:22:9
+   |
+LL |     bar(*"");
+   |     --- ^^^ 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 by a bound in `bar`
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:6:16
+   |
+LL | fn bar(_: impl Sized) {}
+   |                ^^^^^ required by this bound in `bar`
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     bar(*"");
+LL +     bar("");
+   |
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:26:11
+   |
+LL |     S.baz(*"");
+   |       --- ^^^ 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 by a bound in `S::baz`
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:10:27
+   |
+LL |     fn baz(&self, _: impl Sized) {}
+   |                           ^^^^^ required by this bound in `S::baz`
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     S.baz(*"");
+LL +     S.baz("");
+   |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr
index 4fd063e4692..c1ef1cd428e 100644
--- a/tests/ui/suggestions/issue-84973-blacklist.stderr
+++ b/tests/ui/suggestions/issue-84973-blacklist.stderr
@@ -66,6 +66,11 @@ note: required by a bound in `f_sized`
    |
 LL | fn f_sized<T: Sized>(t: T) {}
    |               ^^^^^ required by this bound in `f_sized`
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     f_sized(*ref_cl);
+LL +     f_sized(ref_cl);
+   |
 
 error[E0277]: `Rc<{integer}>` cannot be sent between threads safely
   --> $DIR/issue-84973-blacklist.rs:27:12
diff --git a/tests/ui/unsized/unsized6.stderr b/tests/ui/unsized/unsized6.stderr
index 56e7f60f9ff..d406120efc5 100644
--- a/tests/ui/unsized/unsized6.stderr
+++ b/tests/ui/unsized/unsized6.stderr
@@ -123,6 +123,11 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
 LL - fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL + fn f3<X>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
    |
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let y = *x2;
+LL +     let y = x2;
+   |
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:26:10
@@ -177,6 +182,11 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
 LL - fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL + fn f4<X: T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
    |
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let y = *x2;
+LL +     let y = x2;
+   |
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:34:10