Refactor must_use
lint into two parts
Before, the lint did the checking for `must_use` and pretty printing the types in a special format in one pass, causing quite complex and untranslatable code. Now the collection and printing is split in two. That should also make it easier to translate or extract the type pretty printing in the future. Also fixes an integer overflow in the array length pluralization calculation.
This commit is contained in:
parent
62c627c7a3
commit
4e9ceef76d
5 changed files with 259 additions and 146 deletions
|
@ -13,6 +13,7 @@ use rustc_middle::ty::{self, DefIdTree, Ty};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::symbol::{kw, sym};
|
use rustc_span::symbol::{kw, sym};
|
||||||
use rustc_span::{BytePos, Span};
|
use rustc_span::{BytePos, Span};
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `unused_must_use` lint detects unused result of a type flagged as
|
/// The `unused_must_use` lint detects unused result of a type flagged as
|
||||||
|
@ -113,30 +114,19 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = cx.typeck_results().expr_ty(&expr);
|
let ty = cx.typeck_results().expr_ty(&expr);
|
||||||
let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, expr.span, "", "", 1);
|
|
||||||
|
|
||||||
let mut fn_warned = false;
|
let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span);
|
||||||
let mut op_warned = false;
|
let type_lint_emitted_or_suppressed = match must_use_result {
|
||||||
let maybe_def_id = match expr.kind {
|
Some(path) => {
|
||||||
hir::ExprKind::Call(ref callee, _) => {
|
emit_must_use_untranslated(cx, &path, "", "", 1);
|
||||||
match callee.kind {
|
true
|
||||||
hir::ExprKind::Path(ref qpath) => {
|
|
||||||
match cx.qpath_res(qpath, callee.hir_id) {
|
|
||||||
Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
|
|
||||||
// `Res::Local` if it was a closure, for which we
|
|
||||||
// do not currently support must-use linting
|
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
}
|
None => false,
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir::ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
|
|
||||||
_ => None,
|
|
||||||
};
|
};
|
||||||
if let Some(def_id) = maybe_def_id {
|
|
||||||
fn_warned = check_must_use_def(cx, def_id, expr.span, "return value of ", "");
|
let fn_warned = check_fn_must_use(cx, expr);
|
||||||
} else if type_permits_lack_of_use {
|
|
||||||
|
if !fn_warned && type_lint_emitted_or_suppressed {
|
||||||
// We don't warn about unused unit or uninhabited types.
|
// We don't warn about unused unit or uninhabited types.
|
||||||
// (See https://github.com/rust-lang/rust/issues/43806 for details.)
|
// (See https://github.com/rust-lang/rust/issues/43806 for details.)
|
||||||
return;
|
return;
|
||||||
|
@ -170,6 +160,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut op_warned = false;
|
||||||
|
|
||||||
if let Some(must_use_op) = must_use_op {
|
if let Some(must_use_op) = must_use_op {
|
||||||
cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| {
|
cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| {
|
||||||
lint.set_arg("op", must_use_op)
|
lint.set_arg("op", must_use_op)
|
||||||
|
@ -184,22 +176,64 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||||
op_warned = true;
|
op_warned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(type_permits_lack_of_use || fn_warned || op_warned) {
|
if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) {
|
||||||
cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| {
|
cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| {
|
||||||
lint.set_arg("ty", ty)
|
lint.set_arg("ty", ty)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns whether an error has been emitted (and thus another does not need to be later).
|
fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
|
||||||
fn check_must_use_ty<'tcx>(
|
let maybe_def_id = match expr.kind {
|
||||||
|
hir::ExprKind::Call(ref callee, _) => {
|
||||||
|
match callee.kind {
|
||||||
|
hir::ExprKind::Path(ref qpath) => {
|
||||||
|
match cx.qpath_res(qpath, callee.hir_id) {
|
||||||
|
Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
|
||||||
|
// `Res::Local` if it was a closure, for which we
|
||||||
|
// do not currently support must-use linting
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hir::ExprKind::MethodCall(..) => {
|
||||||
|
cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(def_id) = maybe_def_id {
|
||||||
|
check_must_use_def(cx, def_id, expr.span, "return value of ", "")
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A path through a type to a must_use source. Contains useful info for the lint.
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum MustUsePath {
|
||||||
|
/// Suppress must_use checking.
|
||||||
|
Suppressed,
|
||||||
|
/// The root of the normal must_use lint with an optional message.
|
||||||
|
Def(Span, DefId, Option<Symbol>),
|
||||||
|
Boxed(Box<Self>),
|
||||||
|
Opaque(Box<Self>),
|
||||||
|
TraitObject(Box<Self>),
|
||||||
|
TupleElement(Vec<(usize, Self)>),
|
||||||
|
Array(Box<Self>, u64),
|
||||||
|
/// The root of the unused_closures lint.
|
||||||
|
Closure(Span),
|
||||||
|
/// The root of the unused_generators lint.
|
||||||
|
Generator(Span),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(cx, expr), level = "debug", ret)]
|
||||||
|
fn is_ty_must_use<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
expr: &hir::Expr<'_>,
|
expr: &hir::Expr<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
descr_pre: &str,
|
) -> Option<MustUsePath> {
|
||||||
descr_post: &str,
|
|
||||||
plural_len: usize,
|
|
||||||
) -> bool {
|
|
||||||
if ty.is_unit()
|
if ty.is_unit()
|
||||||
|| cx.tcx.is_ty_uninhabited_from(
|
|| cx.tcx.is_ty_uninhabited_from(
|
||||||
cx.tcx.parent_module(expr.hir_id).to_def_id(),
|
cx.tcx.parent_module(expr.hir_id).to_def_id(),
|
||||||
|
@ -207,87 +241,164 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||||
cx.param_env,
|
cx.param_env,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return true;
|
return Some(MustUsePath::Suppressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
let plural_suffix = pluralize!(plural_len);
|
|
||||||
|
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Adt(..) if ty.is_box() => {
|
ty::Adt(..) if ty.is_box() => {
|
||||||
let boxed_ty = ty.boxed_ty();
|
let boxed_ty = ty.boxed_ty();
|
||||||
let descr_pre = &format!("{}boxed ", descr_pre);
|
is_ty_must_use(cx, boxed_ty, expr, span)
|
||||||
check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural_len)
|
.map(|inner| MustUsePath::Boxed(Box::new(inner)))
|
||||||
}
|
}
|
||||||
ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post),
|
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
|
||||||
ty::Opaque(def, _) => {
|
ty::Opaque(def, _) => {
|
||||||
let mut has_emitted = false;
|
elaborate_predicates_with_span(
|
||||||
for obligation in elaborate_predicates_with_span(
|
|
||||||
cx.tcx,
|
cx.tcx,
|
||||||
cx.tcx.explicit_item_bounds(def).iter().cloned(),
|
cx.tcx.explicit_item_bounds(def).iter().cloned(),
|
||||||
) {
|
)
|
||||||
|
.filter_map(|obligation| {
|
||||||
// We only look at the `DefId`, so it is safe to skip the binder here.
|
// We only look at the `DefId`, so it is safe to skip the binder here.
|
||||||
if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
|
if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
|
||||||
obligation.predicate.kind().skip_binder()
|
obligation.predicate.kind().skip_binder()
|
||||||
{
|
{
|
||||||
let def_id = poly_trait_predicate.trait_ref.def_id;
|
let def_id = poly_trait_predicate.trait_ref.def_id;
|
||||||
let descr_pre =
|
|
||||||
&format!("{}implementer{} of ", descr_pre, plural_suffix,);
|
is_def_must_use(cx, def_id, span)
|
||||||
if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
|
} else {
|
||||||
has_emitted = true;
|
None
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.map(|inner| MustUsePath::Opaque(Box::new(inner)))
|
||||||
|
.next()
|
||||||
}
|
}
|
||||||
}
|
ty::Dynamic(binders, _, _) => binders
|
||||||
has_emitted
|
.iter()
|
||||||
}
|
.filter_map(|predicate| {
|
||||||
ty::Dynamic(binder, _, _) => {
|
|
||||||
let mut has_emitted = false;
|
|
||||||
for predicate in binder.iter() {
|
|
||||||
if let ty::ExistentialPredicate::Trait(ref trait_ref) =
|
if let ty::ExistentialPredicate::Trait(ref trait_ref) =
|
||||||
predicate.skip_binder()
|
predicate.skip_binder()
|
||||||
{
|
{
|
||||||
let def_id = trait_ref.def_id;
|
let def_id = trait_ref.def_id;
|
||||||
let descr_post =
|
is_def_must_use(cx, def_id, span)
|
||||||
&format!(" trait object{}{}", plural_suffix, descr_post,);
|
} else {
|
||||||
if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
|
None
|
||||||
has_emitted = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
.map(|inner| MustUsePath::TraitObject(Box::new(inner)))
|
||||||
}
|
})
|
||||||
has_emitted
|
.next(),
|
||||||
}
|
ty::Tuple(tys) => {
|
||||||
ty::Tuple(ref tys) => {
|
let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind {
|
||||||
let mut has_emitted = false;
|
debug_assert_eq!(elem_exprs.len(), tys.len());
|
||||||
let comps = if let hir::ExprKind::Tup(comps) = expr.kind {
|
elem_exprs
|
||||||
debug_assert_eq!(comps.len(), tys.len());
|
|
||||||
comps
|
|
||||||
} else {
|
} else {
|
||||||
&[]
|
&[]
|
||||||
};
|
};
|
||||||
for (i, ty) in tys.iter().enumerate() {
|
|
||||||
let descr_post = &format!(" in tuple element {}", i);
|
// Default to `expr`.
|
||||||
let e = comps.get(i).unwrap_or(expr);
|
let elem_exprs = elem_exprs.iter().chain(iter::repeat(expr));
|
||||||
let span = e.span;
|
|
||||||
if check_must_use_ty(cx, ty, e, span, descr_pre, descr_post, plural_len) {
|
let nested_must_use = tys
|
||||||
has_emitted = true;
|
.iter()
|
||||||
|
.zip(elem_exprs)
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, (ty, expr))| {
|
||||||
|
is_ty_must_use(cx, ty, expr, expr.span).map(|path| (i, path))
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if !nested_must_use.is_empty() {
|
||||||
|
Some(MustUsePath::TupleElement(nested_must_use))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
has_emitted
|
|
||||||
}
|
|
||||||
ty::Array(ty, len) => match len.try_eval_usize(cx.tcx, cx.param_env) {
|
ty::Array(ty, len) => match len.try_eval_usize(cx.tcx, cx.param_env) {
|
||||||
// If the array is empty we don't lint, to avoid false positives
|
// If the array is empty we don't lint, to avoid false positives
|
||||||
Some(0) | None => false,
|
Some(0) | None => None,
|
||||||
// If the array is definitely non-empty, we can do `#[must_use]` checking.
|
// If the array is definitely non-empty, we can do `#[must_use]` checking.
|
||||||
Some(n) => {
|
Some(len) => is_ty_must_use(cx, ty, expr, span)
|
||||||
let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix,);
|
.map(|inner| MustUsePath::Array(Box::new(inner), len)),
|
||||||
check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, n as usize + 1)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ty::Closure(..) => {
|
ty::Closure(..) => Some(MustUsePath::Closure(span)),
|
||||||
|
ty::Generator(..) => Some(MustUsePath::Generator(span)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_def_must_use(cx: &LateContext<'_>, def_id: DefId, span: Span) -> Option<MustUsePath> {
|
||||||
|
if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
|
||||||
|
// check for #[must_use = "..."]
|
||||||
|
let reason = attr.value_str();
|
||||||
|
Some(MustUsePath::Def(span, def_id, reason))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns whether further errors should be suppressed because either a lint has been emitted or the type should be ignored.
|
||||||
|
fn check_must_use_def(
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
def_id: DefId,
|
||||||
|
span: Span,
|
||||||
|
descr_pre_path: &str,
|
||||||
|
descr_post_path: &str,
|
||||||
|
) -> bool {
|
||||||
|
is_def_must_use(cx, def_id, span)
|
||||||
|
.map(|must_use_path| {
|
||||||
|
emit_must_use_untranslated(
|
||||||
|
cx,
|
||||||
|
&must_use_path,
|
||||||
|
descr_pre_path,
|
||||||
|
descr_post_path,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(cx), level = "debug")]
|
||||||
|
fn emit_must_use_untranslated(
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
path: &MustUsePath,
|
||||||
|
descr_pre: &str,
|
||||||
|
descr_post: &str,
|
||||||
|
plural_len: usize,
|
||||||
|
) {
|
||||||
|
let plural_suffix = pluralize!(plural_len);
|
||||||
|
|
||||||
|
match path {
|
||||||
|
MustUsePath::Suppressed => {}
|
||||||
|
MustUsePath::Boxed(path) => {
|
||||||
|
let descr_pre = &format!("{}boxed ", descr_pre);
|
||||||
|
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
|
||||||
|
}
|
||||||
|
MustUsePath::Opaque(path) => {
|
||||||
|
let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix);
|
||||||
|
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
|
||||||
|
}
|
||||||
|
MustUsePath::TraitObject(path) => {
|
||||||
|
let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post);
|
||||||
|
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
|
||||||
|
}
|
||||||
|
MustUsePath::TupleElement(elems) => {
|
||||||
|
for (index, path) in elems {
|
||||||
|
let descr_post = &format!(" in tuple element {}", index);
|
||||||
|
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MustUsePath::Array(path, len) => {
|
||||||
|
let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix);
|
||||||
|
emit_must_use_untranslated(
|
||||||
|
cx,
|
||||||
|
path,
|
||||||
|
descr_pre,
|
||||||
|
descr_post,
|
||||||
|
plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
MustUsePath::Closure(span) => {
|
||||||
cx.struct_span_lint(
|
cx.struct_span_lint(
|
||||||
UNUSED_MUST_USE,
|
UNUSED_MUST_USE,
|
||||||
span,
|
*span,
|
||||||
fluent::lint_unused_closure,
|
fluent::lint_unused_closure,
|
||||||
|lint| {
|
|lint| {
|
||||||
// FIXME(davidtwco): this isn't properly translatable because of the
|
// FIXME(davidtwco): this isn't properly translatable because of the
|
||||||
|
@ -298,12 +409,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||||
.note(fluent::note)
|
.note(fluent::note)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
true
|
|
||||||
}
|
}
|
||||||
ty::Generator(..) => {
|
MustUsePath::Generator(span) => {
|
||||||
cx.struct_span_lint(
|
cx.struct_span_lint(
|
||||||
UNUSED_MUST_USE,
|
UNUSED_MUST_USE,
|
||||||
span,
|
*span,
|
||||||
fluent::lint_unused_generator,
|
fluent::lint_unused_generator,
|
||||||
|lint| {
|
|lint| {
|
||||||
// FIXME(davidtwco): this isn't properly translatable because of the
|
// FIXME(davidtwco): this isn't properly translatable because of the
|
||||||
|
@ -314,40 +424,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||||
.note(fluent::note)
|
.note(fluent::note)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
true
|
|
||||||
}
|
}
|
||||||
_ => false,
|
MustUsePath::Def(span, def_id, reason) => {
|
||||||
}
|
cx.struct_span_lint(UNUSED_MUST_USE, *span, fluent::lint_unused_def, |lint| {
|
||||||
}
|
|
||||||
|
|
||||||
// Returns whether an error has been emitted (and thus another does not need to be later).
|
|
||||||
// FIXME: Args desc_{pre,post}_path could be made lazy by taking Fn() -> &str, but this
|
|
||||||
// would make calling it a big awkward. Could also take String (so args are moved), but
|
|
||||||
// this would still require a copy into the format string, which would only be executed
|
|
||||||
// when needed.
|
|
||||||
fn check_must_use_def(
|
|
||||||
cx: &LateContext<'_>,
|
|
||||||
def_id: DefId,
|
|
||||||
span: Span,
|
|
||||||
descr_pre_path: &str,
|
|
||||||
descr_post_path: &str,
|
|
||||||
) -> bool {
|
|
||||||
if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
|
|
||||||
cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint_unused_def, |lint| {
|
|
||||||
// FIXME(davidtwco): this isn't properly translatable because of the pre/post
|
// FIXME(davidtwco): this isn't properly translatable because of the pre/post
|
||||||
// strings
|
// strings
|
||||||
lint.set_arg("pre", descr_pre_path);
|
lint.set_arg("pre", descr_pre);
|
||||||
lint.set_arg("post", descr_post_path);
|
lint.set_arg("post", descr_post);
|
||||||
lint.set_arg("def", cx.tcx.def_path_str(def_id));
|
lint.set_arg("def", cx.tcx.def_path_str(*def_id));
|
||||||
// check for #[must_use = "..."]
|
if let Some(note) = reason {
|
||||||
if let Some(note) = attr.value_str() {
|
|
||||||
lint.note(note.as_str());
|
lint.note(note.as_str());
|
||||||
}
|
}
|
||||||
lint
|
lint
|
||||||
});
|
});
|
||||||
true
|
}
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
// check-pass
|
// check-pass
|
||||||
|
|
||||||
#![warn(unused_must_use)]
|
#![warn(unused_must_use)]
|
||||||
|
#![feature(never_type)]
|
||||||
|
|
||||||
|
fn deref_never(x: &!) {
|
||||||
|
// Don't lint for uninhabited typess
|
||||||
|
*x;
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let val = 1;
|
let val = 1;
|
||||||
|
@ -38,4 +44,8 @@ fn main() {
|
||||||
!val; //~ WARNING unused unary operation
|
!val; //~ WARNING unused unary operation
|
||||||
-val; //~ WARNING unused unary operation
|
-val; //~ WARNING unused unary operation
|
||||||
*val_pointer; //~ WARNING unused unary operation
|
*val_pointer; //~ WARNING unused unary operation
|
||||||
|
|
||||||
|
if false {
|
||||||
|
deref_never(&panic!());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
warning: unused comparison that must be used
|
warning: unused comparison that must be used
|
||||||
--> $DIR/must-use-ops.rs:12:5
|
--> $DIR/must-use-ops.rs:18:5
|
||||||
|
|
|
|
||||||
LL | val == 1;
|
LL | val == 1;
|
||||||
| ^^^^^^^^ the comparison produces a value
|
| ^^^^^^^^ the comparison produces a value
|
||||||
|
@ -15,7 +15,7 @@ LL | let _ = val == 1;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused comparison that must be used
|
warning: unused comparison that must be used
|
||||||
--> $DIR/must-use-ops.rs:13:5
|
--> $DIR/must-use-ops.rs:19:5
|
||||||
|
|
|
|
||||||
LL | val < 1;
|
LL | val < 1;
|
||||||
| ^^^^^^^ the comparison produces a value
|
| ^^^^^^^ the comparison produces a value
|
||||||
|
@ -26,7 +26,7 @@ LL | let _ = val < 1;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused comparison that must be used
|
warning: unused comparison that must be used
|
||||||
--> $DIR/must-use-ops.rs:14:5
|
--> $DIR/must-use-ops.rs:20:5
|
||||||
|
|
|
|
||||||
LL | val <= 1;
|
LL | val <= 1;
|
||||||
| ^^^^^^^^ the comparison produces a value
|
| ^^^^^^^^ the comparison produces a value
|
||||||
|
@ -37,7 +37,7 @@ LL | let _ = val <= 1;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused comparison that must be used
|
warning: unused comparison that must be used
|
||||||
--> $DIR/must-use-ops.rs:15:5
|
--> $DIR/must-use-ops.rs:21:5
|
||||||
|
|
|
|
||||||
LL | val != 1;
|
LL | val != 1;
|
||||||
| ^^^^^^^^ the comparison produces a value
|
| ^^^^^^^^ the comparison produces a value
|
||||||
|
@ -48,7 +48,7 @@ LL | let _ = val != 1;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused comparison that must be used
|
warning: unused comparison that must be used
|
||||||
--> $DIR/must-use-ops.rs:16:5
|
--> $DIR/must-use-ops.rs:22:5
|
||||||
|
|
|
|
||||||
LL | val >= 1;
|
LL | val >= 1;
|
||||||
| ^^^^^^^^ the comparison produces a value
|
| ^^^^^^^^ the comparison produces a value
|
||||||
|
@ -59,7 +59,7 @@ LL | let _ = val >= 1;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused comparison that must be used
|
warning: unused comparison that must be used
|
||||||
--> $DIR/must-use-ops.rs:17:5
|
--> $DIR/must-use-ops.rs:23:5
|
||||||
|
|
|
|
||||||
LL | val > 1;
|
LL | val > 1;
|
||||||
| ^^^^^^^ the comparison produces a value
|
| ^^^^^^^ the comparison produces a value
|
||||||
|
@ -70,7 +70,7 @@ LL | let _ = val > 1;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused arithmetic operation that must be used
|
warning: unused arithmetic operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:20:5
|
--> $DIR/must-use-ops.rs:26:5
|
||||||
|
|
|
|
||||||
LL | val + 2;
|
LL | val + 2;
|
||||||
| ^^^^^^^ the arithmetic operation produces a value
|
| ^^^^^^^ the arithmetic operation produces a value
|
||||||
|
@ -81,7 +81,7 @@ LL | let _ = val + 2;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused arithmetic operation that must be used
|
warning: unused arithmetic operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:21:5
|
--> $DIR/must-use-ops.rs:27:5
|
||||||
|
|
|
|
||||||
LL | val - 2;
|
LL | val - 2;
|
||||||
| ^^^^^^^ the arithmetic operation produces a value
|
| ^^^^^^^ the arithmetic operation produces a value
|
||||||
|
@ -92,7 +92,7 @@ LL | let _ = val - 2;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused arithmetic operation that must be used
|
warning: unused arithmetic operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:22:5
|
--> $DIR/must-use-ops.rs:28:5
|
||||||
|
|
|
|
||||||
LL | val / 2;
|
LL | val / 2;
|
||||||
| ^^^^^^^ the arithmetic operation produces a value
|
| ^^^^^^^ the arithmetic operation produces a value
|
||||||
|
@ -103,7 +103,7 @@ LL | let _ = val / 2;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused arithmetic operation that must be used
|
warning: unused arithmetic operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:23:5
|
--> $DIR/must-use-ops.rs:29:5
|
||||||
|
|
|
|
||||||
LL | val * 2;
|
LL | val * 2;
|
||||||
| ^^^^^^^ the arithmetic operation produces a value
|
| ^^^^^^^ the arithmetic operation produces a value
|
||||||
|
@ -114,7 +114,7 @@ LL | let _ = val * 2;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused arithmetic operation that must be used
|
warning: unused arithmetic operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:24:5
|
--> $DIR/must-use-ops.rs:30:5
|
||||||
|
|
|
|
||||||
LL | val % 2;
|
LL | val % 2;
|
||||||
| ^^^^^^^ the arithmetic operation produces a value
|
| ^^^^^^^ the arithmetic operation produces a value
|
||||||
|
@ -125,7 +125,7 @@ LL | let _ = val % 2;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused logical operation that must be used
|
warning: unused logical operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:27:5
|
--> $DIR/must-use-ops.rs:33:5
|
||||||
|
|
|
|
||||||
LL | true && true;
|
LL | true && true;
|
||||||
| ^^^^^^^^^^^^ the logical operation produces a value
|
| ^^^^^^^^^^^^ the logical operation produces a value
|
||||||
|
@ -136,7 +136,7 @@ LL | let _ = true && true;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused logical operation that must be used
|
warning: unused logical operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:28:5
|
--> $DIR/must-use-ops.rs:34:5
|
||||||
|
|
|
|
||||||
LL | false || true;
|
LL | false || true;
|
||||||
| ^^^^^^^^^^^^^ the logical operation produces a value
|
| ^^^^^^^^^^^^^ the logical operation produces a value
|
||||||
|
@ -147,7 +147,7 @@ LL | let _ = false || true;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused bitwise operation that must be used
|
warning: unused bitwise operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:31:5
|
--> $DIR/must-use-ops.rs:37:5
|
||||||
|
|
|
|
||||||
LL | 5 ^ val;
|
LL | 5 ^ val;
|
||||||
| ^^^^^^^ the bitwise operation produces a value
|
| ^^^^^^^ the bitwise operation produces a value
|
||||||
|
@ -158,7 +158,7 @@ LL | let _ = 5 ^ val;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused bitwise operation that must be used
|
warning: unused bitwise operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:32:5
|
--> $DIR/must-use-ops.rs:38:5
|
||||||
|
|
|
|
||||||
LL | 5 & val;
|
LL | 5 & val;
|
||||||
| ^^^^^^^ the bitwise operation produces a value
|
| ^^^^^^^ the bitwise operation produces a value
|
||||||
|
@ -169,7 +169,7 @@ LL | let _ = 5 & val;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused bitwise operation that must be used
|
warning: unused bitwise operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:33:5
|
--> $DIR/must-use-ops.rs:39:5
|
||||||
|
|
|
|
||||||
LL | 5 | val;
|
LL | 5 | val;
|
||||||
| ^^^^^^^ the bitwise operation produces a value
|
| ^^^^^^^ the bitwise operation produces a value
|
||||||
|
@ -180,7 +180,7 @@ LL | let _ = 5 | val;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused bitwise operation that must be used
|
warning: unused bitwise operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:34:5
|
--> $DIR/must-use-ops.rs:40:5
|
||||||
|
|
|
|
||||||
LL | 5 << val;
|
LL | 5 << val;
|
||||||
| ^^^^^^^^ the bitwise operation produces a value
|
| ^^^^^^^^ the bitwise operation produces a value
|
||||||
|
@ -191,7 +191,7 @@ LL | let _ = 5 << val;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused bitwise operation that must be used
|
warning: unused bitwise operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:35:5
|
--> $DIR/must-use-ops.rs:41:5
|
||||||
|
|
|
|
||||||
LL | 5 >> val;
|
LL | 5 >> val;
|
||||||
| ^^^^^^^^ the bitwise operation produces a value
|
| ^^^^^^^^ the bitwise operation produces a value
|
||||||
|
@ -202,7 +202,7 @@ LL | let _ = 5 >> val;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused unary operation that must be used
|
warning: unused unary operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:38:5
|
--> $DIR/must-use-ops.rs:44:5
|
||||||
|
|
|
|
||||||
LL | !val;
|
LL | !val;
|
||||||
| ^^^^ the unary operation produces a value
|
| ^^^^ the unary operation produces a value
|
||||||
|
@ -213,7 +213,7 @@ LL | let _ = !val;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused unary operation that must be used
|
warning: unused unary operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:39:5
|
--> $DIR/must-use-ops.rs:45:5
|
||||||
|
|
|
|
||||||
LL | -val;
|
LL | -val;
|
||||||
| ^^^^ the unary operation produces a value
|
| ^^^^ the unary operation produces a value
|
||||||
|
@ -224,7 +224,7 @@ LL | let _ = -val;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
warning: unused unary operation that must be used
|
warning: unused unary operation that must be used
|
||||||
--> $DIR/must-use-ops.rs:40:5
|
--> $DIR/must-use-ops.rs:46:5
|
||||||
|
|
|
|
||||||
LL | *val_pointer;
|
LL | *val_pointer;
|
||||||
| ^^^^^^^^^^^^ the unary operation produces a value
|
| ^^^^^^^^^^^^ the unary operation produces a value
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![deny(unused_must_use)]
|
#![deny(unused_must_use)]
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
struct A;
|
struct A;
|
||||||
|
@ -34,6 +35,10 @@ fn array_of_arrays_of_arrays() -> [[[S; 1]; 2]; 1] {
|
||||||
[[[S], [S]]]
|
[[[S], [S]]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn usize_max() -> [S; usize::MAX] {
|
||||||
|
[S; usize::MAX]
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
empty(); // ok
|
empty(); // ok
|
||||||
singleton(); //~ ERROR unused array of `S` that must be used
|
singleton(); //~ ERROR unused array of `S` that must be used
|
||||||
|
@ -44,4 +49,6 @@ fn main() {
|
||||||
//~^ ERROR unused array of boxed `T` trait objects in tuple element 1 that must be used
|
//~^ ERROR unused array of boxed `T` trait objects in tuple element 1 that must be used
|
||||||
array_of_arrays_of_arrays();
|
array_of_arrays_of_arrays();
|
||||||
//~^ ERROR unused array of arrays of arrays of `S` that must be used
|
//~^ ERROR unused array of arrays of arrays of `S` that must be used
|
||||||
|
usize_max();
|
||||||
|
//~^ ERROR unused array of `S` that must be used
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: unused array of `S` that must be used
|
error: unused array of `S` that must be used
|
||||||
--> $DIR/must_use-array.rs:39:5
|
--> $DIR/must_use-array.rs:44:5
|
||||||
|
|
|
|
||||||
LL | singleton();
|
LL | singleton();
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
@ -11,34 +11,40 @@ LL | #![deny(unused_must_use)]
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unused array of `S` that must be used
|
error: unused array of `S` that must be used
|
||||||
--> $DIR/must_use-array.rs:40:5
|
--> $DIR/must_use-array.rs:45:5
|
||||||
|
|
|
|
||||||
LL | many();
|
LL | many();
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: unused array of `S` in tuple element 0 that must be used
|
error: unused array of `S` in tuple element 0 that must be used
|
||||||
--> $DIR/must_use-array.rs:41:6
|
--> $DIR/must_use-array.rs:46:6
|
||||||
|
|
|
|
||||||
LL | ([S], 0, ());
|
LL | ([S], 0, ());
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: unused array of implementers of `T` that must be used
|
error: unused array of implementers of `T` that must be used
|
||||||
--> $DIR/must_use-array.rs:42:5
|
--> $DIR/must_use-array.rs:47:5
|
||||||
|
|
|
|
||||||
LL | array_of_impl_trait();
|
LL | array_of_impl_trait();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unused array of boxed `T` trait objects in tuple element 1 that must be used
|
error: unused array of boxed `T` trait objects in tuple element 1 that must be used
|
||||||
--> $DIR/must_use-array.rs:43:5
|
--> $DIR/must_use-array.rs:48:5
|
||||||
|
|
|
|
||||||
LL | impl_array();
|
LL | impl_array();
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unused array of arrays of arrays of `S` that must be used
|
error: unused array of arrays of arrays of `S` that must be used
|
||||||
--> $DIR/must_use-array.rs:45:5
|
--> $DIR/must_use-array.rs:50:5
|
||||||
|
|
|
|
||||||
LL | array_of_arrays_of_arrays();
|
LL | array_of_arrays_of_arrays();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: unused array of `S` that must be used
|
||||||
|
--> $DIR/must_use-array.rs:52:5
|
||||||
|
|
|
||||||
|
LL | usize_max();
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue