Rollup merge of #54920 - varkor:must_use-unit, r=estebank

Fix handling of #[must_use] on unit and uninhabited types

Fixes https://github.com/rust-lang/rust/issues/54828.
This commit is contained in:
kennytm 2018-10-12 22:04:09 +08:00 committed by GitHub
commit b39535d157
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 8 deletions

View file

@ -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,
};
@ -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]`
@ -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");
}
@ -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)

View file

@ -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`
}

View file

@ -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