Skip to content

Commit 99f093f

Browse files
committed
fix lint to catch async fn with maybe sized return type
1 parent 95a27ad commit 99f093f

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_ast::BoundPolarity;
12
use rustc_hir::{self as hir, AmbigArg};
23
use rustc_infer::infer::TyCtxtInferExt;
34
use rustc_macros::{LintDiagnostic, Subdiagnostic};
@@ -66,6 +67,33 @@ declare_lint! {
6667

6768
declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
6869

70+
/// Check if an opaque type has an explicit `?Sized` bound by examining its HIR bounds.
71+
fn opaque_has_maybe_sized_bound<'tcx>(
72+
cx: &LateContext<'tcx>,
73+
opaque_def_id: rustc_span::def_id::DefId,
74+
) -> bool {
75+
let Some(local_def_id) = opaque_def_id.as_local() else {
76+
return false;
77+
};
78+
79+
let opaque_ty = match cx.tcx.hir_node_by_def_id(local_def_id) {
80+
hir::Node::OpaqueTy(opaque) => opaque,
81+
_ => return false,
82+
};
83+
84+
// Check if any of the bounds is a `?Sized` bound
85+
for bound in opaque_ty.bounds {
86+
if let hir::GenericBound::Trait(poly_trait_ref) = bound
87+
&& matches!(poly_trait_ref.modifiers.polarity, BoundPolarity::Maybe(_))
88+
&& cx.tcx.is_lang_item(poly_trait_ref.trait_ref.path.res.def_id(), hir::LangItem::Sized)
89+
{
90+
return true;
91+
}
92+
}
93+
94+
false
95+
}
96+
6997
impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
7098
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
7199
let hir::TyKind::OpaqueDef(opaque) = &ty.kind else {
@@ -98,12 +126,14 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
98126
let Some(proj_term) = proj.term.as_type() else { return };
99127

100128
// HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"...
129+
// unless the nested opaque has an explicit `?Sized` bound.
101130
if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind()
102131
&& cx.tcx.parent(opaque_ty.def_id) == def_id
103132
&& matches!(
104133
opaque.origin,
105134
hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. }
106135
)
136+
&& !opaque_has_maybe_sized_bound(cx, opaque_ty.def_id)
107137
{
108138
return;
109139
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@ edition: 2021
2+
#![deny(opaque_hidden_inferred_bound)]
3+
// Test that async functions cannot return unsized types via `impl Trait + ?Sized`
4+
// Issue #149438
5+
6+
use std::fmt::Debug;
7+
8+
async fn unsized_async() -> impl Debug + ?Sized {
9+
//~^ ERROR opaque type `impl Future<Output = impl Debug + ?Sized>` does not satisfy its associated type bounds
10+
123
11+
}
12+
13+
fn main() {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error: opaque type `impl Future<Output = impl Debug + ?Sized>` does not satisfy its associated type bounds
2+
--> $DIR/async-fn-unsized-return-type.rs:8:29
3+
|
4+
LL | async fn unsized_async() -> impl Debug + ?Sized {
5+
| ^^^^^^^^^^^^^^^^^^^
6+
|
7+
--> $SRC_DIR/core/src/future/future.rs:LL:COL
8+
|
9+
= note: this associated type bound is unsatisfied for `impl Debug + ?Sized`
10+
note: the lint level is defined here
11+
--> $DIR/async-fn-unsized-return-type.rs:2:9
12+
|
13+
LL | #![deny(opaque_hidden_inferred_bound)]
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
help: add this bound
16+
|
17+
LL | async fn unsized_async() -> impl Debug + ?Sized + Sized {
18+
| +++++++
19+
20+
error: aborting due to 1 previous error
21+

0 commit comments

Comments
 (0)