Skip to content

Commit 6667ea1

Browse files
committed
Don't trigger unnecessary_box_returns when the size depends on generics
The lint fired on return types such as `Box<[T; N]>`, suggesting to return the array unboxed. The size of such a type depends on generic parameters and cannot be computed here: `approx_ty_size` falls back to `0` for an array with a const- generic length or a generic element type, so the size check always passed. Use the type's layout directly and only lint when it can actually be computed. This keeps the existing behaviour for concrete types (and for generic types with a known layout such as `Box<Vec<T>>`) while no longer suggesting to unbox a value whose size is unknown and potentially large.
1 parent 3dcef78 commit 6667ea1

2 files changed

Lines changed: 18 additions & 3 deletions

File tree

clippy_lints/src/unnecessary_box_returns.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use clippy_config::Conf;
22
use clippy_utils::diagnostics::span_lint_and_then;
3-
use clippy_utils::ty::approx_ty_size;
43
use rustc_errors::Applicability;
54
use rustc_hir::def_id::LocalDefId;
65
use rustc_hir::{FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
76
use rustc_lint::{LateContext, LateLintPass};
7+
use rustc_middle::ty::layout::LayoutOf;
88
use rustc_session::impl_lint_pass;
99
use rustc_span::Symbol;
1010

@@ -81,8 +81,13 @@ impl UnnecessaryBoxReturns {
8181

8282
// It's sometimes useful to return Box<T> if T is unsized, so don't lint those.
8383
// Also, don't lint if we know that T is very large, in which case returning
84-
// a Box<T> may be beneficial.
85-
if boxed_ty.is_sized(cx.tcx, cx.typing_env()) && approx_ty_size(cx, boxed_ty) <= self.maximum_size {
84+
// a Box<T> may be beneficial. When the size depends on generic parameters
85+
// (e.g. `[T; N]`) it cannot be determined here, so don't lint that either, as
86+
// the `Box` may be a deliberate choice to avoid copying a large value.
87+
if boxed_ty.is_sized(cx.tcx, cx.typing_env())
88+
&& let Ok(layout) = cx.layout_of(boxed_ty)
89+
&& layout.size.bytes() <= self.maximum_size
90+
{
8691
span_lint_and_then(
8792
cx,
8893
UNNECESSARY_BOX_RETURNS,

tests/ui/unnecessary_box_returns.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ impl HasHuge {
7171
}
7272
}
7373

74+
// don't lint (issue #17202): the size of `[T; N]` depends on a const generic parameter
75+
fn const_generic_array<const N: usize, T>(value: Box<[T; N]>) -> Box<[T; N]> {
76+
value
77+
}
78+
79+
// don't lint (issue #17202): the size of `[T; 10]` depends on the generic element type
80+
fn generic_element_array<T>(value: Box<[T; 10]>) -> Box<[T; 10]> {
81+
value
82+
}
83+
7484
fn main() {
7585
// don't lint: this is a closure
7686
let a = || -> Box<usize> { Box::new(5) };

0 commit comments

Comments
 (0)