Skip to content

Commit

Permalink
Check Sizedness of return type in WF
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Feb 3, 2025
1 parent a5db378 commit 7bc0b3c
Show file tree
Hide file tree
Showing 42 changed files with 451 additions and 394 deletions.
30 changes: 28 additions & 2 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,7 @@ fn check_associated_item(
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
check_sized_if_body(wfcx, item.def_id.expect_local(), ty, Some(span));
Ok(())
}
ty::AssocKind::Fn => {
Expand Down Expand Up @@ -1185,7 +1186,7 @@ fn check_type_defn<'tcx>(
),
wfcx.param_env,
ty,
tcx.require_lang_item(LangItem::Sized, None),
tcx.require_lang_item(LangItem::Sized, Some(hir_ty.span)),
);
}

Expand Down Expand Up @@ -1312,7 +1313,7 @@ fn check_item_type(
),
wfcx.param_env,
item_ty,
tcx.require_lang_item(LangItem::Sized, None),
tcx.require_lang_item(LangItem::Sized, Some(ty_span)),
);
}

Expand Down Expand Up @@ -1642,6 +1643,31 @@ fn check_fn_or_method<'tcx>(
);
}
}

// If the function has a body, additionally require that the return type is sized.
check_sized_if_body(wfcx, def_id, sig.output(), match hir_decl.output {
hir::FnRetTy::Return(ty) => Some(ty.span),
hir::FnRetTy::DefaultReturn(_) => None,
});
}

fn check_sized_if_body<'tcx>(
wfcx: &WfCheckingCtxt<'_, 'tcx>,
def_id: LocalDefId,
ty: Ty<'tcx>,
maybe_span: Option<Span>,
) {
let tcx = wfcx.tcx();
if let Some(body) = tcx.hir().maybe_body_owned_by(def_id) {
let span = maybe_span.unwrap_or(body.value.span);

wfcx.register_bound(
ObligationCause::new(span, def_id, traits::ObligationCauseCode::SizedReturnType),
wfcx.param_env,
ty,
tcx.require_lang_item(LangItem::Sized, Some(span)),
);
}
}

/// The `arbitrary_self_types_pointers` feature implies `arbitrary_self_types`.
Expand Down
7 changes: 1 addition & 6 deletions compiler/rustc_hir_typeck/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,7 @@ pub(super) fn check_fn<'a, 'tcx>(
hir::FnRetTy::Return(ty) => ty.span,
};

fcx.require_type_is_sized(
declared_ret_ty,
return_or_body_span,
ObligationCauseCode::SizedReturnType,
);
// We checked the root's signature during wfcheck, but not the child.
// We checked the root's ret ty during wfcheck, but not the child.
if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) {
fcx.require_type_is_sized(
declared_ret_ty,
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,6 @@ fn typeck_with_inspect<'tcx>(
let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id)));
fcx.register_wf_obligation(expected_type.into(), body.value.span, wf_code);

fcx.require_type_is_sized(expected_type, body.value.span, ObligationCauseCode::ConstSized);

// Gather locals in statics (because of block expressions).
GatherLocalsVisitor::new(&fcx).visit_body(body);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};

self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
err.emit()
}
}
Expand Down Expand Up @@ -806,7 +805,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
"Async",
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
return Some(err.emit());
}
}
Expand Down Expand Up @@ -852,7 +850,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
"",
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
return Some(err.emit());
}

Expand All @@ -868,7 +865,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
kind: expected_kind.as_str(),
});
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
return Some(err.emit());
}
}
Expand Down Expand Up @@ -2826,7 +2822,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
err.span_note(self.tcx.def_span(def_id), "opaque type is declared here");

self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
self.dcx().try_steal_replace_and_emit_err(self.tcx.def_span(def_id), StashKey::Cycle, err)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
suggest_increasing_limit,
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
err.emit()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1781,25 +1781,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
} else {
("dyn ", span.shrink_to_lo())
};
let alternatively = if visitor
.returns
.iter()
.map(|expr| self.typeck_results.as_ref().unwrap().expr_ty_adjusted_opt(expr))
.collect::<FxHashSet<_>>()
.len()
<= 1
{
err.span_suggestion_verbose(
impl_span,
"consider returning an `impl Trait` instead of a `dyn Trait`",
"impl ",
Applicability::MaybeIncorrect,
);
"alternatively, "
} else {
err.help("if there were a single returned type, you could use `impl Trait` instead");
""
};

err.span_suggestion_verbose(
impl_span,
"consider returning an `impl Trait` instead of a `dyn Trait`",
"impl ",
Applicability::MaybeIncorrect,
);

let mut sugg = vec![
(span.shrink_to_lo(), format!("Box<{pre}")),
Expand Down Expand Up @@ -1831,7 +1819,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {

err.multipart_suggestion(
format!(
"{alternatively}box the return type, and wrap all of the returned values in \
"alternatively, box the return type, and wrap all of the returned values in \
`Box::new`",
),
sugg,
Expand All @@ -1841,41 +1829,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
true
}

pub(super) fn point_at_returns_when_relevant(
&self,
err: &mut Diag<'_>,
obligation: &PredicateObligation<'tcx>,
) {
match obligation.cause.code().peel_derives() {
ObligationCauseCode::SizedReturnType => {}
_ => return,
}

let hir = self.tcx.hir();
let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn { body: body_id, .. }, ..
}) = node
{
let body = hir.body(*body_id);
// Point at all the `return`s in the function as they have failed trait bounds.
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(body);
let typeck_results = self.typeck_results.as_ref().unwrap();
for expr in &visitor.returns {
if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) {
let ty = self.resolve_vars_if_possible(returned_ty);
if ty.references_error() {
// don't print out the [type error] here
err.downgrade_to_delayed_bug();
} else {
err.span_label(expr.span, format!("this returned value is of type `{ty}`"));
}
}
}
}
}

