Skip to content

Commit f6767f7

Browse files
committed
Detect * operator on !Sized expression
``` 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 = ""; | ```
1 parent d3a3939 commit f6767f7

File tree

10 files changed

+187
-9
lines changed

10 files changed

+187
-9
lines changed

compiler/rustc_hir_typeck/src/expr.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -841,13 +841,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
841841
let ret_ty = ret_coercion.borrow().expected_ty();
842842
let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
843843
let mut span = return_expr.span;
844+
let mut hir_id = return_expr.hir_id;
844845
// Use the span of the trailing expression for our cause,
845846
// not the span of the entire function
846847
if !explicit_return
847848
&& let ExprKind::Block(body, _) = return_expr.kind
848849
&& let Some(last_expr) = body.expr
849850
{
850851
span = last_expr.span;
852+
hir_id = last_expr.hir_id;
851853
}
852854
ret_coercion.borrow_mut().coerce(
853855
self,
@@ -864,6 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
864866
self.select_obligations_where_possible(|errors| {
865867
self.point_at_return_for_opaque_ty_error(
866868
errors,
869+
hir_id,
867870
span,
868871
return_expr_ty,
869872
return_expr.span,
@@ -921,6 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
921924
fn point_at_return_for_opaque_ty_error(
922925
&self,
923926
errors: &mut Vec<traits::FulfillmentError<'tcx>>,
927+
hir_id: HirId,
924928
span: Span,
925929
return_expr_ty: Ty<'tcx>,
926930
return_span: Span,
@@ -935,7 +939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
935939
let new_cause = ObligationCause::new(
936940
cause.span,
937941
cause.body_id,
938-
ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, span))),
942+
ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, hir_id))),
939943
);
940944
*cause = new_cause;
941945
}

compiler/rustc_middle/src/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ pub enum ObligationCauseCode<'tcx> {
353353
ReturnValue(HirId),
354354

355355
/// Opaque return type of this function
356-
OpaqueReturnType(Option<(Ty<'tcx>, Span)>),
356+
OpaqueReturnType(Option<(Ty<'tcx>, HirId)>),
357357

358358
/// Block implicit return
359359
BlockTailExpression(HirId, hir::MatchSource),

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

+42-7
Original file line numberDiff line numberDiff line change
@@ -2725,6 +2725,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
27252725

27262726
let tcx = self.tcx;
27272727
let predicate = predicate.upcast(tcx);
2728+
let suggest_remove_deref = |err: &mut Diag<'_, G>, expr: &hir::Expr<'_>| {
2729+
if let Some(pred) = predicate.as_trait_clause()
2730+
&& tcx.is_lang_item(pred.def_id(), LangItem::Sized)
2731+
&& let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind
2732+
{
2733+
err.span_suggestion_verbose(
2734+
expr.span.until(inner.span),
2735+
"references are always `Sized`, even if they point to unsized data; consider \
2736+
not dereferencing the expression",
2737+
String::new(),
2738+
Applicability::MaybeIncorrect,
2739+
);
2740+
}
2741+
};
27282742
match *cause_code {
27292743
ObligationCauseCode::ExprAssignable
27302744
| ObligationCauseCode::MatchExpressionArm { .. }
@@ -2771,6 +2785,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
27712785
| ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)
27722786
if !span.is_dummy() =>
27732787
{
2788+
if let ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, pos) = &cause_code {
2789+
if let Node::Expr(expr) = tcx.parent_hir_node(*hir_id)
2790+
&& let hir::ExprKind::Call(_, args) = expr.kind
2791+
&& let Some(expr) = args.get(*pos)
2792+
{
2793+
suggest_remove_deref(err, &expr);
2794+
} else if let Node::Expr(expr) = self.tcx.hir_node(*hir_id)
2795+
&& let hir::ExprKind::MethodCall(_, _, args, _) = expr.kind
2796+
&& let Some(expr) = args.get(*pos)
2797+
{
2798+
suggest_remove_deref(err, &expr);
2799+
}
2800+
}
27742801
let item_name = tcx.def_path_str(item_def_id);
27752802
let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id));
27762803
let mut multispan = MultiSpan::from(span);
@@ -2968,6 +2995,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
29682995
));
29692996
err.downgrade_to_delayed_bug();
29702997
}
2998+
let mut local = true;
29712999
match tcx.parent_hir_node(hir_id) {
29723000
Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
29733001
err.span_suggestion_verbose(
@@ -2976,7 +3004,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
29763004
"&",
29773005
Applicability::MachineApplicable,
29783006
);
2979-
err.note("all local variables must have a statically known size");
29803007
}
29813008
Node::LetStmt(hir::LetStmt {
29823009
init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }),
@@ -2991,7 +3018,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
29913018
"&",
29923019
Applicability::MachineApplicable,
29933020
);
2994-
err.note("all local variables must have a statically known size");
3021+
}
3022+
Node::LetStmt(hir::LetStmt { init: Some(expr), .. }) => {
3023+
// When encountering an assignment of an unsized trait, like `let x = *"";`,
3024+
// we check if the RHS is a deref operation, to suggest removing it.
3025+
suggest_remove_deref(err, &expr);
29953026
}
29963027
Node::Param(param) => {
29973028
err.span_suggestion_verbose(
@@ -3001,10 +3032,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
30013032
"&",
30023033
Applicability::MachineApplicable,
30033034
);
3035+
local = false;
30043036
}
3005-
_ => {
3006-
err.note("all local variables must have a statically known size");
3007-
}
3037+
_ => {}
3038+
}
3039+
if local {
3040+
err.note("all local variables must have a statically known size");
30083041
}
30093042
if !tcx.features().unsized_locals {
30103043
err.help("unsized locals are gated as an unstable feature");
@@ -3527,14 +3560,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
35273560
);
35283561
}
35293562
ObligationCauseCode::OpaqueReturnType(expr_info) => {
3530-
if let Some((expr_ty, expr_span)) = expr_info {
3563+
if let Some((expr_ty, hir_id)) = expr_info {
35313564
let expr_ty = self.tcx.short_ty_string(expr_ty, &mut long_ty_file);
3565+
let expr = self.infcx.tcx.hir().expect_expr(hir_id);
35323566
err.span_label(
3533-
expr_span,
3567+
expr.span,
35343568
with_forced_trimmed_paths!(format!(
35353569
"return type was inferred to be `{expr_ty}` here",
35363570
)),
35373571
);
3572+
suggest_remove_deref(err, &expr);
35383573
}
35393574
}
35403575
}

