Skip to content

Commit

Permalink
Fix handling of #[must_use] on unit and uninhabited types
Browse files Browse the repository at this point in the history
  • Loading branch information
varkor committed Oct 8, 2018
1 parent 423d810 commit be88961
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 8 deletions.
23 changes: 15 additions & 8 deletions src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
}

let t = cx.tables.expr_ty(&expr);
let ty_warned = match t.sty {
ty::Tuple(ref tys) if tys.is_empty() => return,
ty::Never => return,
// FIXME(varkor): replace with `t.is_unit() || t.conservative_is_uninhabited()`.
let type_permits_no_use = match t.sty {
ty::Tuple(ref tys) if tys.is_empty() => true,
ty::Never => true,
ty::Adt(def, _) => {
if def.variants.is_empty() {
return;
true
} else {
check_must_use(cx, def.did, s.span, "")
}
check_must_use(cx, def.did, s.span, "")
},
}
_ => false,
};

Expand Down Expand Up @@ -95,7 +97,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
if let Some(def) = maybe_def {
let def_id = def.def_id();
fn_warned = check_must_use(cx, def_id, s.span, "return value of ");
} else if type_permits_no_use {
// We don't warn about unused unit or uninhabited types.
// (See https://github.com/rust-lang/rust/issues/43806 for details.)
return;
}

let must_use_op = match expr.node {
// Hardcoding operators here seemed more expedient than the
// refactoring that would be needed to look up the `#[must_use]`
Expand Down Expand Up @@ -139,7 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
op_warned = true;
}

if !(ty_warned || fn_warned || op_warned) {
if !(type_permits_no_use || fn_warned || op_warned) {
cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
}

Expand Down Expand Up @@ -233,7 +240,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
.find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel)
.is_some();

// Has a plugin registered this attribute as one which must be used at
// Has a plugin registered this attribute as one that must be used at
// the crate level?
let plugin_crate = plugin_attributes.iter()
.find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t)
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/lint/must_use-unit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![feature(never_type)]

#![deny(unused_must_use)]

#[must_use]
fn foo() {}

#[must_use]
fn bar() -> ! {
unimplemented!()
}

fn main() {
foo(); //~ unused return value of `foo`

bar(); //~ unused return value of `bar`
}
20 changes: 20 additions & 0 deletions src/test/ui/lint/must_use-unit.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: unused return value of `foo` which must be used
--> $DIR/must_use-unit.rs:14:5
|
LL | foo(); //~ unused return value of `foo`
| ^^^^^^
|
note: lint level defined here
--> $DIR/must_use-unit.rs:3:9
|
LL | #![deny(unused_must_use)]
| ^^^^^^^^^^^^^^^

error: unused return value of `bar` which must be used
--> $DIR/must_use-unit.rs:16:5
|
LL | bar(); //~ unused return value of `bar`
| ^^^^^^

error: aborting due to 2 previous errors

0 comments on commit be88961

Please sign in to comment.