Skip to content

Commit

Permalink
Auto merge of #61100 - varkor:must_use-tuple-expr, r=<try>
Browse files Browse the repository at this point in the history
Apply #[must_use] lint to components of tuples

Fixes #61061.
  • Loading branch information
bors committed May 24, 2019
2 parents 8869ee0 + 68c0ced commit 58b2112
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 37 deletions.
91 changes: 54 additions & 37 deletions src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rustc::hir::def::{Res, DefKind};
use rustc::hir::def_id::DefId;
use rustc::lint;
use rustc::ty;
use rustc::ty::{self, Ty};
use rustc::ty::adjustment;
use rustc_data_structures::fx::FxHashMap;
use lint::{LateContext, EarlyContext, LintContext, LintArray};
Expand Down Expand Up @@ -47,42 +47,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
return;
}

let t = cx.tables.expr_ty(&expr);
let type_permits_lack_of_use = if t.is_unit()
let ty = cx.tables.expr_ty(&expr);
let type_permits_lack_of_use = if ty.is_unit()
|| cx.tcx.is_ty_uninhabited_from(
cx.tcx.hir().get_module_parent_by_hir_id(expr.hir_id), t)
cx.tcx.hir().get_module_parent_by_hir_id(expr.hir_id), ty)
{
true
} else {
match t.sty {
ty::Adt(def, _) => check_must_use(cx, def.did, s.span, "", ""),
ty::Opaque(def, _) => {
let mut must_use = 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;
if check_must_use(cx, trait_ref.def_id, s.span, "implementer of ", "") {
must_use = true;
break;
}
}
}
must_use
}
ty::Dynamic(binder, _) => {
let mut must_use = false;
for predicate in binder.skip_binder().iter() {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate {
if check_must_use(cx, trait_ref.def_id, s.span, "", " trait object") {
must_use = true;
break;
}
}
}
must_use
}
_ => false,
}
check_must_use_ty(cx, ty, s.span)
};

let mut fn_warned = false;
Expand All @@ -108,7 +80,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
_ => None
};
if let Some(def_id) = maybe_def_id {
fn_warned = check_must_use(cx, def_id, s.span, "return value of ", "");
fn_warned = check_must_use_def(cx, def_id, s.span, "return value of ", "");
} else if type_permits_lack_of_use {
// We don't warn about unused unit or uninhabited types.
// (See https://github.com/rust-lang/rust/issues/43806 for details.)
Expand Down Expand Up @@ -162,18 +134,63 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
}

fn check_must_use(
// Returns whether an error has been emitted (and thus another does not need to be later).
fn check_must_use_ty(
cx: &LateContext<'_, '_>,
ty: Ty<'_>,
span: Span,
) -> bool {
match ty.sty {
ty::Adt(def, _) => check_must_use_def(cx, def.did, span, "", ""),
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 ", "") {
has_emitted = true;
break;
}
}
}
has_emitted
}
ty::Dynamic(binder, _) => {
let mut has_emitted = false;
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") {
has_emitted = true;
break;
}
}
}
has_emitted
}
ty::Tuple(ref tys) => {
tys.iter().map(|k| k.expect_ty()).any(|ty| {
check_must_use_ty(cx, ty, span)
})
}
_ => false,
}
}

// Returns whether an error has been emitted (and thus another does not need to be later).
fn check_must_use_def(
cx: &LateContext<'_, '_>,
def_id: DefId,
sp: Span,
span: Span,
descr_pre_path: &str,
descr_post_path: &str,
) -> bool {
for attr in cx.tcx.get_attrs(def_id).iter() {
if attr.check_name(sym::must_use) {
let msg = format!("unused {}`{}`{} that must be used",
descr_pre_path, cx.tcx.def_path_str(def_id), descr_post_path);
let mut err = cx.struct_span_lint(UNUSED_MUST_USE, sp, &msg);
let mut err = cx.struct_span_lint(UNUSED_MUST_USE, span, &msg);
// check for #[must_use = "..."]
if let Some(note) = attr.value_str() {
err.note(&note.as_str());
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/lint/must_use-tuple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#![deny(unused_must_use)]

fn main() {
(Ok::<(), ()>(()),); //~ ERROR unused `std::result::Result` that must be used
}
15 changes: 15 additions & 0 deletions src/test/ui/lint/must_use-tuple.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error: unused `std::result::Result` that must be used
--> $DIR/must_use-tuple.rs:4:5
|
LL | (Ok::<(), ()>(()),);
| ^^^^^^^^^^^^^^^^^^^^
|
note: lint level defined here
--> $DIR/must_use-tuple.rs:1:9
|
LL | #![deny(unused_must_use)]
| ^^^^^^^^^^^^^^^
= note: this `Result` may be an `Err` variant, which should be handled

error: aborting due to previous error

0 comments on commit 58b2112

Please sign in to comment.