tests/ui/dst/dst-rvalue.stderr

+10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ LL | let _x: Box<str> = Box::new(*"hello world");
99
= help: the trait `Sized` is not implemented for `str`
1010
note: required by a bound in `Box::<T>::new`
1111
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
12+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
13+
|
14+
LL - let _x: Box<str> = Box::new(*"hello world");
15+
LL + let _x: Box<str> = Box::new("hello world");
16+
|
1217

1318
error[E0277]: the size for values of type `[isize]` cannot be known at compilation time
1419
--> $DIR/dst-rvalue.rs:8:37
@@ -21,6 +26,11 @@ LL | let _x: Box<[isize]> = Box::new(*array);
2126
= help: the trait `Sized` is not implemented for `[isize]`
2227
note: required by a bound in `Box::<T>::new`
2328
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
29+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
30+
|
31+
LL - let _x: Box<[isize]> = Box::new(*array);
32+
LL + let _x: Box<[isize]> = Box::new(array);
33+
|
2434

2535
error: aborting due to 2 previous errors
2636

tests/ui/issues/issue-17651.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ LL | (|| Box::new(*(&[0][..])))();
99
= help: the trait `Sized` is not implemented for `[{integer}]`
1010
note: required by a bound in `Box::<T>::new`
1111
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
12+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
13+
|
14+
LL - (|| Box::new(*(&[0][..])))();
15+
LL + (|| Box::new((&[0][..])))();
16+
|
1217

1318
error: aborting due to 1 previous error
1419

tests/ui/sized/unsized-binding.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ LL | let x = *"";
77
= help: the trait `Sized` is not implemented for `str`
88
= note: all local variables must have a statically known size
99
= help: unsized locals are gated as an unstable feature
10+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
11+
|
12+
LL - let x = *"";
13+
LL + let x = "";
14+
|
1015

