diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index b5c5fc0608b95..2db2e0bc0da96 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { } let ty = cx.tables.expr_ty(&expr); - let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, ""); + let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", false); let mut fn_warned = false; let mut op_warned = false; @@ -133,7 +133,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty: Ty<'tcx>, expr: &hir::Expr, span: Span, - descr_post_path: &str, + descr_pre: &str, + descr_post: &str, + plural: bool, ) -> bool { if ty.is_unit() || cx.tcx.is_ty_uninhabited_from( cx.tcx.hir().get_module_parent(expr.hir_id), ty) @@ -141,15 +143,29 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { return true; } + let plural_suffix = if plural { "s" } else { "" }; + match ty.sty { - ty::Adt(def, _) => check_must_use_def(cx, def.did, span, "", descr_post_path), + ty::Adt(..) if ty.is_box() => { + let boxed_ty = ty.boxed_ty(); + let descr_pre = &format!("{}boxed ", descr_pre); + check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural) + } + ty::Adt(def, _) => { + check_must_use_def(cx, def.did, span, descr_pre, descr_post) + } ty::Opaque(def, _) => { let mut has_emitted = false; for (predicate, _) in &cx.tcx.predicates_of(def).predicates { if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate { let trait_ref = poly_trait_predicate.skip_binder().trait_ref; let def_id = trait_ref.def_id; - if check_must_use_def(cx, def_id, span, "implementer of ", "") { + let descr_pre = &format!( + "{}implementer{} of ", + descr_pre, + plural_suffix, + ); + if check_must_use_def(cx, def_id, span, descr_pre, descr_post) { has_emitted = true; break; } @@ -162,7 +178,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { for predicate in binder.skip_binder().iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { let def_id = trait_ref.def_id; - if check_must_use_def(cx, def_id, span, "", " trait object") { + let descr_post = &format!( + " trait object{}{}", + plural_suffix, + descr_post, + ); + if check_must_use_def(cx, def_id, span, descr_pre, descr_post) { has_emitted = true; break; } @@ -179,14 +200,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { vec![] }; for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() { - let descr_post_path = &format!(" in tuple element {}", i); + let descr_post = &format!(" in tuple element {}", i); let span = *spans.get(i).unwrap_or(&span); - if check_must_use_ty(cx, ty, expr, span, descr_post_path) { + if check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, plural) { has_emitted = true; } } has_emitted } + ty::Array(ty, len) => match len.assert_usize(cx.tcx) { + // If the array is definitely non-empty, we can do `#[must_use]` checking. + Some(n) if n != 0 => { + let descr_pre = &format!( + "{}array{} of ", + descr_pre, + plural_suffix, + ); + check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, true) + } + // Otherwise, we don't lint, to avoid false positives. + _ => false, + } _ => false, } } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 9ef42063f9412..797d85e941d96 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -103,7 +103,9 @@ pub fn set_hook(hook: Box) + 'static + Sync + Send>) { HOOK_LOCK.write_unlock(); if let Hook::Custom(ptr) = old_hook { - Box::from_raw(ptr); + #[allow(unused_must_use)] { + Box::from_raw(ptr); + } } } } diff --git a/src/test/run-pass/issues/issue-30530.rs b/src/test/run-pass/issues/issue-30530.rs index e837fc81721a8..111fb8aa506a4 100644 --- a/src/test/run-pass/issues/issue-30530.rs +++ b/src/test/run-pass/issues/issue-30530.rs @@ -12,7 +12,9 @@ pub enum Handler { } fn main() { - take(Handler::Default, Box::new(main)); + #[allow(unused_must_use)] { + take(Handler::Default, Box::new(main)); + } } #[inline(never)] diff --git a/src/test/run-pass/panics/panic-handler-flail-wildly.rs b/src/test/run-pass/panics/panic-handler-flail-wildly.rs index ebe4f70378cf0..6badd203842ff 100644 --- a/src/test/run-pass/panics/panic-handler-flail-wildly.rs +++ b/src/test/run-pass/panics/panic-handler-flail-wildly.rs @@ -1,5 +1,7 @@ // run-pass + #![allow(stable_features)] +#![allow(unused_must_use)] // ignore-emscripten no threads support diff --git a/src/test/ui/lint/must_use-array.rs b/src/test/ui/lint/must_use-array.rs new file mode 100644 index 0000000000000..97825dd2f6c43 --- /dev/null +++ b/src/test/ui/lint/must_use-array.rs @@ -0,0 +1,47 @@ +#![deny(unused_must_use)] + +#[must_use] +struct S; + +struct A; + +#[must_use] +trait T {} + +impl T for A {} + +fn empty() -> [S; 0] { + [] +} + +fn singleton() -> [S; 1] { + [S] +} + +fn many() -> [S; 4] { + [S, S, S, S] +} + +fn array_of_impl_trait() -> [impl T; 2] { + [A, A] +} + +fn impl_array() -> [(u8, Box); 2] { + [(0, Box::new(A)), (0, Box::new(A))] +} + +fn array_of_arrays_of_arrays() -> [[[S; 1]; 2]; 1] { + [[[S], [S]]] +} + +fn main() { + empty(); // ok + singleton(); //~ ERROR unused array of `S` that must be used + many(); //~ ERROR unused array of `S` that must be used + ([S], 0, ()); //~ ERROR unused array of `S` in tuple element 0 that must be used + array_of_impl_trait(); //~ ERROR unused array of implementers of `T` that must be used + impl_array(); + //~^ ERROR unused array of boxed `T` trait objects in tuple element 1 that must be used + array_of_arrays_of_arrays(); + //~^ ERROR unused array of arrays of arrays of `S` that must be used +} diff --git a/src/test/ui/lint/must_use-array.stderr b/src/test/ui/lint/must_use-array.stderr new file mode 100644 index 0000000000000..a6dbd8e93d4d3 --- /dev/null +++ b/src/test/ui/lint/must_use-array.stderr @@ -0,0 +1,44 @@ +error: unused array of `S` that must be used + --> $DIR/must_use-array.rs:39:5 + | +LL | singleton(); + | ^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/must_use-array.rs:1:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +error: unused array of `S` that must be used + --> $DIR/must_use-array.rs:40:5 + | +LL | many(); + | ^^^^^^^ + +error: unused array of `S` in tuple element 0 that must be used + --> $DIR/must_use-array.rs:41:6 + | +LL | ([S], 0, ()); + | ^^^ + +error: unused array of implementers of `T` that must be used + --> $DIR/must_use-array.rs:42:5 + | +LL | array_of_impl_trait(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unused array of boxed `T` trait objects in tuple element 1 that must be used + --> $DIR/must_use-array.rs:43:5 + | +LL | impl_array(); + | ^^^^^^^^^^^^^ + +error: unused array of arrays of arrays of `S` that must be used + --> $DIR/must_use-array.rs:45:5 + | +LL | array_of_arrays_of_arrays(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/lint/must_use-trait.rs b/src/test/ui/lint/must_use-trait.rs index 23df4fa6132d3..0aa751443a080 100644 --- a/src/test/ui/lint/must_use-trait.rs +++ b/src/test/ui/lint/must_use-trait.rs @@ -17,6 +17,23 @@ fn get_critical() -> impl NotSoCritical + Critical + DecidedlyUnimportant { Anon {} } +fn get_boxed_critical() -> Box { + Box::new(Anon {}) +} + +fn get_nested_boxed_critical() -> Box> { + Box::new(Box::new(Anon {})) +} + +fn get_critical_tuple() -> (u32, Box, impl Critical, ()) { + (0, get_boxed_critical(), get_critical(), ()) +} + fn main() { get_critical(); //~ ERROR unused implementer of `Critical` that must be used + get_boxed_critical(); //~ ERROR unused boxed `Critical` trait object that must be used + get_nested_boxed_critical(); + //~^ ERROR unused boxed boxed `Critical` trait object that must be used + get_critical_tuple(); //~ ERROR unused boxed `Critical` trait object in tuple element 1 + //~^ ERROR unused implementer of `Critical` in tuple element 2 } diff --git a/src/test/ui/lint/must_use-trait.stderr b/src/test/ui/lint/must_use-trait.stderr index 7e2b2f67964ac..be74362e29d62 100644 --- a/src/test/ui/lint/must_use-trait.stderr +++ b/src/test/ui/lint/must_use-trait.stderr @@ -1,5 +1,5 @@ error: unused implementer of `Critical` that must be used - --> $DIR/must_use-trait.rs:21:5 + --> $DIR/must_use-trait.rs:33:5 | LL | get_critical(); | ^^^^^^^^^^^^^^^ @@ -10,5 +10,29 @@ note: lint level defined here LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unused boxed `Critical` trait object that must be used + --> $DIR/must_use-trait.rs:34:5 + | +LL | get_boxed_critical(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: unused boxed boxed `Critical` trait object that must be used + --> $DIR/must_use-trait.rs:35:5 + | +LL | get_nested_boxed_critical(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unused boxed `Critical` trait object in tuple element 1 that must be used + --> $DIR/must_use-trait.rs:37:5 + | +LL | get_critical_tuple(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: unused implementer of `Critical` in tuple element 2 that must be used + --> $DIR/must_use-trait.rs:37:5 + | +LL | get_critical_tuple(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors