mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
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.
This commit is contained in:
commit
00308920ae
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
30
tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs
Normal file
30
tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs
Normal file
@ -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`
|
||||
}
|
@ -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`.
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user