1116
error: aborting due to 1 previous error
1217

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
fn foo() -> impl Sized {
2+
//~^ ERROR the size for values of type `str` cannot be known at compilation time
3+
//~| HELP the trait `Sized` is not implemented for `str`
4+
*"" //~ HELP consider not dereferencing the expression
5+
}
6+
fn bar(_: impl Sized) {}
7+
struct S;
8+
9+
impl S {
10+
fn baz(&self, _: impl Sized) {}
11+
}
12+
13+
fn main() {
14+
let _ = foo();
15+
let x = *"";
16+
//~^ ERROR the size for values of type `str` cannot be known at compilation time
17+
//~| HELP consider not dereferencing the expression
18+
//~| HELP the trait `Sized` is not implemented for `str`
19+
//~| HELP unsized locals are gated as an unstable feature
20+
bar(x);
21+
S.baz(x);
22+
bar(*"");
23+
//~^ ERROR the size for values of type `str` cannot be known at compilation time
24+
//~| HELP consider not dereferencing the expression
25+
//~| HELP the trait `Sized` is not implemented for `str`
26+
S.baz(*"");
27+
//~^ ERROR the size for values of type `str` cannot be known at compilation time
28+
//~| HELP consider not dereferencing the expression
29+
//~| HELP the trait `Sized` is not implemented for `str`
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
error[E0277]: the size for values of type `str` cannot be known at compilation time
2+
--> $DIR/unsized-str-in-return-expr-arg-and-local.rs:1:13
3+
|
4+
LL | fn foo() -> impl Sized {
5+
| ^^^^^^^^^^ doesn't have a size known at compile-time
6+
...
7+
LL | *""
8+
| --- return type was inferred to be `str` here
9+
|
10+
= help: the trait `Sized` is not implemented for `str`
11+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
12+
|
13+
LL - *""
14+
LL + ""
15+
|
16+
17+
error[E0277]: the size for values of type `str` cannot be known at compilation time
18+
--> $DIR/unsized-str-in-return-expr-arg-and-local.rs:15:9
19+
|
20+
LL | let x = *"";
21+
| ^ doesn't have a size known at compile-time
22+
|
23+
= help: the trait `Sized` is not implemented for `str`
24+
= note: all local variables must have a statically known size
25+
= help: unsized locals are gated as an unstable feature
26+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
27+
|
28+
LL - let x = *"";
29+
LL + let x = "";
30+
|
31+
32+
error[E0277]: the size for values of type `str` cannot be known at compilation time
33+
--> $DIR/unsized-str-in-return-expr-arg-and-local.rs:22:9
34+
|
35+
LL | bar(*"");
36+
| --- ^^^ doesn't have a size known at compile-time
37+
| |
38+
| required by a bound introduced by this call
39+
|
40+
= help: the trait `Sized` is not implemented for `str`
41+
note: required by a bound in `bar`
42+
--> $DIR/unsized-str-in-return-expr-arg-and-local.rs:6:16
43+
|
44+
LL | fn bar(_: impl Sized) {}
45+
| ^^^^^ required by this bound in `bar`
46+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
47+
|
48+
LL - bar(*"");
49+
LL + bar("");
50+
|
51+
52+
error[E0277]: the size for values of type `str` cannot be known at compilation time
53+
--> $DIR/unsized-str-in-return-expr-arg-and-local.rs:26:11
54+
|
55+
LL | S.baz(*"");
56+
| --- ^^^ doesn't have a size known at compile-time
57+
| |
58+
| required by a bound introduced by this call
59+
|
60+
= help: the trait `Sized` is not implemented for `str`
61+
note: required by a bound in `S::baz`
62+
--> $DIR/unsized-str-in-return-expr-arg-and-local.rs:10:27
63+
|
64+
LL | fn baz(&self, _: impl Sized) {}
65+
| ^^^^^ required by this bound in `S::baz`
66+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
67+
|
68+
LL - S.baz(*"");
69+
LL + S.baz("");
70+
|
71+
72+
error: aborting due to 4 previous errors
73+
74+
For more information about this error, try `rustc --explain E0277`.

tests/ui/suggestions/issue-84973-blacklist.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ note: required by a bound in `f_sized`
6666
|
6767
LL | fn f_sized<T: Sized>(t: T) {}
6868
| ^^^^^ required by this bound in `f_sized`
69+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
70+
|
71+
LL - f_sized(*ref_cl);
72+
LL + f_sized(ref_cl);
73+
|
6974

7075
error[E0277]: `Rc<{integer}>` cannot be sent between threads safely
7176
--> $DIR/issue-84973-blacklist.rs:27:12

tests/ui/unsized/unsized6.stderr

+10
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
123123
LL - fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
124124
LL + fn f3<X>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
125125
|
126+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
127+
|
128+
LL - let y = *x2;
129+
LL + let y = x2;
130+
|
126131

127132
error[E0277]: the size for values of type `X` cannot be known at compilation time
128133
--> $DIR/unsized6.rs:26:10
@@ -177,6 +182,11 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
177182
LL - fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
178183
LL + fn f4<X: T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
179184
|
185+
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
186+
|
187+
LL - let y = *x2;
188+
LL + let y = x2;
189+
|
180190

181191
error[E0277]: the size for values of type `X` cannot be known at compilation time
182192
--> $DIR/unsized6.rs:34:10

0 commit comments

Comments
 (0)