Skip to content

Check Sizedness of return type in WF #136274

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 4, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -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 => {
@@ -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)),
);
}

@@ -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)),
);
}

@@ -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`.
19 changes: 7 additions & 12 deletions compiler/rustc_hir_typeck/src/check.rs
Original file line number Diff line number Diff line change
@@ -117,22 +117,17 @@ pub(super) fn check_fn<'a, 'tcx>(

fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);

let return_or_body_span = match decl.output {
hir::FnRetTy::DefaultReturn(_) => body.value.span,
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()) {
let return_or_body_span = match decl.output {
hir::FnRetTy::DefaultReturn(_) => body.value.span,
hir::FnRetTy::Return(ty) => ty.span,
};

fcx.require_type_is_sized(
declared_ret_ty,
return_or_body_span,
ObligationCauseCode::WellFormed(None),
ObligationCauseCode::SizedReturnType,
);
}

2 changes: 0 additions & 2 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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);

Original file line number Diff line number Diff line change
@@ -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()
}
}
@@ -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());
}
}
@@ -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());
}

@@ -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());
}
}
@@ -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)
}

Original file line number Diff line number Diff line change
@@ -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
@@ -1765,7 +1765,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};

err.code(E0746);
err.primary_message("return type cannot have an unboxed trait object");
err.primary_message("return type cannot be a trait object without pointer indirection");
err.children.clear();

let span = obligation.cause.span;
@@ -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}")),
@@ -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,
@@ -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,
6 changes: 0 additions & 6 deletions tests/crashes/134355.rs

This file was deleted.

5 changes: 4 additions & 1 deletion tests/rustdoc-json/primitives/primitive_impls.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#![feature(no_core)]
#![feature(no_core, lang_items)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![no_core]
#![rustc_coherence_is_core]

//@ set impl_i32 = "$.index[*][?(@.docs=='Only core can do this')].id"

#[lang = "sized"]
trait Sized {}

/// Only core can do this
impl i32 {
//@ set identity = "$.index[*][?(@.docs=='Do Nothing')].id"
5 changes: 4 additions & 1 deletion tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs
Original file line number Diff line number Diff line change
@@ -2,9 +2,12 @@
// feature.

#![deny(warnings)]
#![feature(no_core)]
#![feature(no_core, lang_items)]
#![no_core]

#[lang = "sized"]
trait Sized {}

/// ```{class="}
/// main;
/// ```
4 changes: 2 additions & 2 deletions tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: unclosed quote string `"`
--> $DIR/custom_code_classes_in_docs-warning3.rs:8:1
--> $DIR/custom_code_classes_in_docs-warning3.rs:11:1
|
LL | / /// ```{class="}
LL | | /// main;
@@ -17,7 +17,7 @@ LL | #![deny(warnings)]
= note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]`

error: unclosed quote string `"`
--> $DIR/custom_code_classes_in_docs-warning3.rs:8:1
--> $DIR/custom_code_classes_in_docs-warning3.rs:11:1
|
LL | / /// ```{class="}
LL | | /// main;
5 changes: 4 additions & 1 deletion tests/rustdoc/cfg_doc_reexport.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#![feature(doc_cfg)]
#![feature(no_core)]
#![feature(no_core, lang_items)]

#![crate_name = "foo"]
#![no_core]

#[lang = "sized"]
trait Sized {}

//@ has 'foo/index.html'
//@ has - '//dt/*[@class="stab portability"]' 'foobar'
//@ has - '//dt/*[@class="stab portability"]' 'bar'
5 changes: 4 additions & 1 deletion tests/rustdoc/cross-crate-primitive-doc.rs
Original file line number Diff line number Diff line change
@@ -2,9 +2,12 @@
//@ compile-flags: --extern-html-root-url=primitive_doc=../ -Z unstable-options
//@ only-linux

#![feature(no_core)]
#![feature(no_core, lang_items)]
#![no_core]

#[lang = "sized"]
trait Sized {}

extern crate primitive_doc;

//@ has 'cross_crate_primitive_doc/fn.foo.html' '//a[@href="../primitive_doc/primitive.usize.html"]' 'usize'
5 changes: 5 additions & 0 deletions tests/rustdoc/intra-doc/no-doc-primitive.rs
Original file line number Diff line number Diff line change
@@ -6,8 +6,13 @@
#![rustc_coherence_is_core]
#![crate_type = "rlib"]


//@ has no_doc_primitive/index.html
//! A [`char`] and its [`char::len_utf8`].

#[lang = "sized"]
trait Sized {}

impl char {
pub fn len_utf8(self) -> usize {
42
5 changes: 4 additions & 1 deletion tests/rustdoc/reexport-trait-from-hidden-111064-2.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// Regression test for <https://github.com/rust-lang/rust/issues/111064>.
#![feature(no_core)]
#![feature(no_core, lang_items)]
#![no_core]
#![crate_name = "foo"]

#[lang = "sized"]
trait Sized {}

//@ files "foo" "['sidebar-items.js', 'all.html', 'hidden', 'index.html', 'struct.Bar.html', \
// 'visible']"
//@ files "foo/hidden" "['inner']"
5 changes: 4 additions & 1 deletion tests/rustdoc/safe-intrinsic.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#![feature(intrinsics)]
#![feature(no_core)]
#![feature(no_core, lang_items)]
#![feature(rustc_attrs)]

#![no_core]
#![crate_name = "foo"]

#[lang = "sized"]
trait Sized {}

//@ has 'foo/fn.abort.html'
//@ has - '//pre[@class="rust item-decl"]' 'pub fn abort() -> !'
#[rustc_intrinsic]
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
|
@@ -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
|
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];
Loading