Skip to content

Commit 3dbdccc

Browse files
committed
stabilize #[must_use] for functions and must-use operators
This is in the matter of RFC 1940 and tracking issue #43302.
1 parent c659fab commit 3dbdccc

20 files changed

+166
-342
lines changed

src/doc/unstable-book/src/language-features/fn-must-use.md

-30
This file was deleted.

src/liballoc/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
#![feature(dropck_eyepatch)]
9797
#![feature(exact_size_is_empty)]
9898
#![feature(fmt_internals)]
99-
#![feature(fn_must_use)]
99+
#![cfg_attr(stage0, feature(fn_must_use))]
100100
#![feature(from_ref)]
101101
#![feature(fundamental)]
102102
#![feature(lang_items)]

src/liballoc/tests/slice.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,7 @@ fn test_box_slice_clone() {
12821282
}
12831283

12841284
#[test]
1285+
#[allow(unused_must_use)] // here, we care about the side effects of `.clone()`
12851286
#[cfg_attr(target_os = "emscripten", ignore)]
12861287
fn test_box_slice_clone_panics() {
12871288
use std::sync::Arc;

src/libcore/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@
7676
#![feature(doc_cfg)]
7777
#![feature(doc_spotlight)]
7878
#![feature(extern_types)]
79-
#![feature(fn_must_use)]
8079
#![feature(fundamental)]
8180
#![feature(intrinsics)]
8281
#![feature(iterator_flatten)]
@@ -114,6 +113,7 @@
114113

115114
#![cfg_attr(stage0, feature(target_feature))]
116115
#![cfg_attr(stage0, feature(cfg_target_feature))]
116+
#![cfg_attr(stage0, feature(fn_must_use))]
117117

118118
#[prelude_import]
119119
#[allow(unused)]

src/librustc_lint/unused.rs

+52-52
Original file line numberDiff line numberDiff line change
@@ -73,59 +73,59 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
7373

7474
let mut fn_warned = false;
7575
let mut op_warned = false;
76-
if cx.tcx.features().fn_must_use {
77-
let maybe_def = match expr.node {
78-
hir::ExprCall(ref callee, _) => {
79-
match callee.node {
80-
hir::ExprPath(ref qpath) => {
81-
let def = cx.tables.qpath_def(qpath, callee.hir_id);
82-
if let Def::Fn(_) = def {
83-
Some(def)
84-
} else { // `Def::Local` if it was a closure, for which we
85-
None // do not currently support must-use linting
86-
}
87-
},
88-
_ => None
89-
}
90-
},
91-
hir::ExprMethodCall(..) => {
92-
cx.tables.type_dependent_defs().get(expr.hir_id).cloned()
93-
},
94-
_ => None
95-
};
96-
if let Some(def) = maybe_def {
97-
let def_id = def.def_id();
98-
fn_warned = check_must_use(cx, def_id, s.span, "return value of ");
99-
}
100-
let must_use_op = match expr.node {
101-
// Hardcoding operators here seemed more expedient than the
102-
// refactoring that would be needed to look up the `#[must_use]`
103-
// attribute which does exist on the comparison trait methods
104-
hir::ExprBinary(bin_op, ..) => {
105-
match bin_op.node {
106-
hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => {
107-
Some("comparison")
108-
},
109-
hir::BiAdd | hir::BiSub | hir::BiDiv | hir::BiMul | hir::BiRem => {
110-
Some("arithmetic operation")
111-
},
112-
hir::BiAnd | hir::BiOr => {
113-
Some("logical operation")
114-
},
115-
hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | hir::BiShl | hir::BiShr => {
116-
Some("bitwise operation")
117-
},
118-
}
119-
},
120-
hir::ExprUnary(..) => Some("unary operation"),
121-
_ => None
122-
};
123-
if let Some(must_use_op) = must_use_op {
124-
cx.span_lint(UNUSED_MUST_USE, expr.span,
125-
&format!("unused {} which must be used", must_use_op));
126-
op_warned = true;
127-
}
76+
let maybe_def = match expr.node {
77+
hir::ExprCall(ref callee, _) => {
78+
match callee.node {
79+
hir::ExprPath(ref qpath) => {
80+
let def = cx.tables.qpath_def(qpath, callee.hir_id);
81+
if let Def::Fn(_) = def {
82+
Some(def)
83+
} else { // `Def::Local` if it was a closure, for which we
84+
None // do not currently support must-use linting
85+
}
86+
},
87+
_ => None
88+
}
89+
},
90+
hir::ExprMethodCall(..) => {
91+
cx.tables.type_dependent_defs().get(expr.hir_id).cloned()
92+
},
93+
_ => None
94+
};
95+
if let Some(def) = maybe_def {
96+
let def_id = def.def_id();
97+
fn_warned = check_must_use(cx, def_id, s.span, "return value of ");
12898
}
99+
let must_use_op = match expr.node {
100+
// Hardcoding operators here seemed more expedient than the
101+
// refactoring that would be needed to look up the `#[must_use]`
102+
// attribute which does exist on the comparison trait methods
103+
hir::ExprBinary(bin_op, ..) => {
104+
match bin_op.node {
105+
hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => {
106+
Some("comparison")
107+
},
108+
hir::BiAdd | hir::BiSub | hir::BiDiv | hir::BiMul | hir::BiRem => {
109+
Some("arithmetic operation")
110+
},
111+
hir::BiAnd | hir::BiOr => {
112+
Some("logical operation")
113+
},
114+
hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | hir::BiShl | hir::BiShr => {
115+
Some("bitwise operation")
116+
},
117+
}
118+
},
119+
hir::ExprUnary(..) => Some("unary operation"),
120+
_ => None
121+
};
122+
123+
if let Some(must_use_op) = must_use_op {
124+
cx.span_lint(UNUSED_MUST_USE, expr.span,
125+
&format!("unused {} which must be used", must_use_op));
126+
op_warned = true;
127+
}
128+
129129
if !(ty_warned || fn_warned || op_warned) {
130130
cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
131131
}

src/libstd/ffi/c_str.rs

+2
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,7 @@ impl CStr {
988988
/// behavior when `ptr` is used inside the `unsafe` block:
989989
///
990990
/// ```no_run
991+
/// # #![allow(unused_must_use)]
991992
/// use std::ffi::{CString};
992993
///
993994
/// let ptr = CString::new("Hello").unwrap().as_ptr();
@@ -1003,6 +1004,7 @@ impl CStr {
10031004
/// To fix the problem, bind the `CString` to a local variable:
10041005
///
10051006
/// ```no_run
1007+
/// # #![allow(unused_must_use)]
10061008
/// use std::ffi::{CString};
10071009
///
10081010
/// let hello = CString::new("Hello").unwrap();

src/libstd/sync/mpsc/select.rs

+2
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ mod tests {
518518
}
519519
}
520520

521+
#[allow(unused_must_use)]
521522
#[test]
522523
fn cloning() {
523524
let (tx1, rx1) = channel::<i32>();
@@ -540,6 +541,7 @@ mod tests {
540541
tx3.send(()).unwrap();
541542
}
542543

544+
#[allow(unused_must_use)]
543545
#[test]
544546
fn cloning2() {
545547
let (tx1, rx1) = channel::<i32>();

src/libsyntax/feature_gate.rs

+3-19
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,6 @@ declare_features! (
369369
// #[doc(include="some-file")]
370370
(active, external_doc, "1.22.0", Some(44732), None),
371371

372-
// allow `#[must_use]` on functions and comparison operators (RFC 1940)
373-
(active, fn_must_use, "1.21.0", Some(43302), None),
374-
375372
// Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
376373
(active, non_exhaustive, "1.22.0", Some(44109), None),
377374

@@ -591,6 +588,8 @@ declare_features! (
591588
(accepted, target_feature, "1.27.0", None, None),
592589
// Trait object syntax with `dyn` prefix
593590
(accepted, dyn_trait, "1.27.0", Some(44662), None),
591+
// allow `#[must_use]` on functions; and, must-use operators (RFC 1940)
592+
(accepted, fn_must_use, "1.27.0", Some(43302), None),
594593
);
595594

596595
// If you change this, please modify src/doc/unstable-book as well. You must
@@ -1545,11 +1544,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
15451544
function may change over time, for now \
15461545
a top-level `fn main()` is required");
15471546
}
1548-
if let Some(attr) = attr::find_by_name(&i.attrs[..], "must_use") {
1549-
gate_feature_post!(&self, fn_must_use, attr.span,
1550-
"`#[must_use]` on functions is experimental",
1551-
GateStrength::Soft);
1552-
}
15531547
}
15541548

15551549
ast::ItemKind::Struct(..) => {
@@ -1581,7 +1575,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
15811575
"trait aliases are not yet fully implemented");
15821576
}
15831577

1584-
ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, ref impl_items) => {
1578+
ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
15851579
if polarity == ast::ImplPolarity::Negative {
15861580
gate_feature_post!(&self, optin_builtin_traits,
15871581
i.span,
@@ -1594,16 +1588,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
15941588
i.span,
15951589
"specialization is unstable");
15961590
}
1597-
1598-
for impl_item in impl_items {
1599-
if let ast::ImplItemKind::Method(..) = impl_item.node {
1600-
if let Some(attr) = attr::find_by_name(&impl_item.attrs[..], "must_use") {
1601-
gate_feature_post!(&self, fn_must_use, attr.span,
1602-
"`#[must_use]` on methods is experimental",
1603-
GateStrength::Soft);
1604-
}
1605-
}
1606-
}
16071591
}
16081592

16091593
ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {

src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs

-22
This file was deleted.

src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr

-8
This file was deleted.

src/test/ui/feature-gate-fn_must_use.rs

-31
This file was deleted.

src/test/ui/feature-gate-fn_must_use.stderr

-24
This file was deleted.

src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs

-1
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,6 @@ mod must_use {
661661
mod inner { #![must_use="1400"] }
662662

663663
#[must_use = "1400"] fn f() { }
664-
//~^ WARN `#[must_use]` on functions is experimental
665664

666665
#[must_use = "1400"] struct S;
667666

0 commit comments

Comments
 (0)