pub(super) fn report_closure_arg_mismatch(
&self,
span: Span,
Expand Down
6 changes: 0 additions & 6 deletions tests/crashes/134355.rs

This file was deleted.

18 changes: 9 additions & 9 deletions tests/ui/associated-consts/issue-58022.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type
--> $DIR/issue-58022.rs:4:25
|
LL | const SIZE: usize;
| ------------------ `Foo::SIZE` defined here
LL |
LL | fn new(slice: &[u8; Foo::SIZE]) -> Self;
| ^^^^^^^^^ cannot refer to the associated constant of trait

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/issue-58022.rs:13:41
|
Expand All @@ -21,6 +12,15 @@ LL | pub struct Bar<T: ?Sized>(T);
| ^^^
= note: the return type of a function must have a statically known size

error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type
--> $DIR/issue-58022.rs:4:25
|
LL | const SIZE: usize;
| ------------------ `Foo::SIZE` defined here
LL |
LL | fn new(slice: &[u8; Foo::SIZE]) -> Self;
| ^^^^^^^^^ cannot refer to the associated constant of trait

error[E0423]: expected function, tuple struct or tuple variant, found trait `Foo`
--> $DIR/issue-58022.rs:15:9
|
Expand Down
1 change: 0 additions & 1 deletion tests/ui/consts/const-slice-array-deref.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const ONE: [u16] = [1];
//~^ ERROR the size for values of type `[u16]` cannot be known at compilation time
//~| ERROR the size for values of type `[u16]` cannot be known at compilation time
//~| ERROR mismatched types

const TWO: &'static u16 = &ONE[0];
Expand Down
13 changes: 2 additions & 11 deletions tests/ui/consts/const-slice-array-deref.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,13 @@ error[E0308]: mismatched types
LL | const ONE: [u16] = [1];
| ^^^ expected `[u16]`, found `[u16; 1]`

error[E0277]: the size for values of type `[u16]` cannot be known at compilation time
--> $DIR/const-slice-array-deref.rs:1:20
|
LL | const ONE: [u16] = [1];
| ^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[u16]`
= note: constant expressions must have a statically known size

error[E0161]: cannot move a value of type `[u16]`
--> $DIR/const-slice-array-deref.rs:6:28
--> $DIR/const-slice-array-deref.rs:5:28
|
LL | const TWO: &'static u16 = &ONE[0];
| ^^^ the size of `[u16]` cannot be statically determined

error: aborting due to 4 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0161, E0277, E0308.
For more information about an error, try `rustc --explain E0161`.
8 changes: 4 additions & 4 deletions tests/ui/consts/const-unsized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ use std::fmt::Debug;

const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync));
//~^ ERROR the size for values of type
//~| ERROR the size for values of type
//~| ERROR cannot move out of a shared reference

const CONST_FOO: str = *"foo";
//~^ ERROR the size for values of type
//~| ERROR the size for values of type
//~| ERROR cannot move out of a shared reference

static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
//~^ ERROR the size for values of type
//~| ERROR the size for values of type
//~| ERROR cannot move out of a shared reference

static STATIC_BAR: str = *"bar";
//~^ ERROR the size for values of type
//~| ERROR the size for values of type
//~| ERROR cannot move out of a shared reference

fn main() {
println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
Expand Down
54 changes: 21 additions & 33 deletions tests/ui/consts/const-unsized.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,6 @@ LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync));
|
= help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)`

error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time
--> $DIR/const-unsized.rs:3:35
|
LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)`
= note: constant expressions must have a statically known size

error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/const-unsized.rs:7:18
|
Expand All @@ -23,15 +14,6 @@ LL | const CONST_FOO: str = *"foo";
|
= help: the trait `Sized` is not implemented for `str`

error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/const-unsized.rs:7:24
|
LL | const CONST_FOO: str = *"foo";
| ^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `str`
= note: constant expressions must have a statically known size

error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time
--> $DIR/const-unsized.rs:11:18
|
Expand All @@ -40,15 +22,6 @@ LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
|
= help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)`

error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time
--> $DIR/const-unsized.rs:11:37
|
LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)`
= note: constant expressions must have a statically known size

error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/const-unsized.rs:15:20
|
Expand All @@ -57,14 +30,29 @@ LL | static STATIC_BAR: str = *"bar";
|
= help: the trait `Sized` is not implemented for `str`

error[E0277]: the size for values of type `str` cannot be known at compilation time
error[E0507]: cannot move out of a shared reference
--> $DIR/const-unsized.rs:3:35
|
LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `dyn Debug + Sync`, which does not implement the `Copy` trait

error[E0507]: cannot move out of a shared reference
--> $DIR/const-unsized.rs:7:24
|
LL | const CONST_FOO: str = *"foo";
| ^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait

error[E0507]: cannot move out of a shared reference
--> $DIR/const-unsized.rs:11:37
|
LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `dyn Debug + Sync`, which does not implement the `Copy` trait

error[E0507]: cannot move out of a shared reference
--> $DIR/const-unsized.rs:15:26
|
LL | static STATIC_BAR: str = *"bar";
| ^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `str`
= note: constant expressions must have a statically known size
| ^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait

error[E0161]: cannot move a value of type `str`
--> $DIR/const-unsized.rs:20:48
Expand All @@ -80,5 +68,5 @@ LL | println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATI

error: aborting due to 10 previous errors

Some errors have detailed explanations: E0161, E0277.
Some errors have detailed explanations: E0161, E0277, E0507.
For more information about an error, try `rustc --explain E0161`.
Loading

0 comments on commit 7bc0b3c

Please sign in to comment.