diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 6f956c3bcc1ce..7407dfc455d84 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -152,7 +152,8 @@ pub fn target_machine_factory( let features = features.join(","); let features = CString::new(features).unwrap(); let abi = SmallCStr::new(&sess.target.llvm_abiname); - let trap_unreachable = sess.target.trap_unreachable; + let trap_unreachable = + sess.opts.debugging_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable); let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; let asm_comments = sess.asm_comments(); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 1fc2d281e7935..92262050b8c1b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -547,7 +547,7 @@ fn test_debugging_options_tracking_hash() { tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); tracked!(dual_proc_macros, true); - tracked!(fewer_names, true); + tracked!(fewer_names, Some(true)); tracked!(force_overflow_checks, Some(true)); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); @@ -592,6 +592,7 @@ fn test_debugging_options_tracking_hash() { tracked!(thinlto, Some(true)); tracked!(tune_cpu, Some(String::from("abc"))); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); + tracked!(trap_unreachable, Some(false)); tracked!(treat_err_as_bug, Some(1)); tracked!(unleash_the_miri_inside_of_you, true); tracked!(use_ctors_section, Some(true)); diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 493b9f15271ef..6d7e4ebc253bd 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1155,14 +1155,18 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { false } - fn visit_invoc(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> { + fn visit_invoc(&mut self, id: NodeId) -> ExpnId { let invoc_id = id.placeholder_to_expn_id(); - - self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); - let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope); assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation"); + invoc_id + } + /// Visit invocation in context in which it can emit a named item (possibly `macro_rules`) + /// directly into its parent scope's module. + fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> { + let invoc_id = self.visit_invoc(id); + self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)) } @@ -1291,7 +1295,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { return; } ItemKind::MacCall(..) => { - self.parent_scope.macro_rules = self.visit_invoc(item.id); + self.parent_scope.macro_rules = self.visit_invoc_in_module(item.id); return; } ItemKind::Mod(..) => self.contains_macro_use(&item.attrs), @@ -1309,7 +1313,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_stmt(&mut self, stmt: &'b ast::Stmt) { if let ast::StmtKind::MacCall(..) = stmt.kind { - self.parent_scope.macro_rules = self.visit_invoc(stmt.id); + self.parent_scope.macro_rules = self.visit_invoc_in_module(stmt.id); } else { visit::walk_stmt(self, stmt); } @@ -1317,7 +1321,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_foreign_item(&mut self, foreign_item: &'b ForeignItem) { if let ForeignItemKind::MacCall(_) = foreign_item.kind { - self.visit_invoc(foreign_item.id); + self.visit_invoc_in_module(foreign_item.id); return; } @@ -1336,7 +1340,14 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) { if let AssocItemKind::MacCall(_) = item.kind { - self.visit_invoc(item.id); + match ctxt { + AssocCtxt::Trait => { + self.visit_invoc_in_module(item.id); + } + AssocCtxt::Impl => { + self.visit_invoc(item.id); + } + } return; } @@ -1460,7 +1471,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { // type and value namespaces. fn visit_variant(&mut self, variant: &'b ast::Variant) { if variant.is_placeholder { - self.visit_invoc(variant.id); + self.visit_invoc_in_module(variant.id); return; } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1cd3d11e32153..731bbf029fa31 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -900,7 +900,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "emits a future-incompatibility report for lints (RFC 2834)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), - fewer_names: bool = (false, parse_bool, [TRACKED], + fewer_names: Option = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), force_overflow_checks: Option = (None, parse_opt_bool, [TRACKED], @@ -1113,6 +1113,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "choose the TLS model to use (`rustc --print tls-models` for details)"), trace_macros: bool = (false, parse_bool, [UNTRACKED], "for every macro invocation, print its name and arguments (default: no)"), + trap_unreachable: Option = (None, parse_opt_bool, [TRACKED], + "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"), treat_err_as_bug: Option = (None, parse_treat_err_as_bug, [TRACKED], "treat error number `val` that occurs as bug"), trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 419d1447764ec..5dddf0eb72ea6 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -734,12 +734,15 @@ impl Session { self.opts.cg.panic.unwrap_or(self.target.panic_strategy) } pub fn fewer_names(&self) -> bool { - let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) - || self.opts.output_types.contains_key(&OutputType::Bitcode) - // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue. - || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); - - self.opts.debugging_opts.fewer_names || !more_names + if let Some(fewer_names) = self.opts.debugging_opts.fewer_names { + fewer_names + } else { + let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) + || self.opts.output_types.contains_key(&OutputType::Bitcode) + // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue. + || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); + !more_names + } } pub fn unstable_options(&self) -> bool { diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index eb32cef24a1ea..bd2ad257402fa 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -458,7 +458,7 @@ impl fmt::Debug for RangeMut<'_, K, V> { } impl BTreeMap { - /// Makes a new empty BTreeMap. + /// Makes a new, empty `BTreeMap`. /// /// Does not allocate anything on its own. /// @@ -1924,7 +1924,7 @@ impl Hash for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeMap { - /// Creates an empty `BTreeMap`. + /// Creates an empty `BTreeMap`. fn default() -> BTreeMap { BTreeMap::new() } diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index e3e555a72de02..6a8be441513a0 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -112,20 +112,8 @@ impl InternalNode { /// /// However, `BoxedNode` contains no information as to which of the two types /// of nodes it actually contains, and, partially due to this lack of information, -/// has no destructor. -struct BoxedNode { - ptr: NonNull>, -} - -impl BoxedNode { - fn from_owned(ptr: NonNull>) -> Self { - BoxedNode { ptr } - } - - fn as_ptr(&self) -> NonNull> { - self.ptr - } -} +/// is not a separate type and has no destructor. +type BoxedNode = NonNull>; /// An owned tree. /// @@ -168,11 +156,6 @@ impl NodeRef { pub fn borrow_valmut(&mut self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } - - /// Packs the reference, aware of type and height, into a type-agnostic pointer. - fn into_boxed_node(self) -> BoxedNode { - BoxedNode::from_owned(self.node) - } } impl NodeRef { @@ -181,7 +164,7 @@ impl NodeRef { /// and is the opposite of `pop_internal_level`. pub fn push_internal_level(&mut self) -> NodeRef, K, V, marker::Internal> { let mut new_node = Box::new(unsafe { InternalNode::new() }); - new_node.edges[0].write(BoxedNode::from_owned(self.node)); + new_node.edges[0].write(self.node); let mut new_root = NodeRef::from_new_internal(new_node, self.height + 1); new_root.borrow_mut().first_edge().correct_parent_link(); *self = new_root.forget_type(); @@ -288,13 +271,6 @@ unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef Send for NodeRef, K, V, Type> {} unsafe impl Send for NodeRef {} -impl NodeRef { - /// Unpack a node reference that was packed by `Root::into_boxed_node`. - fn from_boxed_node(boxed_node: BoxedNode, height: usize) -> Self { - NodeRef { height, node: boxed_node.as_ptr(), _marker: PhantomData } - } -} - impl NodeRef { /// Unpack a node reference that was packed as `NodeRef::parent`. fn from_internal(node: NonNull>, height: usize) -> Self { @@ -695,7 +671,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { unsafe { self.reborrow_mut().into_key_area_mut_at(idx).write(key); self.reborrow_mut().into_val_area_mut_at(idx).write(val); - self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.into_boxed_node()); + self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.node); Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); } } @@ -710,7 +686,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { *self.reborrow_mut().into_len_mut() += 1; slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key); slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val); - slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.into_boxed_node()); + slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.node); } self.correct_all_childrens_parent_links(); @@ -732,8 +708,8 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(internal) => { - let boxed_node = ptr::read(internal.reborrow().edge_at(idx + 1)); - let mut edge = Root::from_boxed_node(boxed_node, internal.height - 1); + let node = ptr::read(internal.reborrow().edge_at(idx + 1)); + let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; // In practice, clearing the parent is a waste of time, because we will // insert the node elsewhere and set its parent link again. edge.borrow_mut().clear_parent_link(); @@ -760,9 +736,8 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(mut internal) => { - let boxed_node = - slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0); - let mut edge = Root::from_boxed_node(boxed_node, internal.height - 1); + let node = slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0); + let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; // In practice, clearing the parent is a waste of time, because we will // insert the node elsewhere and set its parent link again. edge.borrow_mut().clear_parent_link(); @@ -1041,12 +1016,11 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, debug_assert!(self.node.len() < CAPACITY); debug_assert!(edge.height == self.node.height - 1); - let boxed_node = edge.into_boxed_node(); unsafe { *self.node.reborrow_mut().into_len_mut() += 1; slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key); slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val); - slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, boxed_node); + slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, edge.node); self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len()); } @@ -1135,8 +1109,8 @@ impl Handle, marke // reference (Rust issue #73987) and invalidate any other references // to or inside the array, should any be around. let parent_ptr = NodeRef::as_internal_ptr(&self.node); - let boxed_node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() }; - NodeRef::from_boxed_node(boxed_node, self.node.height - 1) + let node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() }; + NodeRef { node, height: self.node.height - 1, _marker: PhantomData } } } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 1a807100653bc..f4046e87b99a8 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -220,7 +220,9 @@ impl fmt::Debug for Union<'_, T> { const ITER_PERFORMANCE_TIPPING_SIZE_DIFF: usize = 16; impl BTreeSet { - /// Makes a new `BTreeSet` with a reasonable choice of B. + /// Makes a new, empty `BTreeSet`. + /// + /// Does not allocate anything on its own. /// /// # Examples /// @@ -1121,7 +1123,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeSet { - /// Makes an empty `BTreeSet` with a reasonable choice of B. + /// Creates an empty `BTreeSet`. fn default() -> BTreeSet { BTreeSet::new() } diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 834dd4656ff76..b13019146568c 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::cmp::Ordering::{Equal, Greater, Less}; -use std::str::from_utf8; +use std::str::{from_utf8, from_utf8_unchecked}; #[test] fn test_le() { @@ -1971,3 +1971,97 @@ fn test_str_escapes() { "; assert_eq!(x, r"\\"); // extraneous whitespace stripped } + +#[test] +fn const_str_ptr() { + const A: [u8; 2] = ['h' as u8, 'i' as u8]; + const B: &'static [u8; 2] = &A; + const C: *const u8 = B as *const u8; + + unsafe { + let foo = &A as *const u8; + assert_eq!(foo, C); + assert_eq!(from_utf8_unchecked(&A), "hi"); + assert_eq!(*C, A[0]); + assert_eq!(*(&B[0] as *const u8), A[0]); + } +} + +#[test] +fn utf8() { + let yen: char = '¥'; // 0xa5 + let c_cedilla: char = 'ç'; // 0xe7 + let thorn: char = 'þ'; // 0xfe + let y_diaeresis: char = 'ÿ'; // 0xff + let pi: char = 'Π'; // 0x3a0 + + assert_eq!(yen as isize, 0xa5); + assert_eq!(c_cedilla as isize, 0xe7); + assert_eq!(thorn as isize, 0xfe); + assert_eq!(y_diaeresis as isize, 0xff); + assert_eq!(pi as isize, 0x3a0); + + assert_eq!(pi as isize, '\u{3a0}' as isize); + assert_eq!('\x0a' as isize, '\n' as isize); + + let bhutan: String = "འབྲུག་ཡུལ།".to_string(); + let japan: String = "日本".to_string(); + let uzbekistan: String = "Ўзбекистон".to_string(); + let austria: String = "Österreich".to_string(); + + let bhutan_e: String = + "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string(); + let japan_e: String = "\u{65e5}\u{672c}".to_string(); + let uzbekistan_e: String = + "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string(); + let austria_e: String = "\u{d6}sterreich".to_string(); + + let oo: char = 'Ö'; + assert_eq!(oo as isize, 0xd6); + + fn check_str_eq(a: String, b: String) { + let mut i: isize = 0; + for ab in a.bytes() { + println!("{}", i); + println!("{}", ab); + let bb: u8 = b.as_bytes()[i as usize]; + println!("{}", bb); + assert_eq!(ab, bb); + i += 1; + } + } + + check_str_eq(bhutan, bhutan_e); + check_str_eq(japan, japan_e); + check_str_eq(uzbekistan, uzbekistan_e); + check_str_eq(austria, austria_e); +} + +#[test] +fn utf8_chars() { + // Chars of 1, 2, 3, and 4 bytes + let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; + let s: String = chs.iter().cloned().collect(); + let schs: Vec = s.chars().collect(); + + assert_eq!(s.len(), 10); + assert_eq!(s.chars().count(), 4); + assert_eq!(schs.len(), 4); + assert_eq!(schs.iter().cloned().collect::(), s); + + assert!((from_utf8(s.as_bytes()).is_ok())); + // invalid prefix + assert!((!from_utf8(&[0x80]).is_ok())); + // invalid 2 byte prefix + assert!((!from_utf8(&[0xc0]).is_ok())); + assert!((!from_utf8(&[0xc0, 0x10]).is_ok())); + // invalid 3 byte prefix + assert!((!from_utf8(&[0xe0]).is_ok())); + assert!((!from_utf8(&[0xe0, 0x10]).is_ok())); + assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok())); + // invalid 4 byte prefix + assert!((!from_utf8(&[0xf0]).is_ok())); + assert!((!from_utf8(&[0xf0, 0x10]).is_ok())); + assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok())); + assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok())); +} diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 3244bbc2d670d..66c25e449df2b 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -408,3 +408,56 @@ fn ascii_const() { const BYTE_IS_ASCII: bool = 97u8.is_ascii(); assert!(BYTE_IS_ASCII); } + +#[test] +fn ascii_ctype_const() { + macro_rules! suite { + ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => { + $( + mod $fn { + const CHAR_A_LOWER: bool = 'a'.$fn(); + const CHAR_A_UPPER: bool = 'A'.$fn(); + const CHAR_NINE: bool = '9'.$fn(); + const CHAR_DOT: bool = '.'.$fn(); + const CHAR_SPACE: bool = ' '.$fn(); + + const U8_A_LOWER: bool = b'a'.$fn(); + const U8_A_UPPER: bool = b'A'.$fn(); + const U8_NINE: bool = b'9'.$fn(); + const U8_DOT: bool = b'.'.$fn(); + const U8_SPACE: bool = b' '.$fn(); + + pub fn run() { + assert_eq!(CHAR_A_LOWER, $a); + assert_eq!(CHAR_A_UPPER, $A); + assert_eq!(CHAR_NINE, $nine); + assert_eq!(CHAR_DOT, $dot); + assert_eq!(CHAR_SPACE, $space); + + assert_eq!(U8_A_LOWER, $a); + assert_eq!(U8_A_UPPER, $A); + assert_eq!(U8_NINE, $nine); + assert_eq!(U8_DOT, $dot); + assert_eq!(U8_SPACE, $space); + } + } + )* + + $( $fn::run(); )* + } + } + + suite! { + // 'a' 'A' '9' '.' ' ' + is_ascii_alphabetic => [true, true, false, false, false]; + is_ascii_uppercase => [false, true, false, false, false]; + is_ascii_lowercase => [true, false, false, false, false]; + is_ascii_alphanumeric => [true, true, true, false, false]; + is_ascii_digit => [false, false, true, false, false]; + is_ascii_hexdigit => [true, true, true, false, false]; + is_ascii_punctuation => [false, false, false, true, false]; + is_ascii_graphic => [true, true, true, true, false]; + is_ascii_whitespace => [false, false, false, false, true]; + is_ascii_control => [false, false, false, false, false]; + } +} diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index acbd913982c1f..75528ebb54eaf 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -101,3 +101,82 @@ fn static_init() { assert!(S_INT.fetch_add(1, SeqCst) == 0); assert!(S_UINT.fetch_add(1, SeqCst) == 0); } + +#[test] +fn atomic_access_bool() { + static mut ATOMIC: AtomicBool = AtomicBool::new(false); + + unsafe { + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.store(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_or(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_and(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.fetch_nand(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_xor(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + } +} + +#[test] +fn atomic_alignment() { + use std::mem::{align_of, size_of}; + + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::>(), size_of::>()); + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "16")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "16")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "32")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "32")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "64")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "64")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "128")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "128")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::(), size_of::()); +} + +#[test] +fn atomic_compare_exchange() { + use Ordering::*; + + static ATOMIC: AtomicIsize = AtomicIsize::new(0); + + ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); + ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); +} diff --git a/library/core/tests/bool.rs b/library/core/tests/bool.rs index e89eb2c7f94d5..e40f0482aee3e 100644 --- a/library/core/tests/bool.rs +++ b/library/core/tests/bool.rs @@ -1,3 +1,87 @@ +use core::cmp::Ordering::{Equal, Greater, Less}; +use core::ops::{BitAnd, BitOr, BitXor}; + +#[test] +fn test_bool() { + assert_eq!(false.eq(&true), false); + assert_eq!(false == false, true); + assert_eq!(false != true, true); + assert_eq!(false.ne(&false), false); + + assert_eq!(false.bitand(false), false); + assert_eq!(true.bitand(false), false); + assert_eq!(false.bitand(true), false); + assert_eq!(true.bitand(true), true); + + assert_eq!(false & false, false); + assert_eq!(true & false, false); + assert_eq!(false & true, false); + assert_eq!(true & true, true); + + assert_eq!(false.bitor(false), false); + assert_eq!(true.bitor(false), true); + assert_eq!(false.bitor(true), true); + assert_eq!(true.bitor(true), true); + + assert_eq!(false | false, false); + assert_eq!(true | false, true); + assert_eq!(false | true, true); + assert_eq!(true | true, true); + + assert_eq!(false.bitxor(false), false); + assert_eq!(true.bitxor(false), true); + assert_eq!(false.bitxor(true), true); + assert_eq!(true.bitxor(true), false); + + assert_eq!(false ^ false, false); + assert_eq!(true ^ false, true); + assert_eq!(false ^ true, true); + assert_eq!(true ^ true, false); + + assert_eq!(!true, false); + assert_eq!(!false, true); + + let s = false.to_string(); + assert_eq!(s, "false"); + let s = true.to_string(); + assert_eq!(s, "true"); + + assert!(true > false); + assert!(!(false > true)); + + assert!(false < true); + assert!(!(true < false)); + + assert!(false <= false); + assert!(false >= false); + assert!(true <= true); + assert!(true >= true); + + assert!(false <= true); + assert!(!(false >= true)); + assert!(true >= false); + assert!(!(true <= false)); + + assert_eq!(true.cmp(&true), Equal); + assert_eq!(false.cmp(&false), Equal); + assert_eq!(true.cmp(&false), Greater); + assert_eq!(false.cmp(&true), Less); +} + +#[test] +pub fn test_bool_not() { + if !false { + assert!((true)); + } else { + assert!((false)); + } + if !true { + assert!((false)); + } else { + assert!((true)); + } +} + #[test] fn test_bool_to_option() { assert_eq!(false.then_some(0), None); diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs index 835289daf715a..11cf7add07ada 100644 --- a/library/core/tests/cmp.rs +++ b/library/core/tests/cmp.rs @@ -132,3 +132,74 @@ fn ordering_const() { const THEN: Ordering = Equal.then(ORDERING); assert_eq!(THEN, Greater); } + +#[test] +fn cmp_default() { + // Test default methods in PartialOrd and PartialEq + + #[derive(Debug)] + struct Fool(bool); + + impl PartialEq for Fool { + fn eq(&self, other: &Fool) -> bool { + let Fool(this) = *self; + let Fool(other) = *other; + this != other + } + } + + struct Int(isize); + + impl PartialEq for Int { + fn eq(&self, other: &Int) -> bool { + let Int(this) = *self; + let Int(other) = *other; + this == other + } + } + + impl PartialOrd for Int { + fn partial_cmp(&self, other: &Int) -> Option { + let Int(this) = *self; + let Int(other) = *other; + this.partial_cmp(&other) + } + } + + struct RevInt(isize); + + impl PartialEq for RevInt { + fn eq(&self, other: &RevInt) -> bool { + let RevInt(this) = *self; + let RevInt(other) = *other; + this == other + } + } + + impl PartialOrd for RevInt { + fn partial_cmp(&self, other: &RevInt) -> Option { + let RevInt(this) = *self; + let RevInt(other) = *other; + other.partial_cmp(&this) + } + } + + assert!(Int(2) > Int(1)); + assert!(Int(2) >= Int(1)); + assert!(Int(1) >= Int(1)); + assert!(Int(1) < Int(2)); + assert!(Int(1) <= Int(2)); + assert!(Int(1) <= Int(1)); + + assert!(RevInt(2) < RevInt(1)); + assert!(RevInt(2) <= RevInt(1)); + assert!(RevInt(1) <= RevInt(1)); + assert!(RevInt(1) > RevInt(2)); + assert!(RevInt(1) >= RevInt(2)); + assert!(RevInt(1) >= RevInt(1)); + + assert_eq!(Fool(true), Fool(false)); + assert!(Fool(true) != Fool(true)); + assert!(Fool(false) != Fool(false)); + assert_eq!(Fool(false), Fool(true)); +} diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 75ca897cadc91..7d1980c27d487 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -3482,3 +3482,15 @@ fn test_flatten_non_fused_inner() { assert_eq!(iter.next(), Some(1)); assert_eq!(iter.next(), None); } + +#[test] +pub fn extend_for_unit() { + let mut x = 0; + { + let iter = (0..5).map(|_| { + x += 1; + }); + ().extend(iter); + } + assert_eq!(x, 5); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 14ef03fd53eba..07a36c3ec1e3d 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -8,6 +8,7 @@ #![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] +#![feature(cfg_target_has_atomic)] #![feature(const_assume)] #![feature(const_cell_into_inner)] #![feature(core_intrinsics)] @@ -81,6 +82,7 @@ mod hash; mod intrinsics; mod iter; mod lazy; +mod macros; mod manually_drop; mod mem; mod nonzero; @@ -97,3 +99,4 @@ mod str_lossy; mod task; mod time; mod tuple; +mod unicode; diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs new file mode 100644 index 0000000000000..482f3c1c99840 --- /dev/null +++ b/library/core/tests/macros.rs @@ -0,0 +1,14 @@ +#[test] +fn assert_eq_trailing_comma() { + assert_eq!(1, 1,); +} + +#[test] +fn assert_escape() { + assert!(r#"☃\backslash"#.contains("\\")); +} + +#[test] +fn assert_ne_trailing_comma() { + assert_ne!(1, 2,); +} diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs index 5d4ecb2669a96..01defab2b38f0 100644 --- a/library/core/tests/num/wrapping.rs +++ b/library/core/tests/num/wrapping.rs @@ -74,3 +74,236 @@ wrapping_test!(u64, u64::MIN, u64::MAX); #[cfg(not(target_os = "emscripten"))] wrapping_test!(u128, u128::MIN, u128::MAX); wrapping_test!(usize, usize::MIN, usize::MAX); + +// Don't warn about overflowing ops on 32-bit platforms +#[cfg_attr(target_pointer_width = "32", allow(const_err))] +fn wrapping_int_api() { + assert_eq!(i8::MAX.wrapping_add(1), i8::MIN); + assert_eq!(i16::MAX.wrapping_add(1), i16::MIN); + assert_eq!(i32::MAX.wrapping_add(1), i32::MIN); + assert_eq!(i64::MAX.wrapping_add(1), i64::MIN); + assert_eq!(isize::MAX.wrapping_add(1), isize::MIN); + + assert_eq!(i8::MIN.wrapping_sub(1), i8::MAX); + assert_eq!(i16::MIN.wrapping_sub(1), i16::MAX); + assert_eq!(i32::MIN.wrapping_sub(1), i32::MAX); + assert_eq!(i64::MIN.wrapping_sub(1), i64::MAX); + assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX); + + assert_eq!(u8::MAX.wrapping_add(1), u8::MIN); + assert_eq!(u16::MAX.wrapping_add(1), u16::MIN); + assert_eq!(u32::MAX.wrapping_add(1), u32::MIN); + assert_eq!(u64::MAX.wrapping_add(1), u64::MIN); + assert_eq!(usize::MAX.wrapping_add(1), usize::MIN); + + assert_eq!(u8::MIN.wrapping_sub(1), u8::MAX); + assert_eq!(u16::MIN.wrapping_sub(1), u16::MAX); + assert_eq!(u32::MIN.wrapping_sub(1), u32::MAX); + assert_eq!(u64::MIN.wrapping_sub(1), u64::MAX); + assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX); + + assert_eq!((0xfe_u8 as i8).wrapping_mul(16), (0xe0_u8 as i8)); + assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), (0xedc0_u16 as i16)); + assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), (0xedcb_a980_u32 as i32)); + assert_eq!( + (0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16), + (0xedcb_a987_6543_2170_u64 as i64) + ); + + match () { + #[cfg(target_pointer_width = "32")] + () => { + assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), (0xedcb_a980_u32 as isize)); + } + #[cfg(target_pointer_width = "64")] + () => { + assert_eq!( + (0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16), + (0xedcb_a987_6543_2170_u64 as isize) + ); + } + } + + assert_eq!((0xfe as u8).wrapping_mul(16), (0xe0 as u8)); + assert_eq!((0xfedc as u16).wrapping_mul(16), (0xedc0 as u16)); + assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), (0xedcb_a980 as u32)); + assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), (0xedcb_a987_6543_2170 as u64)); + + match () { + #[cfg(target_pointer_width = "32")] + () => { + assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), (0xedcb_a980 as usize)); + } + #[cfg(target_pointer_width = "64")] + () => { + assert_eq!( + (0xfedc_ba98_7654_3217 as usize).wrapping_mul(16), + (0xedcb_a987_6543_2170 as usize) + ); + } + } + + macro_rules! check_mul_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_mul($f), ($e) * $f); + }; + } + macro_rules! check_mul_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_mul($f), $e); + }; + } + + check_mul_no_wrap!(0xfe_u8 as i8, -1); + check_mul_no_wrap!(0xfedc_u16 as i16, -1); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_mul_no_wrap!(0xfe_u8 as i8, -2); + check_mul_no_wrap!(0xfedc_u16 as i16, -2); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2); + + check_mul_no_wrap!(0xfe_u8 as i8, 2); + check_mul_no_wrap!(0xfedc_u16 as i16, 2); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2); + + check_mul_wraps!(0x80_u8 as i8, -1); + check_mul_wraps!(0x8000_u16 as i16, -1); + check_mul_wraps!(0x8000_0000_u32 as i32, -1); + check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_mul_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_div_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_div($f), ($e) / $f); + }; + } + macro_rules! check_div_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_div($f), $e); + }; + } + + check_div_no_wrap!(0xfe_u8 as i8, -1); + check_div_no_wrap!(0xfedc_u16 as i16, -1); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_div_no_wrap!(0xfe_u8 as i8, -2); + check_div_no_wrap!(0xfedc_u16 as i16, -2); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); + + check_div_no_wrap!(0xfe_u8 as i8, 2); + check_div_no_wrap!(0xfedc_u16 as i16, 2); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); + + check_div_wraps!(-128 as i8, -1); + check_div_wraps!(0x8000_u16 as i16, -1); + check_div_wraps!(0x8000_0000_u32 as i32, -1); + check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_div_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_rem_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_rem($f), ($e) % $f); + }; + } + macro_rules! check_rem_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_rem($f), 0); + }; + } + + check_rem_no_wrap!(0xfe_u8 as i8, -1); + check_rem_no_wrap!(0xfedc_u16 as i16, -1); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_rem_no_wrap!(0xfe_u8 as i8, -2); + check_rem_no_wrap!(0xfedc_u16 as i16, -2); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); + + check_rem_no_wrap!(0xfe_u8 as i8, 2); + check_rem_no_wrap!(0xfedc_u16 as i16, 2); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); + + check_rem_wraps!(0x80_u8 as i8, -1); + check_rem_wraps!(0x8000_u16 as i16, -1); + check_rem_wraps!(0x8000_0000_u32 as i32, -1); + check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_rem_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_neg_no_wrap { + ($e:expr) => { + assert_eq!(($e).wrapping_neg(), -($e)); + }; + } + macro_rules! check_neg_wraps { + ($e:expr) => { + assert_eq!(($e).wrapping_neg(), ($e)); + }; + } + + check_neg_no_wrap!(0xfe_u8 as i8); + check_neg_no_wrap!(0xfedc_u16 as i16); + check_neg_no_wrap!(0xfedc_ba98_u32 as i32); + check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64); + check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize); + + check_neg_wraps!(0x80_u8 as i8); + check_neg_wraps!(0x8000_u16 as i16); + check_neg_wraps!(0x8000_0000_u32 as i32); + check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_neg_wraps!(0x8000_0000_u32 as isize); + } + #[cfg(target_pointer_width = "64")] + () => { + check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize); + } + } +} diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs index e9d595e65e2b2..53e5539fad91c 100644 --- a/library/core/tests/ops.rs +++ b/library/core/tests/ops.rs @@ -1,4 +1,5 @@ use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; +use core::ops::{Deref, DerefMut}; // Test the Range structs and syntax. @@ -197,3 +198,35 @@ fn range_structural_match() { _ => unreachable!(), } } + +// Test Deref implementations + +#[test] +fn deref_mut_on_ref() { + // Test that `&mut T` implements `DerefMut` + + fn inc + DerefMut>(mut t: T) { + *t += 1; + } + + let mut x: isize = 5; + inc(&mut x); + assert_eq!(x, 6); +} + +#[test] +fn deref_on_ref() { + // Test that `&T` and `&mut T` implement `Deref` + + fn deref>(t: T) -> U { + *t + } + + let x: isize = 3; + let y = deref(&x); + assert_eq!(y, 3); + + let mut x: isize = 4; + let y = deref(&mut x); + assert_eq!(y, 4); +} diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index ae814efec2086..5388b4756245a 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -402,3 +402,13 @@ fn test_unwrap_drop() { assert_eq!(x.get(), 0); } + +#[test] +pub fn option_ext() { + let thing = "{{ f }}"; + let f = thing.find("{{"); + + if f.is_none() { + println!("None!"); + } +} diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index bf977c141cbf8..47f0a573ce13e 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -400,3 +400,16 @@ fn align_offset_weird_strides() { } assert!(!x); } + +#[test] +fn offset_from() { + let mut a = [0; 5]; + let ptr1: *mut i32 = &mut a[1]; + let ptr2: *mut i32 = &mut a[3]; + unsafe { + assert_eq!(ptr2.offset_from(ptr1), 2); + assert_eq!(ptr1.offset_from(ptr2), -2); + assert_eq!(ptr1.offset(2), ptr2); + assert_eq!(ptr2.offset(-2), ptr1); + } +} diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 39ea4831b9b86..81660870e95e4 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -320,3 +320,41 @@ fn result_const() { const IS_ERR: bool = RESULT.is_err(); assert!(!IS_ERR) } + +#[test] +fn result_opt_conversions() { + #[derive(Copy, Clone, Debug, PartialEq)] + struct BadNumErr; + + fn try_num(x: i32) -> Result { + if x <= 5 { Ok(x + 1) } else { Err(BadNumErr) } + } + + type ResOpt = Result, BadNumErr>; + type OptRes = Option>; + + let mut x: ResOpt = Ok(Some(5)); + let mut y: OptRes = Some(Ok(5)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Ok(None); + y = None; + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Err(BadNumErr); + y = Some(Err(BadNumErr)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + let res: Result, BadNumErr> = (0..10) + .map(|x| { + let y = try_num(x)?; + Ok(if y % 2 == 0 { Some(y - 1) } else { None }) + }) + .filter_map(Result::transpose) + .collect(); + + assert_eq!(res, Err(BadNumErr)) +} diff --git a/library/core/tests/unicode.rs b/library/core/tests/unicode.rs new file mode 100644 index 0000000000000..c28ea859115e1 --- /dev/null +++ b/library/core/tests/unicode.rs @@ -0,0 +1,5 @@ +#[test] +pub fn version() { + let (major, _minor, _update) = core::unicode::UNICODE_VERSION; + assert!(major >= 10); +} diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index b990b78570393..80b74a9ba9b09 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1739,7 +1739,7 @@ mod super_keyword {} /// /// # Differences between the 2015 and 2018 editions /// -/// In the 2015 edition parameters pattern where not needed for traits: +/// In the 2015 edition the parameters pattern was not needed for traits: /// /// ```rust,edition2015 /// trait Tr { diff --git a/library/std/src/sys/sgx/ext/io.rs b/library/std/src/sys/sgx/ext/io.rs index f79874a4aec97..795a4d190cf4e 100644 --- a/library/std/src/sys/sgx/ext/io.rs +++ b/library/std/src/sys/sgx/ext/io.rs @@ -25,8 +25,11 @@ pub trait AsRawFd { /// descriptor. #[unstable(feature = "sgx_platform", issue = "56975")] pub trait FromRawFd { + /// An associated type that contains relevant metadata for `Self`. + type Metadata: Default; + /// Constructs a new instance of `Self` from the given raw file - /// descriptor. + /// descriptor and metadata. /// /// This function **consumes ownership** of the specified file /// descriptor. The returned object will take responsibility for closing @@ -38,7 +41,7 @@ pub trait FromRawFd { /// accidentally allow violating this contract which can cause memory /// unsafety in code that relies on it being true. #[unstable(feature = "sgx_platform", issue = "56975")] - unsafe fn from_raw_fd(fd: RawFd) -> Self; + unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self; } /// A trait to express the ability to consume an object and acquire ownership of @@ -71,18 +74,40 @@ impl AsRawFd for net::TcpListener { } } +/// Metadata for `TcpStream`. +#[derive(Debug, Clone, Default)] +#[unstable(feature = "sgx_platform", issue = "56975")] +pub struct TcpStreamMetadata { + /// Local address of the TCP stream + pub local_addr: Option, + /// Peer address of the TCP stream + pub peer_addr: Option, +} + impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + type Metadata = TcpStreamMetadata; + + unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpStream { let fd = sys::fd::FileDesc::from_inner(fd); - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, None))) + let socket = sys::net::Socket::from_inner((fd, metadata.local_addr)); + net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, metadata.peer_addr))) } } +/// Metadata for `TcpListener`. +#[derive(Debug, Clone, Default)] +#[unstable(feature = "sgx_platform", issue = "56975")] +pub struct TcpListenerMetadata { + /// Local address of the TCP listener + pub local_addr: Option, +} + impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + type Metadata = TcpListenerMetadata; + + unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpListener { let fd = sys::fd::FileDesc::from_inner(fd); - let socket = sys::net::Socket::from_inner(fd); + let socket = sys::net::Socket::from_inner((fd, metadata.local_addr)); net::TcpListener::from_inner(sys::net::TcpListener::from_inner(socket)) } } diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs index 666a157b09cd0..3dd8267921e5e 100644 --- a/library/std/src/sys/sgx/net.rs +++ b/library/std/src/sys/sgx/net.rs @@ -37,9 +37,9 @@ impl TryIntoInner for Socket { } } -impl FromInner for Socket { - fn from_inner(inner: FileDesc) -> Socket { - Socket { inner: Arc::new(inner), local_addr: None } +impl FromInner<(FileDesc, Option)> for Socket { + fn from_inner((inner, local_addr): (FileDesc, Option)) -> Socket { + Socket { inner: Arc::new(inner), local_addr } } } diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs index c94fc41178dfe..0e55ec648c9c5 100644 --- a/library/std/tests/env.rs +++ b/library/std/tests/env.rs @@ -1,5 +1,6 @@ use std::env::*; use std::ffi::{OsStr, OsString}; +use std::path::PathBuf; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; @@ -76,3 +77,63 @@ fn test_env_set_var() { assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" })); } + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] +#[allow(deprecated)] +fn env_home_dir() { + fn var_to_os_string(var: Result) -> Option { + match var { + Ok(var) => Some(OsString::from(var)), + Err(VarError::NotUnicode(var)) => Some(var), + _ => None, + } + } + + cfg_if::cfg_if! { + if #[cfg(unix)] { + let oldhome = var_to_os_string(var("HOME")); + + set_var("HOME", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + if cfg!(target_os = "android") { + assert!(home_dir().is_none()); + } else { + // When HOME is not set, some platforms return `None`, + // but others return `Some` with a default. + // Just check that it is not "/home/MountainView". + assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + } + + if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } + } else if #[cfg(windows)] { + let oldhome = var_to_os_string(var("HOME")); + let olduserprofile = var_to_os_string(var("USERPROFILE")); + + remove_var("HOME"); + remove_var("USERPROFILE"); + + assert!(home_dir().is_some()); + + set_var("HOME", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + + set_var("USERPROFILE", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + set_var("HOME", "/home/MountainView"); + set_var("USERPROFILE", "/home/PaloAlto"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + remove_var("USERPROFILE"); + + if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } + if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); } + } + } +} diff --git a/src/test/ui/sleep.rs b/library/std/tests/thread.rs similarity index 61% rename from src/test/ui/sleep.rs rename to library/std/tests/thread.rs index 3b3a4a4f3250c..047dec007b7cb 100644 --- a/src/test/ui/sleep.rs +++ b/library/std/tests/thread.rs @@ -1,18 +1,17 @@ -// run-pass -// ignore-emscripten no threads support - -use std::thread::{self, sleep}; -use std::time::Duration; use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; use std::u64; -fn main() { +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn sleep() { let finished = Arc::new(Mutex::new(false)); let t_finished = finished.clone(); thread::spawn(move || { - sleep(Duration::new(u64::MAX, 0)); + thread::sleep(Duration::new(u64::MAX, 0)); *t_finished.lock().unwrap() = true; }); - sleep(Duration::from_millis(100)); + thread::sleep(Duration::from_millis(100)); assert_eq!(*finished.lock().unwrap(), false); } diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index b5ade324bba10..b74d47a80027a 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -216,6 +216,10 @@ def cast_to_internal(node): internal_type = lookup_type(internal_type_name) return node.cast(internal_type.pointer()) + if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"): + # BACKCOMPAT: rust 1.49 + node_ptr = node_ptr["ptr"] + node_ptr = unwrap_unique_or_non_null(node_ptr) leaf = node_ptr.dereference() keys = leaf["keys"] vals = leaf["vals"] @@ -224,9 +228,8 @@ def cast_to_internal(node): for i in xrange(0, length + 1): if height > 0: - boxed_child_node = edges[i]["value"]["value"] - child_node = unwrap_unique_or_non_null(boxed_child_node["ptr"]) - for child in children_of_node(child_node, height - 1): + child_ptr = edges[i]["value"]["value"] + for child in children_of_node(child_ptr, height - 1): yield child if i < length: # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays. @@ -239,9 +242,6 @@ def cast_to_internal(node): if root.type.name.startswith("core::option::Option<"): root = root.cast(gdb.lookup_type(root.type.name[21:-1])) node_ptr = root["node"] - if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"): - node_ptr = node_ptr["ptr"] - node_ptr = unwrap_unique_or_non_null(node_ptr) height = root["height"] for child in children_of_node(node_ptr, height): yield child diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d58a88957df22..e76ca1022a943 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -234,9 +234,8 @@ impl Clean for doctree::Module<'_> { items.extend(self.fns.iter().map(|x| x.clean(cx))); items.extend(self.foreigns.iter().map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); - items.extend(self.items.iter().map(|x| x.clean(cx))); + items.extend(self.items.iter().map(|x| x.clean(cx)).flatten()); items.extend(self.traits.iter().map(|x| x.clean(cx))); - items.extend(self.impls.iter().flat_map(|x| x.clean(cx))); items.extend(self.macros.iter().map(|x| x.clean(cx))); items.extend(self.proc_macros.iter().map(|x| x.clean(cx))); @@ -1922,8 +1921,8 @@ impl Clean for hir::BareFnTy<'_> { } } -impl Clean for (&hir::Item<'_>, Option) { - fn clean(&self, cx: &DocContext<'_>) -> Item { +impl Clean> for (&hir::Item<'_>, Option) { + fn clean(&self, cx: &DocContext<'_>) -> Vec { use hir::ItemKind; let (item, renamed) = self; @@ -1977,10 +1976,11 @@ impl Clean for (&hir::Item<'_>, Option) { fields: variant_data.fields().clean(cx), fields_stripped: false, }), + ItemKind::Impl { .. } => return clean_impl(item, cx), _ => unreachable!("not yet converted"), }; - Item::from_def_id_and_parts(def_id, Some(name), kind, cx) + vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)] } } @@ -2005,57 +2005,53 @@ impl Clean for ty::ImplPolarity { } } -impl Clean> for doctree::Impl<'_> { - fn clean(&self, cx: &DocContext<'_>) -> Vec { - let mut ret = Vec::new(); - let trait_ = self.trait_.clean(cx); - let items = self.items.iter().map(|ii| ii.clean(cx)).collect::>(); - let def_id = cx.tcx.hir().local_def_id(self.id); - - // If this impl block is an implementation of the Deref trait, then we - // need to try inlining the target's inherent impl blocks as well. - if trait_.def_id() == cx.tcx.lang_items().deref_trait() { - build_deref_target_impls(cx, &items, &mut ret); +fn clean_impl(impl_: &hir::Item<'_>, cx: &DocContext<'_>) -> Vec { + let mut ret = Vec::new(); + let (trait_, items, for_, unsafety, generics) = match &impl_.kind { + hir::ItemKind::Impl { of_trait, items, self_ty, unsafety, generics, .. } => { + (of_trait, items, self_ty, *unsafety, generics) } - - let provided: FxHashSet = trait_ - .def_id() - .map(|did| { - cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect() - }) - .unwrap_or_default(); - - let for_ = self.for_.clean(cx); - let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) { - DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)), - _ => None, + _ => unreachable!(), + }; + let trait_ = trait_.clean(cx); + let items = items.iter().map(|ii| cx.tcx.hir().impl_item(ii.id).clean(cx)).collect::>(); + let def_id = cx.tcx.hir().local_def_id(impl_.hir_id); + + // If this impl block is an implementation of the Deref trait, then we + // need to try inlining the target's inherent impl blocks as well. + if trait_.def_id() == cx.tcx.lang_items().deref_trait() { + build_deref_target_impls(cx, &items, &mut ret); + } + + let provided: FxHashSet = trait_ + .def_id() + .map(|did| cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect()) + .unwrap_or_default(); + + let for_ = for_.clean(cx); + let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) { + DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)), + _ => None, + }); + let make_item = |trait_: Option, for_: Type, items: Vec| { + let kind = ImplItem(Impl { + unsafety, + generics: generics.clean(cx), + provided_trait_methods: provided.clone(), + trait_, + for_, + items, + polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)), + synthetic: false, + blanket_impl: None, }); - let make_item = |trait_: Option, for_: Type, items: Vec| Item { - name: None, - attrs: self.attrs.clean(cx), - source: self.span.clean(cx), - def_id: def_id.to_def_id(), - visibility: self.vis.clean(cx), - stability: cx.stability(self.id), - deprecation: cx.deprecation(self.id).clean(cx), - kind: ImplItem(Impl { - unsafety: self.unsafety, - generics: self.generics.clean(cx), - provided_trait_methods: provided.clone(), - trait_, - for_, - items, - polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)), - synthetic: false, - blanket_impl: None, - }), - }; - if let Some(type_alias) = type_alias { - ret.push(make_item(trait_.clone(), type_alias, items.clone())); - } - ret.push(make_item(trait_, for_, items)); - ret + Item::from_hir_id_and_parts(impl_.hir_id, None, kind, cx) + }; + if let Some(type_alias) = type_alias { + ret.push(make_item(trait_.clone(), type_alias, items.clone())); } + ret.push(make_item(trait_, for_, items)); + ret } impl Clean> for doctree::ExternCrate<'_> { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 413f5bdf5214b..b7cc0f1945911 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,4 +1,3 @@ -use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; use rustc_driver::abort_on_err; @@ -156,21 +155,6 @@ impl<'tcx> DocContext<'tcx> { def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)) } } - - crate fn stability(&self, id: HirId) -> Option { - self.tcx - .hir() - .opt_local_def_id(id) - .and_then(|def_id| self.tcx.lookup_stability(def_id.to_def_id())) - .cloned() - } - - crate fn deprecation(&self, id: HirId) -> Option { - self.tcx - .hir() - .opt_local_def_id(id) - .and_then(|def_id| self.tcx.lookup_deprecation(def_id.to_def_id())) - } } /// Creates a new diagnostic `Handler` that can be used to emit warnings and errors. diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index d56328cc2aa08..4d2fe04123bc2 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -23,7 +23,6 @@ crate struct Module<'hir> { // (item, renamed) crate items: Vec<(&'hir hir::Item<'hir>, Option)>, crate traits: Vec>, - crate impls: Vec>, crate foreigns: Vec>, crate macros: Vec, crate proc_macros: Vec, @@ -44,7 +43,6 @@ impl Module<'hir> { mods: Vec::new(), items: Vec::new(), traits: Vec::new(), - impls: Vec::new(), foreigns: Vec::new(), macros: Vec::new(), proc_macros: Vec::new(), @@ -89,22 +87,6 @@ crate struct Trait<'hir> { crate id: hir::HirId, } -#[derive(Debug)] -crate struct Impl<'hir> { - crate unsafety: hir::Unsafety, - crate polarity: hir::ImplPolarity, - crate defaultness: hir::Defaultness, - crate constness: hir::Constness, - crate generics: &'hir hir::Generics<'hir>, - crate trait_: &'hir Option>, - crate for_: &'hir hir::Ty<'hir>, - crate items: Vec<&'hir hir::ImplItem<'hir>>, - crate attrs: &'hir [ast::Attribute], - crate span: Span, - crate vis: &'hir hir::Visibility<'hir>, - crate id: hir::HirId, -} - crate struct ForeignItem<'hir> { crate id: hir::HirId, crate name: Symbol, diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index a72860ef0a8fd..285fabdc37230 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -16,7 +16,7 @@ impl StripItem { crate trait DocFolder: Sized { fn fold_item(&mut self, item: Item) -> Option { - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } /// don't override! @@ -71,15 +71,12 @@ crate trait DocFolder: Sized { } /// don't override! - fn fold_item_recur(&mut self, item: Item) -> Option { - let Item { attrs, name, source, visibility, def_id, kind, stability, deprecation } = item; - - let kind = match kind { + fn fold_item_recur(&mut self, mut item: Item) -> Item { + item.kind = match item.kind { StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)), - _ => self.fold_inner_recur(kind), + _ => self.fold_inner_recur(item.kind), }; - - Some(Item { attrs, name, source, kind, visibility, stability, deprecation, def_id }) + item } fn fold_mod(&mut self, m: Module) -> Module { diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 917c1a95fdbf5..39b750279ac5b 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -421,55 +421,52 @@ impl DocFolder for Cache { // Once we've recursively found all the generics, hoard off all the // implementations elsewhere. - let ret = self.fold_item_recur(item).and_then(|item| { - if let clean::Item { kind: clean::ImplItem(_), .. } = item { - // Figure out the id of this impl. This may map to a - // primitive rather than always to a struct/enum. - // Note: matching twice to restrict the lifetime of the `i` borrow. - let mut dids = FxHashSet::default(); - if let clean::Item { kind: clean::ImplItem(ref i), .. } = item { - match i.for_ { - clean::ResolvedPath { did, .. } - | clean::BorrowedRef { - type_: box clean::ResolvedPath { did, .. }, .. - } => { - dids.insert(did); - } - ref t => { - let did = t - .primitive_type() - .and_then(|t| self.primitive_locations.get(&t).cloned()); + let item = self.fold_item_recur(item); + let ret = if let clean::Item { kind: clean::ImplItem(_), .. } = item { + // Figure out the id of this impl. This may map to a + // primitive rather than always to a struct/enum. + // Note: matching twice to restrict the lifetime of the `i` borrow. + let mut dids = FxHashSet::default(); + if let clean::Item { kind: clean::ImplItem(ref i), .. } = item { + match i.for_ { + clean::ResolvedPath { did, .. } + | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => { + dids.insert(did); + } + ref t => { + let did = t + .primitive_type() + .and_then(|t| self.primitive_locations.get(&t).cloned()); - if let Some(did) = did { - dids.insert(did); - } + if let Some(did) = did { + dids.insert(did); } } + } - if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { - for bound in generics { - if let Some(did) = bound.def_id() { - dids.insert(did); - } + if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { + for bound in generics { + if let Some(did) = bound.def_id() { + dids.insert(did); } } - } else { - unreachable!() - }; - let impl_item = Impl { impl_item: item }; - if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) { - for did in dids { - self.impls.entry(did).or_insert(vec![]).push(impl_item.clone()); - } - } else { - let trait_did = impl_item.trait_did().expect("no trait did"); - self.orphan_trait_impls.push((trait_did, dids, impl_item)); } - None } else { - Some(item) + unreachable!() + }; + let impl_item = Impl { impl_item: item }; + if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) { + for did in dids { + self.impls.entry(did).or_insert(vec![]).push(impl_item.clone()); + } + } else { + let trait_did = impl_item.trait_did().expect("no trait did"); + self.orphan_trait_impls.push((trait_did, dids, impl_item)); } - }); + None + } else { + Some(item) + }; if pushed { self.stack.pop().expect("stack already empty"); diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 0f82649409f36..e7b5a90d84df0 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -60,7 +60,7 @@ impl<'a> DocFolder for SourceCollector<'a> { } }; } - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index aca218e538165..3f9978c8fca84 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -268,6 +268,6 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { } } - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index a48fa738e3b72..0c76dc571beee 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -105,7 +105,7 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { } } - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } } diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index 1f9f5c58e5a93..e1ba75baa0fa4 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -23,7 +23,7 @@ struct Collapser; impl fold::DocFolder for Collapser { fn fold_item(&mut self, mut i: Item) -> Option { i.attrs.collapse_doc_comments(); - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fd09ba04b3db9..6aa46b24a0e96 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -858,7 +858,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // we don't display docs on `extern crate` items anyway, so don't process them. clean::ExternCrateItem(..) => { debug!("ignoring extern crate item {:?}", item.def_id); - return self.fold_item_recur(item); + return Some(self.fold_item_recur(item)); } clean::ImportItem(Import { kind: clean::ImportKind::Simple(ref name, ..), .. }) => { Some(name.clone()) @@ -958,7 +958,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } - if item.is_mod() { + Some(if item.is_mod() { if !item.attrs.inner_docs { self.mod_ids.push(item.def_id); } @@ -968,7 +968,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { ret } else { self.fold_item_recur(item) - } + }) } } @@ -1022,7 +1022,7 @@ impl LinkCollector<'_, '_> { (link.trim(), None) }; - if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, ".contains(ch))) { + if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !".contains(ch))) { return None; } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 2946db1f46206..4c3defabc3294 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { } } - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } @@ -152,7 +152,7 @@ impl DocFolder for ItemCollector { fn fold_item(&mut self, i: Item) -> Option { self.items.insert(i.def_id); - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 60fe8080f56b4..299a73c8a0112 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -41,7 +41,7 @@ impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> { look_for_tests(&cx, &dox, &item); - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } } diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index 70748633117fb..a7a1ba1118d1f 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -178,7 +178,7 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { Some(hir_id) => hir_id, None => { // If non-local, no need to check anything. - return self.fold_item_recur(item); + return Some(self.fold_item_recur(item)); } }; let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); @@ -223,6 +223,6 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { } } - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } } diff --git a/src/librustdoc/passes/non_autolinks.rs b/src/librustdoc/passes/non_autolinks.rs index c9c49968b93e1..1f411b997f802 100644 --- a/src/librustdoc/passes/non_autolinks.rs +++ b/src/librustdoc/passes/non_autolinks.rs @@ -68,7 +68,7 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> { Some(hir_id) => hir_id, None => { // If non-local, no need to check anything. - return self.fold_item_recur(item); + return Some(self.fold_item_recur(item)); } }; let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); @@ -133,6 +133,6 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> { } } - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } } diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index fbfc693c5347d..6722d7c2fc9fe 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -39,6 +39,6 @@ impl DocFolder for CfgPropagator { let result = self.fold_item_recur(item); self.parent_cfg = old_parent_cfg; - result + Some(result) } } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 6da753ea6e695..6b59eb8cf288a 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -47,7 +47,7 @@ impl<'a> DocFolder for Stripper<'a> { // strip things like impl methods but when doing so // we must not add any items to the `retained` set. let old = mem::replace(&mut self.update_retained, false); - let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); + let ret = StripItem(self.fold_item_recur(i)).strip(); self.update_retained = old; return ret; } @@ -58,6 +58,6 @@ impl<'a> DocFolder for Stripper<'a> { self.retained.insert(i.def_id); } } - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index eb5a61a9d202a..444fd593ec9c9 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -22,7 +22,7 @@ impl<'a> DocFolder for Stripper<'a> { let old = mem::replace(&mut self.update_retained, false); let ret = self.fold_item_recur(i); self.update_retained = old; - return ret; + return Some(ret); } // These items can all get re-exported clean::OpaqueTyItem(..) @@ -59,7 +59,7 @@ impl<'a> DocFolder for Stripper<'a> { if i.def_id.is_local() && !i.visibility.is_public() { debug!("Stripper: stripping module {:?}", i.name); let old = mem::replace(&mut self.update_retained, false); - let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); + let ret = StripItem(self.fold_item_recur(i)).strip(); self.update_retained = old; return ret; } @@ -107,12 +107,10 @@ impl<'a> DocFolder for Stripper<'a> { self.fold_item_recur(i) }; - if let Some(ref i) = i { - if self.update_retained { - self.retained.insert(i.def_id); - } + if self.update_retained { + self.retained.insert(i.def_id); } - i + Some(i) } } @@ -153,7 +151,7 @@ impl<'a> DocFolder for ImplStripper<'a> { } } } - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } @@ -164,7 +162,7 @@ impl DocFolder for ImportStripper { fn fold_item(&mut self, i: Item) -> Option { match i.kind { clean::ExternCrateItem(..) | clean::ImportItem(..) if !i.visibility.is_public() => None, - _ => self.fold_item_recur(i), + _ => Some(self.fold_item_recur(i)), } } } diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index eb2f066bbdebb..d0345d1e48cb5 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -23,7 +23,7 @@ struct CommentCleaner; impl fold::DocFolder for CommentCleaner { fn fold_item(&mut self, mut i: Item) -> Option { i.attrs.unindent_doc_comments(); - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c55e5f7690c14..37050a57ca017 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -401,37 +401,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; om.traits.push(t); } - hir::ItemKind::Impl { - unsafety, - polarity, - defaultness, - constness, - defaultness_span: _, - ref generics, - ref of_trait, - self_ty, - ref items, - } => { + hir::ItemKind::Impl { ref of_trait, .. } => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. if !self.inlining && of_trait.is_none() { - let items = - items.iter().map(|item| self.cx.tcx.hir().impl_item(item.id)).collect(); - let i = Impl { - unsafety, - polarity, - defaultness, - constness, - generics, - trait_: of_trait, - for_: self_ty, - items, - attrs: &item.attrs, - id: item.hir_id, - span: item.span, - vis: &item.vis, - }; - om.impls.push(i); + om.items.push((item, None)); } } } diff --git a/src/test/codegen/fewer-names.rs b/src/test/codegen/fewer-names.rs new file mode 100644 index 0000000000000..53a926d49efe7 --- /dev/null +++ b/src/test/codegen/fewer-names.rs @@ -0,0 +1,20 @@ +// no-system-llvm +// compile-flags: -Coverflow-checks=no -O +// revisions: YES NO +// [YES]compile-flags: -Zfewer-names=yes +// [NO] compile-flags: -Zfewer-names=no +#![crate_type = "lib"] + +#[no_mangle] +pub fn sum(x: u32, y: u32) -> u32 { +// YES-LABEL: define i32 @sum(i32 %0, i32 %1) +// YES-NEXT: %3 = add i32 %1, %0 +// YES-NEXT: ret i32 %3 + +// NO-LABEL: define i32 @sum(i32 %x, i32 %y) +// NO-NEXT: start: +// NO-NEXT: %z = add i32 %y, %x +// NO-NEXT: ret i32 %z + let z = x + y; + z +} diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 31e7fc48afde5..be98cac94ece7 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -106,6 +106,15 @@ LL | /// [S!] | this link resolves to the struct `S`, which is not in the macro namespace | help: to link to the struct, prefix with `struct@`: `struct@S` +error: unresolved link to `S::h` + --> $DIR/intra-link-errors.rs:78:6 + | +LL | /// [type@S::h] + | ^^^^^^^^^ + | | + | this link resolves to the associated function `h`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `S::h()` + error: unresolved link to `T::g` --> $DIR/intra-link-errors.rs:86:6 | @@ -121,15 +130,6 @@ error: unresolved link to `T::h` LL | /// [T::h!] | ^^^^^ the trait `T` has no macro named `h` -error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:78:6 - | -LL | /// [type@S::h] - | ^^^^^^^^^ - | | - | this link resolves to the associated function `h`, which is not in the type namespace - | help: to link to the associated function, add parentheses: `S::h()` - error: unresolved link to `m` --> $DIR/intra-link-errors.rs:98:6 | diff --git a/src/test/rustdoc/intra-doc-link-generic-params.rs b/src/test/rustdoc/intra-doc-link-generic-params.rs index 7d7289437ff8a..1de6410f10c43 100644 --- a/src/test/rustdoc/intra-doc-link-generic-params.rs +++ b/src/test/rustdoc/intra-doc-link-generic-params.rs @@ -15,8 +15,11 @@ // @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option' //! We should also try linking to [`Result`]; it has *two* generics! +//! And [`Result`] and [`Result`]. //! // @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result' +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result' +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result' //! Now let's test a trickier case: [`Vec::::new`], or you could write it //! [with parentheses as `Vec::::new()`][Vec::::new()]. diff --git a/src/test/ui/assert-eq-trailing-comma.rs b/src/test/ui/assert-eq-trailing-comma.rs deleted file mode 100644 index 7071f80d7f7ba..0000000000000 --- a/src/test/ui/assert-eq-trailing-comma.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass - -fn main() { - assert_eq!(1, 1,); -} diff --git a/src/test/ui/assert-escape.rs b/src/test/ui/assert-escape.rs deleted file mode 100644 index 00e51d42cab9e..0000000000000 --- a/src/test/ui/assert-escape.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass - -fn main() { - assert!(r#"☃\backslash"#.contains("\\")); -} diff --git a/src/test/ui/assert-ne-trailing-comma.rs b/src/test/ui/assert-ne-trailing-comma.rs deleted file mode 100644 index 03308db9a1fee..0000000000000 --- a/src/test/ui/assert-ne-trailing-comma.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass - -fn main() { - assert_ne!(1, 2,); -} diff --git a/src/test/ui/atomic-access-bool.rs b/src/test/ui/atomic-access-bool.rs deleted file mode 100644 index e9d48bb3b43d8..0000000000000 --- a/src/test/ui/atomic-access-bool.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-pass - -#![allow(stable_features)] -#![feature(atomic_access)] -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering::*; - -static mut ATOMIC: AtomicBool = AtomicBool::new(false); - -fn main() { - unsafe { - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.store(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_or(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_and(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.fetch_nand(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_xor(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - } -} diff --git a/src/test/ui/atomic-alignment.rs b/src/test/ui/atomic-alignment.rs deleted file mode 100644 index 5bda90d2eab02..0000000000000 --- a/src/test/ui/atomic-alignment.rs +++ /dev/null @@ -1,38 +0,0 @@ -// run-pass - -#![feature(cfg_target_has_atomic)] -#![feature(integer_atomics)] - -use std::mem::{align_of, size_of}; -use std::sync::atomic::*; - -fn main() { - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::>(), size_of::>()); - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "16")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "16")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "32")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "32")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "64")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "64")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "128")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "128")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::(), size_of::()); -} diff --git a/src/test/ui/atomic-compare_exchange.rs b/src/test/ui/atomic-compare_exchange.rs deleted file mode 100644 index 9b327eef3c894..0000000000000 --- a/src/test/ui/atomic-compare_exchange.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -#![allow(stable_features)] - -#![feature(extended_compare_and_swap)] -use std::sync::atomic::AtomicIsize; -use std::sync::atomic::Ordering::*; - -static ATOMIC: AtomicIsize = AtomicIsize::new(0); - -fn main() { - // Make sure codegen can emit all the intrinsics correctly - ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); - ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); -} diff --git a/src/test/ui/bool-not.rs b/src/test/ui/bool-not.rs deleted file mode 100644 index 84713d6818a3e..0000000000000 --- a/src/test/ui/bool-not.rs +++ /dev/null @@ -1,6 +0,0 @@ -// run-pass - -pub fn main() { - if !false { assert!((true)); } else { assert!((false)); } - if !true { assert!((false)); } else { assert!((true)); } -} diff --git a/src/test/ui/bool.rs b/src/test/ui/bool.rs deleted file mode 100644 index 92f36c8fd25ad..0000000000000 --- a/src/test/ui/bool.rs +++ /dev/null @@ -1,72 +0,0 @@ -// run-pass -// Basic boolean tests - - -use std::cmp::Ordering::{Equal, Greater, Less}; -use std::ops::{BitAnd, BitOr, BitXor}; - -fn main() { - assert_eq!(false.eq(&true), false); - assert_eq!(false == false, true); - assert_eq!(false != true, true); - assert_eq!(false.ne(&false), false); - - assert_eq!(false.bitand(false), false); - assert_eq!(true.bitand(false), false); - assert_eq!(false.bitand(true), false); - assert_eq!(true.bitand(true), true); - - assert_eq!(false & false, false); - assert_eq!(true & false, false); - assert_eq!(false & true, false); - assert_eq!(true & true, true); - - assert_eq!(false.bitor(false), false); - assert_eq!(true.bitor(false), true); - assert_eq!(false.bitor(true), true); - assert_eq!(true.bitor(true), true); - - assert_eq!(false | false, false); - assert_eq!(true | false, true); - assert_eq!(false | true, true); - assert_eq!(true | true, true); - - assert_eq!(false.bitxor(false), false); - assert_eq!(true.bitxor(false), true); - assert_eq!(false.bitxor(true), true); - assert_eq!(true.bitxor(true), false); - - assert_eq!(false ^ false, false); - assert_eq!(true ^ false, true); - assert_eq!(false ^ true, true); - assert_eq!(true ^ true, false); - - assert_eq!(!true, false); - assert_eq!(!false, true); - - let s = false.to_string(); - assert_eq!(s, "false"); - let s = true.to_string(); - assert_eq!(s, "true"); - - assert!(true > false); - assert!(!(false > true)); - - assert!(false < true); - assert!(!(true < false)); - - assert!(false <= false); - assert!(false >= false); - assert!(true <= true); - assert!(true >= true); - - assert!(false <= true); - assert!(!(false >= true)); - assert!(true >= false); - assert!(!(true <= false)); - - assert_eq!(true.cmp(&true), Equal); - assert_eq!(false.cmp(&false), Equal); - assert_eq!(true.cmp(&false), Greater); - assert_eq!(false.cmp(&true), Less); -} diff --git a/src/test/ui/char_unicode.rs b/src/test/ui/char_unicode.rs deleted file mode 100644 index 65dda47066f4e..0000000000000 --- a/src/test/ui/char_unicode.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass - -/// Tests access to the Unicode version constant. -pub fn main() { - check(std::char::UNICODE_VERSION); -} - -pub fn check(unicode_version: (u8, u8, u8)) { - assert!(unicode_version.0 >= 10); -} diff --git a/src/test/ui/cmp-default.rs b/src/test/ui/cmp-default.rs deleted file mode 100644 index bb5c39f5cdea9..0000000000000 --- a/src/test/ui/cmp-default.rs +++ /dev/null @@ -1,73 +0,0 @@ -// run-pass - -use std::cmp::Ordering; - -// Test default methods in PartialOrd and PartialEq -// -#[derive(Debug)] -struct Fool(bool); - -impl PartialEq for Fool { - fn eq(&self, other: &Fool) -> bool { - let Fool(this) = *self; - let Fool(other) = *other; - this != other - } -} - -struct Int(isize); - -impl PartialEq for Int { - fn eq(&self, other: &Int) -> bool { - let Int(this) = *self; - let Int(other) = *other; - this == other - } -} - -impl PartialOrd for Int { - fn partial_cmp(&self, other: &Int) -> Option { - let Int(this) = *self; - let Int(other) = *other; - this.partial_cmp(&other) - } -} - -struct RevInt(isize); - -impl PartialEq for RevInt { - fn eq(&self, other: &RevInt) -> bool { - let RevInt(this) = *self; - let RevInt(other) = *other; - this == other - } -} - -impl PartialOrd for RevInt { - fn partial_cmp(&self, other: &RevInt) -> Option { - let RevInt(this) = *self; - let RevInt(other) = *other; - other.partial_cmp(&this) - } -} - -pub fn main() { - assert!(Int(2) > Int(1)); - assert!(Int(2) >= Int(1)); - assert!(Int(1) >= Int(1)); - assert!(Int(1) < Int(2)); - assert!(Int(1) <= Int(2)); - assert!(Int(1) <= Int(1)); - - assert!(RevInt(2) < RevInt(1)); - assert!(RevInt(2) <= RevInt(1)); - assert!(RevInt(1) <= RevInt(1)); - assert!(RevInt(1) > RevInt(2)); - assert!(RevInt(1) >= RevInt(2)); - assert!(RevInt(1) >= RevInt(1)); - - assert_eq!(Fool(true), Fool(false)); - assert!(Fool(true) != Fool(true)); - assert!(Fool(false) != Fool(false)); - assert_eq!(Fool(false), Fool(true)); -} diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.stderr b/src/test/ui/conditional-compilation/cfg-generic-params.stderr index d9e29c8262c63..4d6560e96e513 100644 --- a/src/test/ui/conditional-compilation/cfg-generic-params.stderr +++ b/src/test/ui/conditional-compilation/cfg-generic-params.stderr @@ -17,16 +17,16 @@ LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy; | ^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:34:43 + --> $DIR/cfg-generic-params.rs:19:29 | -LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; - | ^^^^^^^ +LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} + | ^^^^^^^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:30:40 + --> $DIR/cfg-generic-params.rs:22:29 | -LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; - | ^^^^^^^ +LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} + | ^^^^^^^ error: cannot find attribute `unknown` in this scope --> $DIR/cfg-generic-params.rs:26:34 @@ -35,16 +35,16 @@ LL | type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); | ^^^^^^^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:22:29 + --> $DIR/cfg-generic-params.rs:30:40 | -LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} - | ^^^^^^^ +LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; + | ^^^^^^^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:19:29 + --> $DIR/cfg-generic-params.rs:34:43 | -LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} - | ^^^^^^^ +LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; + | ^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/consts/ascii_ctype.rs b/src/test/ui/consts/ascii_ctype.rs deleted file mode 100644 index ef2f7322f2718..0000000000000 --- a/src/test/ui/consts/ascii_ctype.rs +++ /dev/null @@ -1,53 +0,0 @@ -// run-pass - -macro_rules! suite { - ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => { - $( - mod $fn { - const CHAR_A_LOWER: bool = 'a'.$fn(); - const CHAR_A_UPPER: bool = 'A'.$fn(); - const CHAR_NINE: bool = '9'.$fn(); - const CHAR_DOT: bool = '.'.$fn(); - const CHAR_SPACE: bool = ' '.$fn(); - - const U8_A_LOWER: bool = b'a'.$fn(); - const U8_A_UPPER: bool = b'A'.$fn(); - const U8_NINE: bool = b'9'.$fn(); - const U8_DOT: bool = b'.'.$fn(); - const U8_SPACE: bool = b' '.$fn(); - - pub fn run() { - assert_eq!(CHAR_A_LOWER, $a); - assert_eq!(CHAR_A_UPPER, $A); - assert_eq!(CHAR_NINE, $nine); - assert_eq!(CHAR_DOT, $dot); - assert_eq!(CHAR_SPACE, $space); - - assert_eq!(U8_A_LOWER, $a); - assert_eq!(U8_A_UPPER, $A); - assert_eq!(U8_NINE, $nine); - assert_eq!(U8_DOT, $dot); - assert_eq!(U8_SPACE, $space); - } - } - )* - - fn main() { - $( $fn::run(); )* - } - } -} - -suite! { - // 'a' 'A' '9' '.' ' ' - is_ascii_alphabetic => [true, true, false, false, false]; - is_ascii_uppercase => [false, true, false, false, false]; - is_ascii_lowercase => [true, false, false, false, false]; - is_ascii_alphanumeric => [true, true, true, false, false]; - is_ascii_digit => [false, false, true, false, false]; - is_ascii_hexdigit => [true, true, true, false, false]; - is_ascii_punctuation => [false, false, false, true, false]; - is_ascii_graphic => [true, true, true, true, false]; - is_ascii_whitespace => [false, false, false, false, true]; - is_ascii_control => [false, false, false, false, false]; -} diff --git a/src/test/ui/consts/const-str-ptr.rs b/src/test/ui/consts/const-str-ptr.rs deleted file mode 100644 index 56fd9d9f55ffc..0000000000000 --- a/src/test/ui/consts/const-str-ptr.rs +++ /dev/null @@ -1,17 +0,0 @@ -// run-pass -#![allow(unused_imports)] -use std::{str, string}; - -const A: [u8; 2] = ['h' as u8, 'i' as u8]; -const B: &'static [u8; 2] = &A; -const C: *const u8 = B as *const u8; - -pub fn main() { - unsafe { - let foo = &A as *const u8; - assert_eq!(foo, C); - assert_eq!(str::from_utf8_unchecked(&A), "hi"); - assert_eq!(*C, A[0]); - assert_eq!(*(&B[0] as *const u8), A[0]); - } -} diff --git a/src/test/ui/deref-mut-on-ref.rs b/src/test/ui/deref-mut-on-ref.rs deleted file mode 100644 index a6df5495a2775..0000000000000 --- a/src/test/ui/deref-mut-on-ref.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass -// Test that `&mut T` implements `DerefMut` - - -use std::ops::{Deref, DerefMut}; - -fn inc + DerefMut>(mut t: T) { - *t += 1; -} - -fn main() { - let mut x: isize = 5; - inc(&mut x); - assert_eq!(x, 6); -} diff --git a/src/test/ui/deref-on-ref.rs b/src/test/ui/deref-on-ref.rs deleted file mode 100644 index 973e61c9d59fa..0000000000000 --- a/src/test/ui/deref-on-ref.rs +++ /dev/null @@ -1,19 +0,0 @@ -// run-pass -// Test that `&T` and `&mut T` implement `Deref` - - -use std::ops::Deref; - -fn deref>(t: T) -> U { - *t -} - -fn main() { - let x: isize = 3; - let y = deref(&x); - assert_eq!(y, 3); - - let mut x: isize = 4; - let y = deref(&mut x); - assert_eq!(y, 4); -} diff --git a/src/test/ui/env-home-dir.rs b/src/test/ui/env-home-dir.rs deleted file mode 100644 index c597b4732d158..0000000000000 --- a/src/test/ui/env-home-dir.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-pass - -#![allow(unused_variables)] -#![allow(deprecated)] -// ignore-emscripten env vars don't work? -// ignore-sgx env vars cannot be modified - -use std::env::*; -use std::path::PathBuf; - -#[cfg(unix)] -fn main() { - let oldhome = var("HOME"); - - set_var("HOME", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - remove_var("HOME"); - if cfg!(target_os = "android") { - assert!(home_dir().is_none()); - } else { - // When HOME is not set, some platforms return `None`, - // but others return `Some` with a default. - // Just check that it is not "/home/MountainView". - assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - } -} - -#[cfg(windows)] -fn main() { - let oldhome = var("HOME"); - let olduserprofile = var("USERPROFILE"); - - remove_var("HOME"); - remove_var("USERPROFILE"); - - assert!(home_dir().is_some()); - - set_var("HOME", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - remove_var("HOME"); - - set_var("USERPROFILE", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - set_var("HOME", "/home/MountainView"); - set_var("USERPROFILE", "/home/PaloAlto"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); -} diff --git a/src/test/ui/extend-for-unit.rs b/src/test/ui/extend-for-unit.rs deleted file mode 100644 index 01d743f70bc0a..0000000000000 --- a/src/test/ui/extend-for-unit.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - -pub fn main() { - let mut x = 0; - { - let iter = (0..5).map(|_| { - x += 1; - }); - ().extend(iter); - } - assert_eq!(x, 5); -} diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr index b33710ce04958..f2287111719bc 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr @@ -1,50 +1,50 @@ -error: cannot find attribute `lt_hof` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:51:21 +error: cannot find attribute `lt_struct` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:4:15 | -LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 - | ^^^^^^ +LL | struct StLt<#[lt_struct] 'a>(&'a u32); + | ^^^^^^^^^ -error: cannot find attribute `ty_meth` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:46:15 +error: cannot find attribute `ty_struct` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:6:15 | -LL | fn m_ty<#[ty_meth] P>(_: P) { } - | ^^^^^^^ +LL | struct StTy<#[ty_struct] I>(I); + | ^^^^^^^^^ -error: cannot find attribute `lt_meth` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:44:15 +error: cannot find attribute `lt_enum` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:9:13 | -LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } - | ^^^^^^^ +LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } + | ^^^^^^^ -error: cannot find attribute `ty_fn` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:40:11 +error: cannot find attribute `ty_enum` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:11:13 | -LL | fn f_ty<#[ty_fn] O>(_: O) { } - | ^^^^^ +LL | enum EnTy<#[ty_enum] J> { A(J), B } + | ^^^^^^^ -error: cannot find attribute `lt_fn` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:38:11 +error: cannot find attribute `lt_trait` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:14:14 | -LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } - | ^^^^^ +LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } + | ^^^^^^^^ -error: cannot find attribute `ty_impl_for` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:33:8 +error: cannot find attribute `ty_trait` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:16:14 | -LL | impl<#[ty_impl_for] N> TrTy for StTy { - | ^^^^^^^^^^^ +LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } + | ^^^^^^^^ -error: cannot find attribute `lt_impl_for` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:29:8 +error: cannot find attribute `lt_type` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:19:13 | -LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { - | ^^^^^^^^^^^ +LL | type TyLt<#[lt_type] 'd> = &'d u32; + | ^^^^^^^ -error: cannot find attribute `ty_inherent` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:26:8 +error: cannot find attribute `ty_type` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:21:13 | -LL | impl<#[ty_inherent] M> StTy { } - | ^^^^^^^^^^^ +LL | type TyTy<#[ty_type] L> = (L, ); + | ^^^^^^^ error: cannot find attribute `lt_inherent` in this scope --> $DIR/feature-gate-custom_attribute2.rs:24:8 @@ -52,53 +52,53 @@ error: cannot find attribute `lt_inherent` in this scope LL | impl<#[lt_inherent] 'e> StLt<'e> { } | ^^^^^^^^^^^ -error: cannot find attribute `ty_type` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:21:13 +error: cannot find attribute `ty_inherent` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:26:8 | -LL | type TyTy<#[ty_type] L> = (L, ); - | ^^^^^^^ +LL | impl<#[ty_inherent] M> StTy { } + | ^^^^^^^^^^^ -error: cannot find attribute `lt_type` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:19:13 +error: cannot find attribute `lt_impl_for` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:29:8 | -LL | type TyLt<#[lt_type] 'd> = &'d u32; - | ^^^^^^^ +LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { + | ^^^^^^^^^^^ -error: cannot find attribute `ty_trait` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:16:14 +error: cannot find attribute `ty_impl_for` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:33:8 | -LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } - | ^^^^^^^^ +LL | impl<#[ty_impl_for] N> TrTy for StTy { + | ^^^^^^^^^^^ -error: cannot find attribute `lt_trait` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:14:14 +error: cannot find attribute `lt_fn` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:38:11 | -LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } - | ^^^^^^^^ +LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } + | ^^^^^ -error: cannot find attribute `ty_enum` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:11:13 +error: cannot find attribute `ty_fn` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:40:11 | -LL | enum EnTy<#[ty_enum] J> { A(J), B } - | ^^^^^^^ +LL | fn f_ty<#[ty_fn] O>(_: O) { } + | ^^^^^ -error: cannot find attribute `lt_enum` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:9:13 +error: cannot find attribute `lt_meth` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:44:15 | -LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } - | ^^^^^^^ +LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } + | ^^^^^^^ -error: cannot find attribute `ty_struct` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:6:15 +error: cannot find attribute `ty_meth` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:46:15 | -LL | struct StTy<#[ty_struct] I>(I); - | ^^^^^^^^^ +LL | fn m_ty<#[ty_meth] P>(_: P) { } + | ^^^^^^^ -error: cannot find attribute `lt_struct` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:4:15 +error: cannot find attribute `lt_hof` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:51:21 | -LL | struct StLt<#[lt_struct] 'a>(&'a u32); - | ^^^^^^^^^ +LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 + | ^^^^^^ error: aborting due to 17 previous errors diff --git a/src/test/ui/issues/issue-40845.stderr b/src/test/ui/issues/issue-40845.stderr index 2744330a4e58e..66bf053204c08 100644 --- a/src/test/ui/issues/issue-40845.stderr +++ b/src/test/ui/issues/issue-40845.stderr @@ -1,14 +1,14 @@ -error: cannot find macro `m` in this scope - --> $DIR/issue-40845.rs:4:10 - | -LL | impl S { m!(); } - | ^ - error: cannot find macro `m` in this scope --> $DIR/issue-40845.rs:1:11 | LL | trait T { m!(); } | ^ +error: cannot find macro `m` in this scope + --> $DIR/issue-40845.rs:4:10 + | +LL | impl S { m!(); } + | ^ + error: aborting due to 2 previous errors diff --git a/src/test/ui/offset_from.rs b/src/test/ui/offset_from.rs deleted file mode 100644 index aa59c119706ea..0000000000000 --- a/src/test/ui/offset_from.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass - -fn main() { - let mut a = [0; 5]; - let ptr1: *mut i32 = &mut a[1]; - let ptr2: *mut i32 = &mut a[3]; - unsafe { - assert_eq!(ptr2.offset_from(ptr1), 2); - assert_eq!(ptr1.offset_from(ptr2), -2); - assert_eq!(ptr1.offset(2), ptr2); - assert_eq!(ptr2.offset(-2), ptr1); - } -} diff --git a/src/test/ui/option-ext.rs b/src/test/ui/option-ext.rs deleted file mode 100644 index 76d0cf43984b3..0000000000000 --- a/src/test/ui/option-ext.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass - -pub fn main() { - let thing = "{{ f }}"; - let f = thing.find("{{"); - - if f.is_none() { - println!("None!"); - } -} diff --git a/src/test/ui/parser/default-unmatched-assoc.stderr b/src/test/ui/parser/default-unmatched-assoc.stderr index c8d1769cb5a2a..ee35fded99ec9 100644 --- a/src/test/ui/parser/default-unmatched-assoc.stderr +++ b/src/test/ui/parser/default-unmatched-assoc.stderr @@ -39,13 +39,13 @@ LL | } | - item list ends here error: cannot find macro `default` in this scope - --> $DIR/default-unmatched-assoc.rs:12:5 + --> $DIR/default-unmatched-assoc.rs:4:5 | LL | default!(); | ^^^^^^^ error: cannot find macro `default` in this scope - --> $DIR/default-unmatched-assoc.rs:4:5 + --> $DIR/default-unmatched-assoc.rs:12:5 | LL | default!(); | ^^^^^^^ diff --git a/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr index 40599d228b27a..16a08b9b85607 100644 --- a/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr +++ b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr @@ -34,15 +34,15 @@ LL | mac2! { does_not_exist!() } = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find macro `does_not_exist` in this scope - --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:20:13 + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13 | -LL | mac1! { does_not_exist!() } +LL | mac2! { does_not_exist!() } | ^^^^^^^^^^^^^^ error: cannot find macro `does_not_exist` in this scope - --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13 + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:20:13 | -LL | mac2! { does_not_exist!() } +LL | mac1! { does_not_exist!() } | ^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/resolve/macro-determinacy-non-module.rs b/src/test/ui/resolve/macro-determinacy-non-module.rs new file mode 100644 index 0000000000000..3215e0cd34605 --- /dev/null +++ b/src/test/ui/resolve/macro-determinacy-non-module.rs @@ -0,0 +1,7 @@ +// check-pass + +use std as line; + +const C: u32 = line!(); + +fn main() {} diff --git a/src/test/ui/result-opt-conversions.rs b/src/test/ui/result-opt-conversions.rs deleted file mode 100644 index 57f258aab654a..0000000000000 --- a/src/test/ui/result-opt-conversions.rs +++ /dev/null @@ -1,47 +0,0 @@ -// run-pass - -#[derive(Copy, Clone, Debug, PartialEq)] -struct BadNumErr; - -fn try_num(x: i32) -> Result { - if x <= 5 { - Ok(x + 1) - } else { - Err(BadNumErr) - } -} - -type ResOpt = Result, BadNumErr>; -type OptRes = Option>; - -fn main() { - let mut x: ResOpt = Ok(Some(5)); - let mut y: OptRes = Some(Ok(5)); - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - x = Ok(None); - y = None; - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - x = Err(BadNumErr); - y = Some(Err(BadNumErr)); - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - let res: Result, BadNumErr> = - (0..10) - .map(|x| { - let y = try_num(x)?; - Ok(if y % 2 == 0 { - Some(y - 1) - } else { - None - }) - }) - .filter_map(Result::transpose) - .collect(); - - assert_eq!(res, Err(BadNumErr)) -} diff --git a/src/test/ui/utf8.rs b/src/test/ui/utf8.rs deleted file mode 100644 index 75b6ddf7895c7..0000000000000 --- a/src/test/ui/utf8.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-pass - -pub fn main() { - let yen: char = '¥'; // 0xa5 - let c_cedilla: char = 'ç'; // 0xe7 - let thorn: char = 'þ'; // 0xfe - let y_diaeresis: char = 'ÿ'; // 0xff - let pi: char = 'Π'; // 0x3a0 - - assert_eq!(yen as isize, 0xa5); - assert_eq!(c_cedilla as isize, 0xe7); - assert_eq!(thorn as isize, 0xfe); - assert_eq!(y_diaeresis as isize, 0xff); - assert_eq!(pi as isize, 0x3a0); - - assert_eq!(pi as isize, '\u{3a0}' as isize); - assert_eq!('\x0a' as isize, '\n' as isize); - - let bhutan: String = "འབྲུག་ཡུལ།".to_string(); - let japan: String = "日本".to_string(); - let uzbekistan: String = "Ўзбекистон".to_string(); - let austria: String = "Österreich".to_string(); - - let bhutan_e: String = - "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string(); - let japan_e: String = "\u{65e5}\u{672c}".to_string(); - let uzbekistan_e: String = - "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string(); - let austria_e: String = "\u{d6}sterreich".to_string(); - - let oo: char = 'Ö'; - assert_eq!(oo as isize, 0xd6); - - fn check_str_eq(a: String, b: String) { - let mut i: isize = 0; - for ab in a.bytes() { - println!("{}", i); - println!("{}", ab); - let bb: u8 = b.as_bytes()[i as usize]; - println!("{}", bb); - assert_eq!(ab, bb); - i += 1; - } - } - - check_str_eq(bhutan, bhutan_e); - check_str_eq(japan, japan_e); - check_str_eq(uzbekistan, uzbekistan_e); - check_str_eq(austria, austria_e); -} diff --git a/src/test/ui/utf8_chars.rs b/src/test/ui/utf8_chars.rs deleted file mode 100644 index d764509813de1..0000000000000 --- a/src/test/ui/utf8_chars.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -use std::str; - -pub fn main() { - // Chars of 1, 2, 3, and 4 bytes - let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; - let s: String = chs.iter().cloned().collect(); - let schs: Vec = s.chars().collect(); - - assert_eq!(s.len(), 10); - assert_eq!(s.chars().count(), 4); - assert_eq!(schs.len(), 4); - assert_eq!(schs.iter().cloned().collect::(), s); - - assert!((str::from_utf8(s.as_bytes()).is_ok())); - // invalid prefix - assert!((!str::from_utf8(&[0x80]).is_ok())); - // invalid 2 byte prefix - assert!((!str::from_utf8(&[0xc0]).is_ok())); - assert!((!str::from_utf8(&[0xc0, 0x10]).is_ok())); - // invalid 3 byte prefix - assert!((!str::from_utf8(&[0xe0]).is_ok())); - assert!((!str::from_utf8(&[0xe0, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xe0, 0xff, 0x10]).is_ok())); - // invalid 4 byte prefix - assert!((!str::from_utf8(&[0xf0]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0xff, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok())); -} diff --git a/src/test/ui/wrapping-int-api.rs b/src/test/ui/wrapping-int-api.rs deleted file mode 100644 index ecdd742fb4e08..0000000000000 --- a/src/test/ui/wrapping-int-api.rs +++ /dev/null @@ -1,228 +0,0 @@ -// run-pass -// Test inherent wrapping_* methods for {i,u}{size,8,16,32,64}. - -// Don't warn about overflowing ops on 32-bit platforms -#![cfg_attr(target_pointer_width = "32", allow(const_err))] - -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; - -fn main() { - assert_eq!( i8::MAX.wrapping_add(1), i8::MIN); - assert_eq!( i16::MAX.wrapping_add(1), i16::MIN); - assert_eq!( i32::MAX.wrapping_add(1), i32::MIN); - assert_eq!( i64::MAX.wrapping_add(1), i64::MIN); - assert_eq!(isize::MAX.wrapping_add(1), isize::MIN); - - assert_eq!( i8::MIN.wrapping_sub(1), i8::MAX); - assert_eq!( i16::MIN.wrapping_sub(1), i16::MAX); - assert_eq!( i32::MIN.wrapping_sub(1), i32::MAX); - assert_eq!( i64::MIN.wrapping_sub(1), i64::MAX); - assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX); - - assert_eq!( u8::MAX.wrapping_add(1), u8::MIN); - assert_eq!( u16::MAX.wrapping_add(1), u16::MIN); - assert_eq!( u32::MAX.wrapping_add(1), u32::MIN); - assert_eq!( u64::MAX.wrapping_add(1), u64::MIN); - assert_eq!(usize::MAX.wrapping_add(1), usize::MIN); - - assert_eq!( u8::MIN.wrapping_sub(1), u8::MAX); - assert_eq!( u16::MIN.wrapping_sub(1), u16::MAX); - assert_eq!( u32::MIN.wrapping_sub(1), u32::MAX); - assert_eq!( u64::MIN.wrapping_sub(1), u64::MAX); - assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX); - - assert_eq!((0xfe_u8 as i8).wrapping_mul(16), - (0xe0_u8 as i8)); - assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), - (0xedc0_u16 as i16)); - assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), - (0xedcb_a980_u32 as i32)); - assert_eq!((0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16), - (0xedcb_a987_6543_2170_u64 as i64)); - - match () { - #[cfg(target_pointer_width = "32")] - () => { - assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), - (0xedcb_a980_u32 as isize)); - } - #[cfg(target_pointer_width = "64")] - () => { - assert_eq!((0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16), - (0xedcb_a987_6543_2170_u64 as isize)); - } - } - - assert_eq!((0xfe as u8).wrapping_mul(16), - (0xe0 as u8)); - assert_eq!((0xfedc as u16).wrapping_mul(16), - (0xedc0 as u16)); - assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), - (0xedcb_a980 as u32)); - assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), - (0xedcb_a987_6543_2170 as u64)); - - match () { - #[cfg(target_pointer_width = "32")] - () => { - assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), - (0xedcb_a980 as usize)); - } - #[cfg(target_pointer_width = "64")] - () => { - assert_eq!((0xfedc_ba98_7654_3217 as usize).wrapping_mul(16), - (0xedcb_a987_6543_2170 as usize)); - } - } - - macro_rules! check_mul_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_mul($f), ($e) * $f); } - } - macro_rules! check_mul_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_mul($f), $e); } - } - - check_mul_no_wrap!(0xfe_u8 as i8, -1); - check_mul_no_wrap!(0xfedc_u16 as i16, -1); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_mul_no_wrap!(0xfe_u8 as i8, -2); - check_mul_no_wrap!(0xfedc_u16 as i16, -2); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2); - - check_mul_no_wrap!(0xfe_u8 as i8, 2); - check_mul_no_wrap!(0xfedc_u16 as i16, 2); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2); - - check_mul_wraps!(0x80_u8 as i8, -1); - check_mul_wraps!(0x8000_u16 as i16, -1); - check_mul_wraps!(0x8000_0000_u32 as i32, -1); - check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_mul_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_div_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_div($f), ($e) / $f); } - } - macro_rules! check_div_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_div($f), $e); } - } - - check_div_no_wrap!(0xfe_u8 as i8, -1); - check_div_no_wrap!(0xfedc_u16 as i16, -1); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_div_no_wrap!(0xfe_u8 as i8, -2); - check_div_no_wrap!(0xfedc_u16 as i16, -2); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); - - check_div_no_wrap!(0xfe_u8 as i8, 2); - check_div_no_wrap!(0xfedc_u16 as i16, 2); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); - - check_div_wraps!(-128 as i8, -1); - check_div_wraps!(0x8000_u16 as i16, -1); - check_div_wraps!(0x8000_0000_u32 as i32, -1); - check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_div_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - - macro_rules! check_rem_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_rem($f), ($e) % $f); } - } - macro_rules! check_rem_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_rem($f), 0); } - } - - check_rem_no_wrap!(0xfe_u8 as i8, -1); - check_rem_no_wrap!(0xfedc_u16 as i16, -1); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_rem_no_wrap!(0xfe_u8 as i8, -2); - check_rem_no_wrap!(0xfedc_u16 as i16, -2); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); - - check_rem_no_wrap!(0xfe_u8 as i8, 2); - check_rem_no_wrap!(0xfedc_u16 as i16, 2); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); - - check_rem_wraps!(0x80_u8 as i8, -1); - check_rem_wraps!(0x8000_u16 as i16, -1); - check_rem_wraps!(0x8000_0000_u32 as i32, -1); - check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_rem_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_neg_no_wrap { - ($e:expr) => { assert_eq!(($e).wrapping_neg(), -($e)); } - } - macro_rules! check_neg_wraps { - ($e:expr) => { assert_eq!(($e).wrapping_neg(), ($e)); } - } - - check_neg_no_wrap!(0xfe_u8 as i8); - check_neg_no_wrap!(0xfedc_u16 as i16); - check_neg_no_wrap!(0xfedc_ba98_u32 as i32); - check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64); - check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize); - - check_neg_wraps!(0x80_u8 as i8); - check_neg_wraps!(0x8000_u16 as i16); - check_neg_wraps!(0x8000_0000_u32 as i32); - check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_neg_wraps!(0x8000_0000_u32 as isize); - } - #[cfg(target_pointer_width = "64")] - () => { - check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize); - } - } - -} diff --git a/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md b/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md index 6c92e10522c99..a3f114e0bb34f 100644 --- a/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md +++ b/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,8 @@ Thank you for making Clippy better! We're collecting our changelog from pull request descriptions. -If your PR only updates to the latest nightly, you can leave the -`changelog` entry as `none`. Otherwise, please write a short comment +If your PR only includes internal changes, you can just write +`changelog: none`. Otherwise, please write a short comment explaining your change. If your PR fixes an issue, you can add "fixes #issue_number" into this @@ -28,5 +28,5 @@ Delete this line and everything above before opening your PR. --- -*Please keep the line below* -changelog: none +*Please write a short comment explaining your change (or "none" for internal only changes)* +changelog: diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 1b9b33803de26..b9e4b0e67040c 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,117 @@ document. ## Unreleased / In Rust Nightly -[e636b88...master](https://github.com/rust-lang/rust-clippy/compare/e636b88...master) +[b20d4c1...master](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...master) + +## Rust 1.49 + +Current beta, release 2020-12-31 + +[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1) + +### New Lints + +* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911) +* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029) +* [`disallowed_method`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081) +* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092) +* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092) +* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101) +* [`mut_mutex_lock`] [#6103](https://github.com/rust-lang/rust-clippy/pull/6103) +* [`single_element_loop`] [#6109](https://github.com/rust-lang/rust-clippy/pull/6109) +* [`manual_unwrap_or`] [#6123](https://github.com/rust-lang/rust-clippy/pull/6123) +* [`large_types_passed_by_value`] [#6135](https://github.com/rust-lang/rust-clippy/pull/6135) +* [`result_unit_err`] [#6157](https://github.com/rust-lang/rust-clippy/pull/6157) +* [`ref_option_ref`] [#6165](https://github.com/rust-lang/rust-clippy/pull/6165) +* [`manual_range_contains`] [#6177](https://github.com/rust-lang/rust-clippy/pull/6177) +* [`unusual_byte_groupings`] [#6183](https://github.com/rust-lang/rust-clippy/pull/6183) +* [`comparison_to_empty`] [#6226](https://github.com/rust-lang/rust-clippy/pull/6226) +* [`map_collect_result_unit`] [#6227](https://github.com/rust-lang/rust-clippy/pull/6227) +* [`manual_ok_or`] [#6233](https://github.com/rust-lang/rust-clippy/pull/6233) + +### Moves and Deprecations + +* Rename `single_char_push_str` to [`single_char_add_str`] + [#6037](https://github.com/rust-lang/rust-clippy/pull/6037) +* Rename `zero_width_space` to [`invisible_characters`] + [#6105](https://github.com/rust-lang/rust-clippy/pull/6105) +* Deprecate [`drop_bounds`] (uplifted) + [#6111](https://github.com/rust-lang/rust-clippy/pull/6111) +* Move [`string_lit_as_bytes`] to `nursery` + [#6117](https://github.com/rust-lang/rust-clippy/pull/6117) +* Move [`rc_buffer`] to `restriction` + [#6128](https://github.com/rust-lang/rust-clippy/pull/6128) + +### Enhancements + +* [`manual_memcpy`]: Also lint when there are loop counters (and produce a + reliable suggestion) + [#5727](https://github.com/rust-lang/rust-clippy/pull/5727) +* [`single_char_add_str`]: Also lint on `String::insert_str` + [#6037](https://github.com/rust-lang/rust-clippy/pull/6037) +* [`invisible_characters`]: Also lint the characters `\u{AD}` and `\u{2060}` + [#6105](https://github.com/rust-lang/rust-clippy/pull/6105) +* [`eq_op`]: Also lint on the `assert_*!` macro family + [#6167](https://github.com/rust-lang/rust-clippy/pull/6167) +* [`items_after_statements`]: Also lint in local macro expansions + [#6176](https://github.com/rust-lang/rust-clippy/pull/6176) +* [`unnecessary_cast`]: Also lint casts on integer and float literals + [#6187](https://github.com/rust-lang/rust-clippy/pull/6187) +* [`manual_unwrap_or`]: Also lint `Result::unwrap_or` + [#6190](https://github.com/rust-lang/rust-clippy/pull/6190) +* [`match_like_matches_macro`]: Also lint when `match` has more than two arms + [#6216](https://github.com/rust-lang/rust-clippy/pull/6216) +* [`integer_arithmetic`]: Better handle `/` an `%` operators + [#6229](https://github.com/rust-lang/rust-clippy/pull/6229) + +### False Positive Fixes + +* [`needless_lifetimes`]: Bail out if the function has a `where` clause with the + lifetime [#5978](https://github.com/rust-lang/rust-clippy/pull/5978) +* [`explicit_counter_loop`]: No longer lints, when loop counter is used after it + is incremented [#6076](https://github.com/rust-lang/rust-clippy/pull/6076) +* [`or_fun_call`]: Revert changes addressing the handling of `const fn` + [#6077](https://github.com/rust-lang/rust-clippy/pull/6077) +* [`needless_range_loop`]: No longer lints, when the iterable is used in the + range [#6102](https://github.com/rust-lang/rust-clippy/pull/6102) +* [`inconsistent_digit_grouping`]: Fix bug when using floating point exponent + [#6104](https://github.com/rust-lang/rust-clippy/pull/6104) +* [`mistyped_literal_suffixes`]: No longer lints on the fractional part of a + float (e.g. `713.32_64`) + [#6114](https://github.com/rust-lang/rust-clippy/pull/6114) +* [`invalid_regex`]: No longer lint on unicode characters within `bytes::Regex` + [#6132](https://github.com/rust-lang/rust-clippy/pull/6132) +* [`boxed_local`]: No longer lints on `extern fn` arguments + [#6133](https://github.com/rust-lang/rust-clippy/pull/6133) +* [`needless_lifetimes`]: Fix regression, where lifetime is used in `where` + clause [#6198](https://github.com/rust-lang/rust-clippy/pull/6198) + +### Suggestion Fixes/Improvements + +* [`unnecessary_sort_by`]: Avoid dereferencing the suggested closure parameter + [#6078](https://github.com/rust-lang/rust-clippy/pull/6078) +* [`needless_arbitrary_self_type`]: Correctly handle expanded code + [#6093](https://github.com/rust-lang/rust-clippy/pull/6093) +* [`useless_format`]: Preserve raw strings in suggestion + [#6151](https://github.com/rust-lang/rust-clippy/pull/6151) +* [`empty_loop`]: Suggest alternatives + [#6162](https://github.com/rust-lang/rust-clippy/pull/6162) +* [`borrowed_box`]: Correctly add parentheses in suggestion + [#6200](https://github.com/rust-lang/rust-clippy/pull/6200) +* [`unused_unit`]: Improve suggestion formatting + [#6247](https://github.com/rust-lang/rust-clippy/pull/6247) + +### Documentation Improvements + +* Some doc improvements: + * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090) + * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162) +* [`doc_markdown`]: Document problematic link text style + [#6107](https://github.com/rust-lang/rust-clippy/pull/6107) ## Rust 1.48 -Current beta, release 2020-11-19 +Current stable, released 2020-11-19 [09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88) @@ -56,7 +162,7 @@ Current beta, release 2020-11-19 * [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`] [#5994](https://github.com/rust-lang/rust-clippy/pull/5994) -* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts +* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts [#5999](https://github.com/rust-lang/rust-clippy/pull/5999) * [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures [#5920](https://github.com/rust-lang/rust-clippy/pull/5920) @@ -64,7 +170,7 @@ Current beta, release 2020-11-19 [#5949](https://github.com/rust-lang/rust-clippy/pull/5949) * [`doc_markdown`]: allow using "GraphQL" without backticks [#5996](https://github.com/rust-lang/rust-clippy/pull/5996) -* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self` +* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self` [#5971](https://github.com/rust-lang/rust-clippy/pull/5971) * [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays [#6034](https://github.com/rust-lang/rust-clippy/pull/6034) @@ -85,19 +191,19 @@ Current beta, release 2020-11-19 [#5946](https://github.com/rust-lang/rust-clippy/pull/5946) * [`useless_conversion`]: show the type in the error message [#6035](https://github.com/rust-lang/rust-clippy/pull/6035) -* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message +* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message [#5892](https://github.com/rust-lang/rust-clippy/pull/5892) * [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous [#6043](https://github.com/rust-lang/rust-clippy/pull/6043) * [`default_trait_access`]: do not use unnecessary type parameters in the suggestion [#5993](https://github.com/rust-lang/rust-clippy/pull/5993) -* [`collapsible_if`]: don't use expanded code in the suggestion +* [`collapsible_if`]: don't use expanded code in the suggestion [#5992](https://github.com/rust-lang/rust-clippy/pull/5992) * Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`] [#6042](https://github.com/rust-lang/rust-clippy/pull/6042) * [`unit_arg`]: improve the readability of the suggestion [#5931](https://github.com/rust-lang/rust-clippy/pull/5931) -* [`stable_sort_primitive`]: print the type that is being sorted in the lint message +* [`stable_sort_primitive`]: print the type that is being sorted in the lint message [#5935](https://github.com/rust-lang/rust-clippy/pull/5935) * Show line count and max lines in [`too_many_lines`] lint message [#6009](https://github.com/rust-lang/rust-clippy/pull/6009) @@ -105,7 +211,7 @@ Current beta, release 2020-11-19 [#5900](https://github.com/rust-lang/rust-clippy/pull/5900) * [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly [#6024](https://github.com/rust-lang/rust-clippy/pull/6024) -* [`redundant_allocation`]: suggest replacing `Rc>` with `Rc` +* [`redundant_allocation`]: suggest replacing `Rc>` with `Rc` [#5899](https://github.com/rust-lang/rust-clippy/pull/5899) * Make lint messages adhere to rustc dev guide conventions [#5893](https://github.com/rust-lang/rust-clippy/pull/5893) @@ -128,7 +234,7 @@ Current beta, release 2020-11-19 ## Rust 1.47 -Current stable, released 2020-10-08 +Released 2020-10-08 [c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400) @@ -1787,6 +1893,7 @@ Released 2018-09-13 [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return +[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop [`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock [`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value @@ -1956,6 +2063,7 @@ Released 2018-09-13 [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars +[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools @@ -2006,6 +2114,7 @@ Released 2018-09-13 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap +[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern [`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern [`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index 8a5975e1f9711..1da626b505dfb 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -7,28 +7,22 @@ A collection of lints to catch common mistakes and improve your [Rust](https://g [There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) -We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: - -* `clippy::all` (everything that is on by default: all the categories below except for `nursery`, `pedantic`, and `cargo`) -* `clippy::correctness` (code that is just **outright wrong** or **very very useless**, causes hard errors by default) -* `clippy::style` (code that should be written in a more idiomatic way) -* `clippy::complexity` (code that does something simple but in a complex way) -* `clippy::perf` (code that can be written in a faster way) -* `clippy::pedantic` (lints which are rather strict, off by default) -* `clippy::nursery` (new lints that aren't quite ready yet, off by default) -* `clippy::cargo` (checks against the cargo manifest, off by default) +Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). +You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. + +Category | Description | Default level +-- | -- | -- +`clippy::all` | all lints that are on by default (correctness, style, complexity, perf) | **warn/deny** +`clippy::correctness` | code that is outright wrong or very useless | **deny** +`clippy::style` | code that should be written in a more idiomatic way | **warn** +`clippy::complexity` | code that does something simple but in a complex way | **warn** +`clippy::perf` | code that can be written to run faster | **warn** +`clippy::pedantic` | lints which are rather strict or might have false positives | allow +`clippy::nursery` | new lints that are still under development | allow +`clippy::cargo` | lints for the cargo manifest | allow More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas! -Only the following of those categories are enabled by default: - -* `clippy::style` -* `clippy::correctness` -* `clippy::complexity` -* `clippy::perf` - -Other categories need to be enabled in order for their lints to be executed. - The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also contains "restriction lints", which are for things which are usually not considered "bad", but may be useful to turn on in specific cases. These should be used very selectively, if at all. diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs index a52f0997d439d..62c73dbac48b4 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -129,7 +129,7 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) if let ExprKind::Block(ref block, _) = arms[0].body.kind; if block.stmts.is_empty(); if let Some(block_expr) = &block.expr; - // inner block is optional. unwarp it if it exists, or use the expression as is otherwise. + // inner block is optional. unwrap it if it exists, or use the expression as is otherwise. if let Some(begin_panic_call) = match block_expr.kind { ExprKind::Block(ref inner_block, _) => &inner_block.expr, _ => &block.expr, diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index fcebb54c6c217..58892024ce243 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { /// } /// ``` pub AWAIT_HOLDING_LOCK, - correctness, + pedantic, "Inside an async function, holding a MutexGuard while calling await" } @@ -65,8 +65,8 @@ declare_clippy_lint! { /// use std::cell::RefCell; /// /// async fn foo(x: &RefCell) { - /// let b = x.borrow_mut()(); - /// *ref += 1; + /// let mut y = x.borrow_mut(); + /// *y += 1; /// bar.await; /// } /// ``` @@ -77,14 +77,14 @@ declare_clippy_lint! { /// /// async fn foo(x: &RefCell) { /// { - /// let b = x.borrow_mut(); - /// *ref += 1; + /// let mut y = x.borrow_mut(); + /// *y += 1; /// } /// bar.await; /// } /// ``` pub AWAIT_HOLDING_REFCELL_REF, - correctness, + pedantic, "Inside an async function, holding a RefCell ref while calling await" } diff --git a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs index 76a000157df03..0d294761af5ab 100644 --- a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs +++ b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs @@ -23,6 +23,21 @@ declare_clippy_lint! { /// [package] /// name = "clippy" /// version = "0.0.212" + /// description = "A bunch of helpful lints to avoid common pitfalls in Rust" + /// repository = "https://github.com/rust-lang/rust-clippy" + /// readme = "README.md" + /// license = "MIT OR Apache-2.0" + /// keywords = ["clippy", "lint", "plugin"] + /// categories = ["development-tools", "development-tools::cargo-plugins"] + /// ``` + /// + /// Should include an authors field like: + /// + /// ```toml + /// # This `Cargo.toml` includes all common metadata + /// [package] + /// name = "clippy" + /// version = "0.0.212" /// authors = ["Someone "] /// description = "A bunch of helpful lints to avoid common pitfalls in Rust" /// repository = "https://github.com/rust-lang/rust-clippy" diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index 461c6e31d3eb4..1c3285ed701db 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -181,3 +181,8 @@ declare_deprecated_lint! { pub TEMPORARY_CSTRING_AS_PTR, "this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`" } + +declare_deprecated_lint! { + pub PANIC_PARAMS, + "this lint has been uplifted to rustc and is now called `panic_fmt`" +} diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 8e2f03d6e4e91..8842901d90b83 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -69,7 +69,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for comparing to an empty slice such as "" or [],` + /// **What it does:** Checks for comparing to an empty slice such as `""` or `[]`, /// and suggests using `.is_empty()` where applicable. /// /// **Why is this bad?** Some structures can answer `.is_empty()` much faster diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index ae2f6131b5b8f..6a5a77f8690a9 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -5,7 +5,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; +use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; declare_clippy_lint! { /// **What it does:** Checks for `let _ = ` @@ -58,7 +58,48 @@ declare_clippy_lint! { "non-binding let on a synchronization lock" } -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK]); +declare_clippy_lint! { + /// **What it does:** Checks for `let _ = ` + /// where expr has a type that implements `Drop` + /// + /// **Why is this bad?** This statement immediately drops the initializer + /// expression instead of extending its lifetime to the end of the scope, which + /// is often not intended. To extend the expression's lifetime to the end of the + /// scope, use an underscore-prefixed name instead (i.e. _var). If you want to + /// explicitly drop the expression, `std::mem::drop` conveys your intention + /// better and is less error-prone. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// Bad: + /// ```rust,ignore + /// struct Droppable; + /// impl Drop for Droppable { + /// fn drop(&mut self) {} + /// } + /// { + /// let _ = Droppable; + /// // ^ dropped here + /// /* more code */ + /// } + /// ``` + /// + /// Good: + /// ```rust,ignore + /// { + /// let _droppable = Droppable; + /// /* more code */ + /// // dropped at end of scope + /// } + /// ``` + pub LET_UNDERSCORE_DROP, + pedantic, + "non-binding let on a type that implements `Drop`" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]); const SYNC_GUARD_PATHS: [&[&str]; 3] = [ &paths::MUTEX_GUARD, @@ -84,6 +125,15 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }); + let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait| + init_ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => { + implements_trait(cx, inner_ty, drop_trait, &[]) + }, + + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) + ); if contains_sync_guard { span_lint_and_help( cx, @@ -94,6 +144,16 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" ) + } else if implements_drop { + span_lint_and_help( + cx, + LET_UNDERSCORE_DROP, + local.span, + "non-binding `let` on a type that implements `Drop`", + None, + "consider using an underscore-prefixed named \ + binding or dropping explicitly with `std::mem::drop`" + ) } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 19bf67d80c428..7e8cbd00c22a1 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -323,6 +323,7 @@ mod unicode; mod unit_return_expecting_ord; mod unnamed_address; mod unnecessary_sort_by; +mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; mod unused_io_amount; @@ -495,6 +496,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "clippy::temporary_cstring_as_ptr", "this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`", ); + store.register_removed( + "clippy::panic_params", + "this lint has been uplifted to rustc and is now called `panic_fmt`", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` // begin register lints, do not remove this comment, it’s used in `update_lints` @@ -622,6 +627,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, &let_if_seq::USELESS_LET_IF_SEQ, + &let_underscore::LET_UNDERSCORE_DROP, &let_underscore::LET_UNDERSCORE_LOCK, &let_underscore::LET_UNDERSCORE_MUST_USE, &lifetimes::EXTRA_UNUSED_LIFETIMES, @@ -831,6 +837,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &stable_sort_primitive::STABLE_SORT_PRIMITIVE, &strings::STRING_ADD, &strings::STRING_ADD_ASSIGN, + &strings::STRING_FROM_UTF8_AS_BYTES, &strings::STRING_LIT_AS_BYTES, &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, @@ -889,6 +896,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unnamed_address::FN_ADDRESS_COMPARISONS, &unnamed_address::VTABLE_ADDRESS_COMPARISONS, &unnecessary_sort_by::UNNECESSARY_SORT_BY, + &unnecessary_wraps::UNNECESSARY_WRAPS, &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, &unused_io_amount::UNUSED_IO_AMOUNT, @@ -1061,6 +1069,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box redundant_clone::RedundantClone); store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy); + store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps); store.register_late_pass(|| box types::RefToMut); store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); @@ -1215,6 +1224,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(&attrs::INLINE_ALWAYS), + LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK), + LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(&bit_mask::VERBOSE_BIT_MASK), LintId::of(&checked_conversions::CHECKED_CONVERSIONS), LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), @@ -1238,6 +1249,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&infinite_iter::MAYBE_INFINITE_ITER), LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS), + LintId::of(&let_underscore::LET_UNDERSCORE_DROP), LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), LintId::of(&literal_representation::UNREADABLE_LITERAL), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), @@ -1317,8 +1329,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&attrs::MISMATCHED_TARGET_OS), LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), LintId::of(&attrs::USELESS_ATTRIBUTE), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(&bit_mask::BAD_BIT_MASK), LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(&blacklisted_name::BLACKLISTED_NAME), @@ -1525,6 +1535,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), + LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), @@ -1565,6 +1576,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unused_unit::UNUSED_UNIT), @@ -1749,6 +1761,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), LintId::of(&repeat_once::REPEAT_ONCE), + LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), LintId::of(&swap::MANUAL_SWAP), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), @@ -1767,6 +1780,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&useless_conversion::USELESS_CONVERSION), LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), @@ -1779,8 +1793,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&attrs::DEPRECATED_SEMVER), LintId::of(&attrs::MISMATCHED_TARGET_OS), LintId::of(&attrs::USELESS_ATTRIBUTE), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(&bit_mask::BAD_BIT_MASK), LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(&booleans::LOGIC_BUG), diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index 5a4264f9b5c4e..0d31e9cfc3dec 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -4,10 +4,10 @@ use crate::utils::sugg::Sugg; use crate::utils::usage::{is_unused, mutated_variables}; use crate::utils::{ contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, - indent_of, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, - match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path, snippet, - snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, - span_lint_and_then, sugg, SpanlessEq, + indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, + last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path, + snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, + span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -543,17 +543,15 @@ impl<'tcx> LateLintPass<'tcx> for Loops { // (also matches an explicit "match" instead of "if let") // (even if the "match" or "if let" is used for declaration) if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind { - // also check for empty `loop {}` statements - // TODO(issue #6161): Enable for no_std crates (outside of #[panic_handler]) - if block.stmts.is_empty() && block.expr.is_none() && !is_no_std_crate(cx.tcx.hir().krate()) { - span_lint_and_help( - cx, - EMPTY_LOOP, - expr.span, - "empty `loop {}` wastes CPU cycles", - None, - "You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.", - ); + // also check for empty `loop {}` statements, skipping those in #[panic_handler] + if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) { + let msg = "empty `loop {}` wastes CPU cycles"; + let help = if is_no_std_crate(cx.tcx.hir().krate()) { + "you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body" + } else { + "you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body" + }; + span_lint_and_help(cx, EMPTY_LOOP, expr.span, msg, None, help); } // extract the expression from the first statement (if any) in a block diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 864d1ea87f575..7b3b450ef93e9 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use crate::utils::paths::FUTURE_FROM_GENERATOR; -use crate::utils::{match_function_call, snippet_block, snippet_opt, span_lint_and_then}; +use crate::utils::{match_function_call, position_before_rarrow, snippet_block, snippet_opt, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { |diag| { if_chain! { if let Some(header_snip) = snippet_opt(cx, header_span); - if let Some(ret_pos) = header_snip.rfind("->"); + if let Some(ret_pos) = position_before_rarrow(header_snip.clone()); if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output); then { let help = format!("make the function `async` and {}", ret_sugg); @@ -194,7 +194,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, }, _ => { let sugg = "return the output of the future directly"; - snippet_opt(cx, output.span).map(|snip| (sugg, format!("-> {}", snip))) + snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {}", snip))) }, } } diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs index 034cd99a9be06..220240acb7aa9 100644 --- a/src/tools/clippy/clippy_lints/src/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/map_clone.rs @@ -8,13 +8,15 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::Mutability; use rustc_middle::ty; +use rustc_middle::ty::adjustment::Adjust; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests - /// `iterator.cloned()` instead + /// **What it does:** Checks for usage of `map(|x| x.clone())` or + /// dereferencing closures for `Copy` types, on `Iterator` or `Option`, + /// and suggests `cloned()` or `copied()` instead /// /// **Why is this bad?** Readability, this can be written more concisely /// @@ -75,14 +77,19 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { } } }, - hir::ExprKind::MethodCall(ref method, _, ref obj, _) => { - if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone" - && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) { - - let obj_ty = cx.typeck_results().expr_ty(&obj[0]); - if let ty::Ref(_, ty, _) = obj_ty.kind() { - let copy = is_copy(cx, ty); - lint(cx, e.span, args[0].span, copy); + hir::ExprKind::MethodCall(ref method, _, [obj], _) => if_chain! { + if ident_eq(name, obj) && method.ident.name == sym::clone; + if match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT); + // no autoderefs + if !cx.typeck_results().expr_adjustments(obj).iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))); + then { + let obj_ty = cx.typeck_results().expr_ty(obj); + if let ty::Ref(_, ty, mutability) = obj_ty.kind() { + if matches!(mutability, Mutability::Not) { + let copy = is_copy(cx, ty); + lint(cx, e.span, args[0].span, copy); + } } else { lint_needless_cloning(cx, e.span, args[0].span); } diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs index ae37942e55a1b..540a1484a8558 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,14 +1,12 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use crate::utils::{ in_macro, match_qpath, match_type, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet, - snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, + snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, visitors::find_all_ret_expressions, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::LateContext; -use rustc_middle::hir::map::Map; use rustc_span::Span; pub(crate) struct OptionAndThenSome; @@ -193,124 +191,3 @@ pub(crate) trait BindInsteadOfMap { } } } - -/// returns `true` if expr contains match expr desugared from try -fn contains_try(expr: &hir::Expr<'_>) -> bool { - struct TryFinder { - found: bool, - } - - impl<'hir> intravisit::Visitor<'hir> for TryFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - if self.found { - return; - } - match expr.kind { - hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true, - _ => intravisit::walk_expr(self, expr), - } - } - } - - let mut visitor = TryFinder { found: false }; - visitor.visit_expr(expr); - visitor.found -} - -fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool -where - F: FnMut(&'hir hir::Expr<'hir>) -> bool, -{ - struct RetFinder { - in_stmt: bool, - failed: bool, - cb: F, - } - - struct WithStmtGuarg<'a, F> { - val: &'a mut RetFinder, - prev_in_stmt: bool, - } - - impl RetFinder { - fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { - let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); - WithStmtGuarg { - val: self, - prev_in_stmt, - } - } - } - - impl std::ops::Deref for WithStmtGuarg<'_, F> { - type Target = RetFinder; - - fn deref(&self) -> &Self::Target { - self.val - } - } - - impl std::ops::DerefMut for WithStmtGuarg<'_, F> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.val - } - } - - impl Drop for WithStmtGuarg<'_, F> { - fn drop(&mut self) { - self.val.in_stmt = self.prev_in_stmt; - } - } - - impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { - intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { - if self.failed { - return; - } - if self.in_stmt { - match expr.kind { - hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), - _ => intravisit::walk_expr(self, expr), - } - } else { - match expr.kind { - hir::ExprKind::Match(cond, arms, _) => { - self.inside_stmt(true).visit_expr(cond); - for arm in arms { - self.visit_expr(arm.body); - } - }, - hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), - hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), - _ => self.failed |= !(self.cb)(expr), - } - } - } - } - - !contains_try(expr) && { - let mut ret_finder = RetFinder { - in_stmt: false, - failed: false, - cb: callback, - }; - ret_finder.visit_expr(expr); - !ret_finder.failed - } -} diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 30f4c0c56d27b..fa1744043657a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -515,11 +515,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for an iterator search (such as `find()`, + /// **What it does:** Checks for an iterator or string search (such as `find()`, /// `position()`, or `rposition()`) followed by a call to `is_some()`. /// /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.any(_)`. + /// `_.any(_)` or `_.contains(_)`. /// /// **Known problems:** None. /// @@ -535,7 +535,7 @@ declare_clippy_lint! { /// ``` pub SEARCH_IS_SOME, complexity, - "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`" + "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`" } declare_clippy_lint! { @@ -1351,7 +1351,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map(_).collect::()`. + /// **What it does:** Checks for usage of `_.map(_).collect::()`. /// /// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic. /// @@ -1797,12 +1797,20 @@ fn lint_or_fun_call<'tcx>( cx: &LateContext<'tcx>, name: &str, method_span: Span, - fun_span: Span, self_expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, - or_has_args: bool, span: Span, + // None if lambda is required + fun_span: Option, ) { + // (path, fn_has_argument, methods, suffix) + static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ + (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), + (&paths::RESULT, true, &["or", "unwrap_or"], "else"), + ]; + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { if path.ident.as_str() == "len" { let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); @@ -1818,16 +1826,8 @@ fn lint_or_fun_call<'tcx>( } } - // (path, fn_has_argument, methods, suffix) - let know_types: &[(&[_], _, &[_], _)] = &[ - (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), - (&paths::RESULT, true, &["or", "unwrap_or"], "else"), - ]; - if_chain! { - if know_types.iter().any(|k| k.2.contains(&name)); + if KNOW_TYPES.iter().any(|k| k.2.contains(&name)); if is_lazyness_candidate(cx, arg); if !contains_return(&arg); @@ -1835,15 +1835,23 @@ fn lint_or_fun_call<'tcx>( let self_ty = cx.typeck_results().expr_ty(self_expr); if let Some(&(_, fn_has_arguments, poss, suffix)) = - know_types.iter().find(|&&i| match_type(cx, self_ty, i.0)); + KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0)); if poss.contains(&name); then { - let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) { - (true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(), - (false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(), - (false, true) => snippet_with_macro_callsite(cx, fun_span, ".."), + let sugg: Cow<'_, str> = { + let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { + (false, Some(fun_span)) => (fun_span, false), + _ => (arg.span, true), + }; + let snippet = snippet_with_macro_callsite(cx, snippet_span, ".."); + if use_lambda { + let l_arg = if fn_has_arguments { "_" } else { "" }; + format!("|{}| {}", l_arg, snippet).into() + } else { + snippet + } }; let span_replace_word = method_span.with_hi(span.hi()); span_lint_and_sugg( @@ -1864,28 +1872,13 @@ fn lint_or_fun_call<'tcx>( hir::ExprKind::Call(ref fun, ref or_args) => { let or_has_args = !or_args.is_empty(); if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { - check_general_case( - cx, - name, - method_span, - fun.span, - &args[0], - &args[1], - or_has_args, - expr.span, - ); + let fun_span = if or_has_args { None } else { Some(fun.span) }; + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span); } }, - hir::ExprKind::MethodCall(_, span, ref or_args, _) => check_general_case( - cx, - name, - method_span, - span, - &args[0], - &args[1], - !or_args.is_empty(), - expr.span, - ), + hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); + }, _ => {}, } } @@ -3048,6 +3041,7 @@ fn lint_flat_map_identity<'tcx>( } /// lint searching an Iterator followed by `is_some()` +/// or calling `find()` on a string followed by `is_some()` fn lint_search_is_some<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, @@ -3059,10 +3053,10 @@ fn lint_search_is_some<'tcx>( // lint if caller of search is an Iterator if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { let msg = format!( - "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \ - expressed by calling `any()`.", + "called `is_some()` after searching an `Iterator` with `{}`", search_method ); + let hint = "this is more succinctly expressed by calling `any()`"; let search_snippet = snippet(cx, search_args[1].span, ".."); if search_snippet.lines().count() <= 1 { // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` @@ -3090,7 +3084,7 @@ fn lint_search_is_some<'tcx>( SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), &msg, - "try this", + "use `any()` instead", format!( "any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) @@ -3098,7 +3092,36 @@ fn lint_search_is_some<'tcx>( Applicability::MachineApplicable, ); } else { - span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); + span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint); + } + } + // lint if `find()` is called by `String` or `&str` + else if search_method == "find" { + let is_string_or_str_slice = |e| { + let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); + if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { + true + } else { + *self_ty.kind() == ty::Str + } + }; + if_chain! { + if is_string_or_str_slice(&search_args[0]); + if is_string_or_str_slice(&search_args[1]); + then { + let msg = "called `is_some()` after calling `find()` on a string"; + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + msg, + "use `contains()` instead", + format!("contains({})", find_arg), + applicability, + ); + } } } } @@ -3901,21 +3924,24 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); - let from_iter_id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); - let iter_id = get_trait_def_id(cx, &paths::ITERATOR).unwrap(); + if_chain! { + if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); + if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR); - if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]) { - // `expr` implements `FromIterator` trait - let iter_expr = snippet(cx, args[0].span, ".."); - span_lint_and_sugg( - cx, - FROM_ITER_INSTEAD_OF_COLLECT, - expr.span, - "usage of `FromIterator::from_iter`", - "use `.collect()` instead of `::from_iter()`", - format!("{}.collect()", iter_expr), - Applicability::MaybeIncorrect, - ); + if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); + then { + // `expr` implements `FromIterator` trait + let iter_expr = snippet(cx, args[0].span, ".."); + span_lint_and_sugg( + cx, + FROM_ITER_INSTEAD_OF_COLLECT, + expr.span, + "usage of `FromIterator::from_iter`", + "use `.collect()` instead of `::from_iter()`", + format!("{}.collect()", iter_expr), + Applicability::MaybeIncorrect, + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs index cde89983a2656..a867bdb326d72 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -33,6 +33,17 @@ pub(super) fn lint<'tcx>( } else { "unnecessary closure used to substitute value for `Result::Err`" }; + let applicability = if body + .params + .iter() + // bindings are checked to be unused above + .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) + { + Applicability::MachineApplicable + } else { + // replacing the lambda may break type inference + Applicability::MaybeIncorrect + }; span_lint_and_sugg( cx, @@ -46,7 +57,7 @@ pub(super) fn lint<'tcx>( simplify_using, snippet(cx, body_expr.span, ".."), ), - Applicability::MachineApplicable, + applicability, ); } } diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 9cceecc785a28..11044e0c2fb48 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -89,11 +89,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir:: for (hir_ty, ty) in decl.inputs.iter().zip(fn_sig.inputs().skip_binder().iter()) { check_ty(cx, hir_ty.span, ty); } - check_ty( - cx, - decl.output.span(), - cx.tcx.erase_late_bound_regions(fn_sig.output()), - ); + check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output())); } // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 7b662eae7753e..6b0d198edcffa 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -5,11 +5,15 @@ use std::ptr; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp}; +use rustc_hir::def_id::DefId; +use rustc_hir::{ + BodyId, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp, +}; use rustc_infer::traits::specialization_graph; use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_middle::mir::interpret::{ConstValue, ErrorHandled}; use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{AssocKind, Ty}; +use rustc_middle::ty::{self, AssocKind, Const, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; @@ -36,14 +40,17 @@ declare_clippy_lint! { /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, /// and this lint should be suppressed. /// - /// When an enum has variants with interior mutability, use of its non interior mutable - /// variants can generate false positives. See issue - /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) + /// Even though the lint avoids triggering on a constant whose type has enums that have variants + /// with interior mutability, and its value uses non interior mutable variants (see + /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and + /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples); + /// it complains about associated constants without default values only based on its types; + /// which might not be preferable. + /// There're other enums plus associated constants cases that the lint cannot handle. /// /// Types that have underlying or potential interior mutability trigger the lint whether /// the interior mutable field is used or not. See issues /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and - /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) /// /// **Example:** /// ```rust @@ -105,6 +112,79 @@ declare_clippy_lint! { "referencing `const` with interior mutability" } +fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, + // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is + // 'unfrozen'. However, this code causes a false negative in which + // a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell`. + // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` + // since it works when a pointer indirection involves (`Cell<*const T>`). + // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; + // but I'm not sure whether it's a decent way, if possible. + cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) +} + +fn is_value_unfrozen_raw<'tcx>( + cx: &LateContext<'tcx>, + result: Result, ErrorHandled>, + ty: Ty<'tcx>, +) -> bool { + fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool { + match val.ty.kind() { + // the fact that we have to dig into every structs to search enums + // leads us to the point checking `UnsafeCell` directly is the only option. + ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true, + ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { + let val = cx.tcx.destructure_const(cx.param_env.and(val)); + val.fields.iter().any(|field| inner(cx, field)) + }, + _ => false, + } + } + + result.map_or_else( + |err| { + // Consider `TooGeneric` cases as being unfrozen. + // This causes a false positive where an assoc const whose type is unfrozen + // have a value that is a frozen variant with a generic param (an example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`). + // However, it prevents a number of false negatives that is, I think, important: + // 1. assoc consts in trait defs referring to consts of themselves + // (an example is `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). + // 2. a path expr referring to assoc consts whose type is doesn't have + // any frozen variants in trait defs (i.e. without substitute for `Self`). + // (e.g. borrowing `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) + // 3. similar to the false positive above; + // but the value is an unfrozen variant, or the type has no enums. (An example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` + // and `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). + // One might be able to prevent these FNs correctly, and replace this with `false`; + // e.g. implementing `has_frozen_variant` described above, and not running this function + // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd + // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, + // similar to 2., but with the a frozen variant) (e.g. borrowing + // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). + // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). + err == ErrorHandled::TooGeneric + }, + |val| inner(cx, Const::from_value(cx.tcx, val, ty)), + ) +} + +fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { + let result = cx.tcx.const_eval_poly(body_id.hir_id.owner.to_def_id()); + is_value_unfrozen_raw(cx, result, ty) +} + +fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { + let substs = cx.typeck_results().node_substs(hir_id); + + let result = cx + .tcx + .const_eval_resolve(cx.param_env, ty::WithOptConstParam::unknown(def_id), substs, None, None); + is_value_unfrozen_raw(cx, result, ty) +} + #[derive(Copy, Clone)] enum Source { Item { item: Span }, @@ -130,19 +210,7 @@ impl Source { } } -fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) { - // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, - // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is - // 'unfrozen'. However, this code causes a false negative in which - // a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell`. - // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` - // since it works when a pointer indirection involves (`Cell<*const T>`). - // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; - // but I'm not sure whether it's a decent way, if possible. - if cx.tcx.layout_of(cx.param_env.and(ty)).is_err() || ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) { - return; - } - +fn lint(cx: &LateContext<'_>, source: Source) { let (lint, msg, span) = source.lint(); span_lint_and_then(cx, lint, span, msg, |diag| { if span.from_expansion() { @@ -165,24 +233,44 @@ declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTER impl<'tcx> LateLintPass<'tcx> for NonCopyConst { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { - if let ItemKind::Const(hir_ty, ..) = &it.kind { + if let ItemKind::Const(hir_ty, body_id) = it.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); - verify_ty_bound(cx, ty, Source::Item { item: it.span }); + + if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) { + lint(cx, Source::Item { item: it.span }); + } } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind { + if let TraitItemKind::Const(hir_ty, body_id_opt) = &trait_item.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); + // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - verify_ty_bound(cx, normalized, Source::Assoc { item: trait_item.span }); + if is_unfrozen(cx, normalized) + // When there's no default value, lint it only according to its type; + // in other words, lint consts whose value *could* be unfrozen, not definitely is. + // This feels inconsistent with how the lint treats generic types, + // which avoids linting types which potentially become unfrozen. + // One could check whether a unfrozen type have a *frozen variant* + // (like `body_id_opt.map_or_else(|| !has_frozen_variant(...), ...)`), + // and do the same as the case of generic types at impl items. + // Note that it isn't sufficient to check if it has an enum + // since all of that enum's variants can be unfrozen: + // i.e. having an enum doesn't necessary mean a type has a frozen variant. + // And, implementing it isn't a trivial task; it'll probably end up + // re-implementing the trait predicate evaluation specific to `Freeze`. + && body_id_opt.map_or(true, |body_id| is_value_unfrozen_poly(cx, body_id, normalized)) + { + lint(cx, Source::Assoc { item: trait_item.span }); + } } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind { + if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind { let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id); let item = cx.tcx.hir().expect_item(item_hir_id); @@ -209,16 +297,23 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { ), )) .is_err(); + // If there were a function like `has_frozen_variant` described above, + // we should use here as a frozen variant is a potential to be frozen + // similar to unknown layouts. + // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` then { let ty = hir_ty_to_ty(cx.tcx, hir_ty); let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - verify_ty_bound( - cx, - normalized, - Source::Assoc { - item: impl_item.span, - }, - ); + if is_unfrozen(cx, normalized) + && is_value_unfrozen_poly(cx, *body_id, normalized) + { + lint( + cx, + Source::Assoc { + item: impl_item.span, + }, + ); + } } } }, @@ -226,7 +321,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { let ty = hir_ty_to_ty(cx.tcx, hir_ty); // Normalize assoc types originated from generic params. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - verify_ty_bound(cx, normalized, Source::Assoc { item: impl_item.span }); + + if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, *body_id, normalized) { + lint(cx, Source::Assoc { item: impl_item.span }); + } }, _ => (), } @@ -241,8 +339,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } // Make sure it is a const item. - match qpath_res(cx, qpath, expr.hir_id) { - Res::Def(DefKind::Const | DefKind::AssocConst, _) => {}, + let item_def_id = match qpath_res(cx, qpath, expr.hir_id) { + Res::Def(DefKind::Const | DefKind::AssocConst, did) => did, _ => return, }; @@ -319,7 +417,9 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { cx.typeck_results().expr_ty(dereferenced_expr) }; - verify_ty_bound(cx, ty, Source::Expr { expr: expr.span }); + if is_unfrozen(cx, ty) && is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) { + lint(cx, Source::Expr { expr: expr.span }); + } } } } diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index 6b175490cc833..5b42b61fcde90 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -1,7 +1,5 @@ use crate::utils::{span_lint, span_lint_and_then}; -use rustc_ast::ast::{ - Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind, -}; +use rustc_ast::ast::{Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind}; use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_middle::lint::in_external_macro; diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs index 8b10d07164712..31b03ecd101c0 100644 --- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs +++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs @@ -73,7 +73,7 @@ declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANI impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(_) = match_panic_call(cx, expr) { + if match_panic_call(cx, expr).is_some() { let span = get_outer_span(expr); if is_expn_of(expr.span, "unimplemented").is_some() { span_lint( diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 79e9a56af9a19..4b514bbd42ca7 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -222,13 +222,14 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' let name = snippet_with_applicability(cx, name_span, "_", &mut applicability); let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability); let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability); + let space = if lo.ends_with('.') { " " } else { "" }; span_lint_and_sugg( cx, MANUAL_RANGE_CONTAINS, span, &format!("manual `{}::contains` implementation", range_type), "use", - format!("({}{}{}).contains(&{})", lo, range_op, hi, name), + format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), applicability, ); } else if !combine_and && ord == Some(lord) { @@ -251,13 +252,14 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' let name = snippet_with_applicability(cx, name_span, "_", &mut applicability); let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability); let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability); + let space = if lo.ends_with('.') { " " } else { "" }; span_lint_and_sugg( cx, MANUAL_RANGE_CONTAINS, span, &format!("manual `!{}::contains` implementation", range_type), "use", - format!("!({}{}{}).contains(&{})", lo, range_op, hi, name), + format!("!({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), applicability, ); } diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 602facbe062ac..f0e507105a6a0 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -320,11 +320,11 @@ fn find_stmt_assigns_to<'tcx>( match (by_ref, &*rvalue) { (true, mir::Rvalue::Ref(_, _, place)) | (false, mir::Rvalue::Use(mir::Operand::Copy(place))) => { - base_local_and_movability(cx, mir, *place) + Some(base_local_and_movability(cx, mir, *place)) }, (false, mir::Rvalue::Ref(_, _, place)) => { if let [mir::ProjectionElem::Deref] = place.as_ref().projection { - base_local_and_movability(cx, mir, *place) + Some(base_local_and_movability(cx, mir, *place)) } else { None } @@ -341,7 +341,7 @@ fn base_local_and_movability<'tcx>( cx: &LateContext<'tcx>, mir: &mir::Body<'tcx>, place: mir::Place<'tcx>, -) -> Option<(mir::Local, CannotMoveOut)> { +) -> (mir::Local, CannotMoveOut) { use rustc_middle::mir::PlaceRef; // Dereference. You cannot move things out from a borrowed value. @@ -362,7 +362,7 @@ fn base_local_and_movability<'tcx>( && !is_copy(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty); } - Some((local, deref || field || slice)) + (local, deref || field || slice) } struct LocalUseVisitor { diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index 3fda00403c611..efe3237990d43 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -1,9 +1,10 @@ -use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; -use rustc_ast::ast::{Expr, ExprKind, UnOp}; +use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::BytePos; declare_clippy_lint! { /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. @@ -42,19 +43,55 @@ impl EarlyLintPass for DerefAddrOf { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { if_chain! { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind; - if let ExprKind::AddrOf(_, _, ref addrof_target) = without_parens(deref_target).kind; + if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind; if !in_macro(addrof_target.span); then { let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - DEREF_ADDROF, - e.span, - "immediately dereferencing a reference", - "try this", - format!("{}", snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)), - applicability, - ); + let sugg = if e.span.from_expansion() { + if let Ok(macro_source) = cx.sess.source_map().span_to_snippet(e.span) { + // Remove leading whitespace from the given span + // e.g: ` $visitor` turns into `$visitor` + let trim_leading_whitespaces = |span| { + snippet_opt(cx, span).and_then(|snip| { + #[allow(clippy::cast_possible_truncation)] + snip.find(|c: char| !c.is_whitespace()).map(|pos| { + span.lo() + BytePos(pos as u32) + }) + }).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) + }; + + let mut generate_snippet = |pattern: &str| { + #[allow(clippy::cast_possible_truncation)] + macro_source.rfind(pattern).map(|pattern_pos| { + let rpos = pattern_pos + pattern.len(); + let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); + let span = trim_leading_whitespaces(span_after_ref); + snippet_with_applicability(cx, span, "_", &mut applicability) + }) + }; + + if *mutability == Mutability::Mut { + generate_snippet("mut") + } else { + generate_snippet("&") + } + } else { + Some(snippet_with_applicability(cx, e.span, "_", &mut applicability)) + } + } else { + Some(snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)) + }; + if let Some(sugg) = sugg { + span_lint_and_sugg( + cx, + DEREF_ADDROF, + e.span, + "immediately dereferencing a reference", + "try this", + sugg.to_string(), + applicability, + ); + } } } } diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index 95594e38c9ec1..d06ab14348237 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -11,7 +11,7 @@ use std::convert::TryFrom; declare_clippy_lint! { /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation - /// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct + /// (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct /// regex syntax. /// /// **Why is this bad?** This will lead to a runtime panic. @@ -29,7 +29,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for trivial [regex](https://crates.io/crates/regex) - /// creation (with `Regex::new`, `RegexBuilder::new` or `RegexSet::new`). + /// creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`). /// /// **Why is this bad?** Matching the regex can likely be replaced by `==` or /// `str::starts_with`, `str::ends_with` or `std::contains` or other `str` diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 0dd2da949c4c3..ede37624f71a4 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -1,5 +1,5 @@ use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -9,7 +9,10 @@ use rustc_span::sym; use if_chain::if_chain; use crate::utils::SpanlessEq; -use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg}; +use crate::utils::{ + get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint, + span_lint_and_sugg, +}; declare_clippy_lint! { /// **What it does:** Checks for string appends of the form `x = x + y` (without @@ -174,16 +177,75 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { } } +declare_clippy_lint! { + /// **What it does:** Check if the string is transformed to byte array and casted back to string. + /// + /// **Why is this bad?** It's unnecessary, the string can be used directly. + /// + /// **Known problems:** None + /// + /// **Example:** + /// ```rust + /// let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); + /// ``` + /// could be written as + /// ```rust + /// let _ = &"Hello World!"[6..11]; + /// ``` + pub STRING_FROM_UTF8_AS_BYTES, + complexity, + "casting string slices to byte slices and back" +} + // Max length a b"foo" string can take const MAX_LENGTH_BYTE_STRING_LIT: usize = 32; -declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]); +declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]); impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use crate::utils::{snippet, snippet_with_applicability}; use rustc_ast::LitKind; + if_chain! { + // Find std::str::converts::from_utf8 + if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8); + + // Find string::as_bytes + if let ExprKind::AddrOf(BorrowKind::Ref, _, ref args) = args[0].kind; + if let ExprKind::Index(ref left, ref right) = args.kind; + let (method_names, expressions, _) = method_calls(left, 1); + if method_names.len() == 1; + if expressions.len() == 1; + if expressions[0].len() == 1; + if method_names[0] == sym!(as_bytes); + + // Check for slicer + if let ExprKind::Struct(ref path, _, _) = right.kind; + if let QPath::LangItem(LangItem::Range, _) = path; + + then { + let mut applicability = Applicability::MachineApplicable; + let string_expression = &expressions[0][0]; + + let snippet_app = snippet_with_applicability( + cx, + string_expression.span, "..", + &mut applicability, + ); + + span_lint_and_sugg( + cx, + STRING_FROM_UTF8_AS_BYTES, + e.span, + "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", + "try", + format!("Some(&{}[{}])", snippet_app, snippet(cx, right.span, "..")), + applicability + ) + } + } + if_chain! { if let ExprKind::MethodCall(path, _, args, _) = &e.kind; if path.ident.name == sym!(as_bytes); diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs index 6f6b6999bf0a9..73e3a04aec987 100644 --- a/src/tools/clippy/clippy_lints/src/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/try_err.rs @@ -1,6 +1,6 @@ use crate::utils::{ - is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite, - span_lint_and_sugg, + differing_macro_contexts, in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, + snippet_with_macro_callsite, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -92,8 +92,11 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { }; let expr_err_ty = cx.typeck_results().expr_ty(err_arg); + let differing_contexts = differing_macro_contexts(expr.span, err_arg.span); - let origin_snippet = if err_arg.span.from_expansion() { + let origin_snippet = if in_macro(expr.span) && in_macro(err_arg.span) && differing_contexts { + snippet(cx, err_arg.span.ctxt().outer_expn_data().call_site, "_") + } else if err_arg.span.from_expansion() && !in_macro(expr.span) { snippet_with_macro_callsite(cx, err_arg.span, "_") } else { snippet(cx, err_arg.span, "_") diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs index c7d82da3b8ba4..f0e10e374e118 100644 --- a/src/tools/clippy/clippy_lints/src/types.rs +++ b/src/tools/clippy/clippy_lints/src/types.rs @@ -553,7 +553,7 @@ impl Types { hir_ty.span, "`Vec` is already on the heap, the boxing is unnecessary.", "try", - format!("Vec<{}>", ty_ty), + format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")), Applicability::MachineApplicable, ); return; // don't recurse into the type diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index ade5fff5ffc06..2501635e7ef66 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust - /// let mut twins = vec!((1,1), (2,2)); + /// let mut twins = vec!((1, 1), (2, 2)); /// twins.sort_by_key(|x| { x.1; }); /// ``` pub UNIT_RETURN_EXPECTING_ORD, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs new file mode 100644 index 0000000000000..25ecc7a82f18b --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -0,0 +1,143 @@ +use crate::utils::{ + in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, + visitors::find_all_ret_expressions, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Node}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for private functions that only return `Ok` or `Some`. + /// + /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned. + /// + /// **Known problems:** Since this lint changes function type signature, you may need to + /// adjust some code at callee side. + /// + /// **Example:** + /// + /// ```rust + /// fn get_cool_number(a: bool, b: bool) -> Option { + /// if a && b { + /// return Some(50); + /// } + /// if a { + /// Some(0) + /// } else { + /// Some(10) + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn get_cool_number(a: bool, b: bool) -> i32 { + /// if a && b { + /// return 50; + /// } + /// if a { + /// 0 + /// } else { + /// 10 + /// } + /// } + /// ``` + pub UNNECESSARY_WRAPS, + complexity, + "functions that only return `Ok` or `Some`" +} + +declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]); + +impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + fn_kind: FnKind<'tcx>, + fn_decl: &FnDecl<'tcx>, + body: &Body<'tcx>, + span: Span, + hir_id: HirId, + ) { + match fn_kind { + FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => { + if visibility.node.is_pub() { + return; + } + }, + FnKind::Closure(..) => return, + _ => (), + } + + if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { + if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), ..} | ItemKind::Trait(..)) { + return; + } + } + + let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { + ("Option", &paths::OPTION_SOME) + } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { + ("Result", &paths::RESULT_OK) + } else { + return; + }; + + let mut suggs = Vec::new(); + let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| { + if_chain! { + if !in_macro(ret_expr.span); + if let ExprKind::Call(ref func, ref args) = ret_expr.kind; + if let ExprKind::Path(ref qpath) = func.kind; + if match_qpath(qpath, path); + if args.len() == 1; + then { + suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string())); + true + } else { + false + } + } + }); + + if can_sugg && !suggs.is_empty() { + span_lint_and_then( + cx, + UNNECESSARY_WRAPS, + span, + format!( + "this function's return value is unnecessarily wrapped by `{}`", + return_type + ) + .as_str(), + |diag| { + let inner_ty = return_ty(cx, hir_id) + .walk() + .skip(1) // skip `std::option::Option` or `std::result::Result` + .take(1) // take the first outermost inner type + .filter_map(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()), + _ => None, + }); + inner_ty.for_each(|inner_ty| { + diag.span_suggestion( + fn_decl.output.span(), + format!("remove `{}` from the return type...", return_type).as_str(), + inner_ty, + Applicability::MaybeIncorrect, + ); + }); + diag.multipart_suggestion( + "...and change the returning expressions", + suggs, + Applicability::MachineApplicable, + ); + }, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index b1339c3d6395d..f61fd2ecd735d 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -7,7 +7,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; -use crate::utils::span_lint_and_sugg; +use crate::utils::{position_before_rarrow, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for unit (`()`) expressions that can be removed. @@ -120,26 +120,13 @@ fn is_unit_expr(expr: &ast::Expr) -> bool { fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) { - fn_source - .rfind("->") - .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { - let mut rpos = rpos; - let chars: Vec = fn_source.chars().collect(); - while rpos > 1 { - if let Some(c) = chars.get(rpos - 1) { - if c.is_whitespace() { - rpos -= 1; - continue; - } - } - break; - } - ( - #[allow(clippy::cast_possible_truncation)] - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable, - ) - }) + position_before_rarrow(fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + ( + #[allow(clippy::cast_possible_truncation)] + ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + Applicability::MachineApplicable, + ) + }) } else { (ty.span, Applicability::MaybeIncorrect) }; diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index c6194b0c6de3e..efa9c3fab4ab8 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -12,8 +12,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls - /// that useless converts to the same type as caller. + /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls + /// which uselessly convert to the same type. /// /// **Why is this bad?** Redundant code. /// @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` pub USELESS_CONVERSION, complexity, - "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type" + "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type" } #[derive(Default)] diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs index 9050b9b2d9ab8..fcf7a4b1367e3 100644 --- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -110,8 +110,7 @@ pub fn eq_expr_opt(l: &Option>, r: &Option>) -> bool { pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool { match (l, r) { (StructRest::Base(lb), StructRest::Base(rb)) => eq_expr(lb, rb), - (StructRest::Rest(_), StructRest::Rest(_)) => true, - (StructRest::None, StructRest::None) => true, + (StructRest::Rest(_), StructRest::Rest(_)) | (StructRest::None, StructRest::None) => true, _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs b/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs index 4ceea13df377d..8fe5ddee1ca8d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs @@ -9,7 +9,7 @@ //! - or-fun-call //! - option-if-let-else -use crate::utils::is_ctor_or_promotable_const_function; +use crate::utils::{is_ctor_or_promotable_const_function, is_type_diagnostic_item, match_type, paths}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -96,6 +96,11 @@ fn identify_some_potentially_expensive_patterns<'tcx>(cx: &LateContext<'tcx>, ex let call_found = match &expr.kind { // ignore enum and struct constructors ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr), + ExprKind::Index(obj, _) => { + let ty = self.cx.typeck_results().expr_ty(obj); + is_type_diagnostic_item(self.cx, ty, sym!(hashmap_type)) + || match_type(self.cx, ty, &paths::BTREEMAP) + }, ExprKind::MethodCall(..) => true, _ => false, }; diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 270fdc9bf462f..e9c71e23a670b 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -21,6 +21,7 @@ pub mod ptr; pub mod qualify_min_const_fn; pub mod sugg; pub mod usage; +pub mod visitors; pub use self::attrs::*; pub use self::diagnostics::*; @@ -364,6 +365,9 @@ pub fn implements_trait<'tcx>( return false; } let ty = cx.tcx.erase_regions(ty); + if ty.has_escaping_bound_vars() { + return false; + } let ty_params = cx.tcx.mk_substs(ty_params.iter()); cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) } @@ -468,6 +472,13 @@ pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool { .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id()) } +/// Returns `true` if the expression is in the program's `#[panic_handler]`. +pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { + let parent = cx.tcx.hir().get_parent_item(e.hir_id); + let def_id = cx.tcx.hir().local_def_id(parent).to_def_id(); + Some(def_id) == cx.tcx.lang_items().panic_impl() +} + /// Gets the name of the item the expression is in, if available. pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id); @@ -659,6 +670,35 @@ pub fn indent_of(cx: &T, span: Span) -> Option { snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) } +/// Returns the positon just before rarrow +/// +/// ```rust,ignore +/// fn into(self) -> () {} +/// ^ +/// // in case of unformatted code +/// fn into2(self)-> () {} +/// ^ +/// fn into3(self) -> () {} +/// ^ +/// ``` +#[allow(clippy::needless_pass_by_value)] +pub fn position_before_rarrow(s: String) -> Option { + s.rfind("->").map(|rpos| { + let mut rpos = rpos; + let chars: Vec = s.chars().collect(); + while rpos > 1 { + if let Some(c) = chars.get(rpos - 1) { + if c.is_whitespace() { + rpos -= 1; + continue; + } + } + break; + } + rpos + }) +} + /// Extends the span to the beginning of the spans line, incl. whitespaces. /// /// ```rust,ignore diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs index 8f5fbfd9f846a..137f5d18b6649 100644 --- a/src/tools/clippy/clippy_lints/src/utils/paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs @@ -126,6 +126,7 @@ pub const STRING: [&str; 3] = ["alloc", "string", "String"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "", "ends_with"]; +pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"]; pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "", "starts_with"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; diff --git a/src/tools/clippy/clippy_lints/src/utils/visitors.rs b/src/tools/clippy/clippy_lints/src/utils/visitors.rs new file mode 100644 index 0000000000000..b0837b6c43e76 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/utils/visitors.rs @@ -0,0 +1,125 @@ +use rustc_hir as hir; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; + +/// returns `true` if expr contains match expr desugared from try +fn contains_try(expr: &hir::Expr<'_>) -> bool { + struct TryFinder { + found: bool, + } + + impl<'hir> intravisit::Visitor<'hir> for TryFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { + if self.found { + return; + } + match expr.kind { + hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true, + _ => intravisit::walk_expr(self, expr), + } + } + } + + let mut visitor = TryFinder { found: false }; + visitor.visit_expr(expr); + visitor.found +} + +pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool +where + F: FnMut(&'hir hir::Expr<'hir>) -> bool, +{ + struct RetFinder { + in_stmt: bool, + failed: bool, + cb: F, + } + + struct WithStmtGuarg<'a, F> { + val: &'a mut RetFinder, + prev_in_stmt: bool, + } + + impl RetFinder { + fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { + let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); + WithStmtGuarg { + val: self, + prev_in_stmt, + } + } + } + + impl std::ops::Deref for WithStmtGuarg<'_, F> { + type Target = RetFinder; + + fn deref(&self) -> &Self::Target { + self.val + } + } + + impl std::ops::DerefMut for WithStmtGuarg<'_, F> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.val + } + } + + impl Drop for WithStmtGuarg<'_, F> { + fn drop(&mut self) { + self.val.in_stmt = self.prev_in_stmt; + } + } + + impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { + intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) + } + + fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { + if self.failed { + return; + } + if self.in_stmt { + match expr.kind { + hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), + _ => intravisit::walk_expr(self, expr), + } + } else { + match expr.kind { + hir::ExprKind::Match(cond, arms, _) => { + self.inside_stmt(true).visit_expr(cond); + for arm in arms { + self.visit_expr(arm.body); + } + }, + hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), + hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), + _ => self.failed |= !(self.cb)(expr), + } + } + } + } + + !contains_try(expr) && { + let mut ret_finder = RetFinder { + in_stmt: false, + failed: false, + cb: callback, + }; + ret_finder.visit_expr(expr); + !ret_finder.failed + } +} diff --git a/src/tools/clippy/doc/changelog_update.md b/src/tools/clippy/doc/changelog_update.md index 4972646495730..115848c48044c 100644 --- a/src/tools/clippy/doc/changelog_update.md +++ b/src/tools/clippy/doc/changelog_update.md @@ -29,8 +29,11 @@ bullet points might be helpful: * When writing the release notes for the **upcoming beta release**, you need to check out the Clippy commit of the current Rust `master`. [Link][rust_master_tools] * When writing the (forgotten) release notes for a **past stable release**, you - need to select the Rust release tag from the dropdown and then check the - commit of the Clippy directory: + need to check out the Rust release tag of the stable release. + [Link][rust_stable_tools] + +Usually you want to wirte the changelog of the **upcoming stable release**. Make +sure though, that `beta` was already branched in the Rust repository. To find the commit hash, issue the following command when in a `rust-lang/rust` checkout: ``` @@ -71,6 +74,19 @@ The order should roughly be: 7. Documentation improvements 8. Others +As section headers, we use: + +``` +### New Lints +### Moves and Deprecations +### Enhancements +### False Positive Fixes +### Suggestion Fixes/Improvements +### ICE Fixes +### Documentation Improvements +### Others +``` + Please also be sure to update the Beta/Unreleased sections at the top with the relevant commit ranges. @@ -78,3 +94,4 @@ relevant commit ranges. [forge]: https://forge.rust-lang.org/ [rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy [rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy +[rust_stable_tools]: https://github.com/rust-lang/rust/releases diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs index 702f9d86de62d..1d906d20ad475 100644 --- a/src/tools/clippy/src/lintlist/mod.rs +++ b/src/tools/clippy/src/lintlist/mod.rs @@ -62,14 +62,14 @@ vec![ }, Lint { name: "await_holding_lock", - group: "correctness", + group: "pedantic", desc: "Inside an async function, holding a MutexGuard while calling await", deprecation: None, module: "await_holding_invalid", }, Lint { name: "await_holding_refcell_ref", - group: "correctness", + group: "pedantic", desc: "Inside an async function, holding a RefCell ref while calling await", deprecation: None, module: "await_holding_invalid", @@ -1117,6 +1117,13 @@ vec![ deprecation: None, module: "returns", }, + Lint { + name: "let_underscore_drop", + group: "pedantic", + desc: "non-binding let on a type that implements `Drop`", + deprecation: None, + module: "let_underscore", + }, Lint { name: "let_underscore_lock", group: "correctness", @@ -1831,13 +1838,6 @@ vec![ deprecation: None, module: "panic_in_result_fn", }, - Lint { - name: "panic_params", - group: "style", - desc: "missing parameters in `panic!` calls", - deprecation: None, - module: "panic_unimplemented", - }, Lint { name: "panicking_unwrap", group: "correctness", @@ -2114,7 +2114,7 @@ vec![ Lint { name: "search_is_some", group: "complexity", - desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`", + desc: "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`", deprecation: None, module: "methods", }, @@ -2258,6 +2258,13 @@ vec![ deprecation: None, module: "methods", }, + Lint { + name: "string_from_utf8_as_bytes", + group: "complexity", + desc: "casting string slices to byte slices and back", + deprecation: None, + module: "strings", + }, Lint { name: "string_lit_as_bytes", group: "nursery", @@ -2594,6 +2601,13 @@ vec![ deprecation: None, module: "unwrap", }, + Lint { + name: "unnecessary_wraps", + group: "complexity", + desc: "functions that only return `Ok` or `Some`", + deprecation: None, + module: "unnecessary_wraps", + }, Lint { name: "unneeded_field_pattern", group: "restriction", @@ -2737,7 +2751,7 @@ vec![ Lint { name: "useless_conversion", group: "complexity", - desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type", + desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type", deprecation: None, module: "useless_conversion", }, diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs new file mode 100644 index 0000000000000..2289f7875f04c --- /dev/null +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs @@ -0,0 +1,16 @@ +// this file solely exists to test constants defined in foreign crates. +// As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure. + +#![allow(clippy::declare_interior_mutable_const)] + +use std::sync::atomic::AtomicUsize; + +enum Private { + ToBeUnfrozen(T), + Frozen(usize), +} + +pub struct Wrapper(Private); + +pub const WRAPPED_PRIVATE_UNFROZEN_VARIANT: Wrapper = Wrapper(Private::ToBeUnfrozen(AtomicUsize::new(6))); +pub const WRAPPED_PRIVATE_FROZEN_VARIANT: Wrapper = Wrapper(Private::Frozen(7)); diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs new file mode 100644 index 0000000000000..5027db4456179 --- /dev/null +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs @@ -0,0 +1,101 @@ +// aux-build:helper.rs + +#![warn(clippy::borrow_interior_mutable_const)] +#![allow(clippy::declare_interior_mutable_const)] + +// this file (mostly) replicates its `declare` counterpart. Please see it for more discussions. + +extern crate helper; + +use std::cell::Cell; +use std::sync::atomic::AtomicUsize; + +enum OptionalCell { + Unfrozen(Cell), + Frozen, +} + +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); +const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + +fn borrow_optional_cell() { + let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &FROZEN_VARIANT; +} + +trait AssocConsts { + const TO_BE_UNFROZEN_VARIANT: OptionalCell; + const TO_BE_FROZEN_VARIANT: OptionalCell; + + const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + + fn function() { + // This is the "suboptimal behavior" mentioned in `is_value_unfrozen` + // caused by a similar reason to unfrozen types without any default values + // get linted even if it has frozen variants'. + let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable + + // The lint ignores default values because an impl of this trait can set + // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`. + let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable + } +} + +impl AssocConsts for u64 { + const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + + fn function() { + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &::TO_BE_FROZEN_VARIANT; + let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; + } +} + +trait AssocTypes { + type ToBeUnfrozen; + + const TO_BE_UNFROZEN_VARIANT: Option; + const TO_BE_FROZEN_VARIANT: Option; + + // there's no need to test here because it's the exactly same as `trait::AssocTypes` + fn function(); +} + +impl AssocTypes for u64 { + type ToBeUnfrozen = AtomicUsize; + + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + const TO_BE_FROZEN_VARIANT: Option = None; + + fn function() { + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &::TO_BE_FROZEN_VARIANT; + } +} + +enum BothOfCellAndGeneric { + Unfrozen(Cell<*const T>), + Generic(*const T), + Frozen(usize), +} + +impl BothOfCellAndGeneric { + const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); + + fn function() { + let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability + let _ = &Self::FROZEN_VARIANT; + } +} + +fn main() { + // constants defined in foreign crates + let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT; +} diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr new file mode 100644 index 0000000000000..654a1ee7df659 --- /dev/null +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr @@ -0,0 +1,75 @@ +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:22:14 + | +LL | let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:37:18 + | +LL | let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:41:18 + | +LL | let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:50:18 + | +LL | let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:52:18 + | +LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:74:18 + | +LL | let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:91:18 + | +LL | let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:92:18 + | +LL | let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:99:14 + | +LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs similarity index 81% rename from src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs rename to src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs index 9fcc9ece49bb7..ea25729d11d4d 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs @@ -19,33 +19,7 @@ const NO_ANN: &dyn Display = &70; static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); const ONCE_INIT: Once = Once::new(); -trait Trait { - type AssocType; - - const ATOMIC: AtomicUsize; - const INPUT: T; - const ASSOC: Self::AssocType; - - fn function() { - let _ = &Self::INPUT; - let _ = &Self::ASSOC; - } -} - -impl Trait for u64 { - type AssocType = AtomicUsize; - - const ATOMIC: AtomicUsize = AtomicUsize::new(9); - const INPUT: u32 = 10; - const ASSOC: Self::AssocType = AtomicUsize::new(11); - - fn function() { - let _ = &Self::INPUT; - let _ = &Self::ASSOC; //~ ERROR interior mutability - } -} - -// This is just a pointer that can be safely dereferended, +// This is just a pointer that can be safely dereferenced, // it's semantically the same as `&'static T`; // but it isn't allowed to make a static reference from an arbitrary integer value at the moment. // For more information, please see the issue #5918. @@ -100,7 +74,7 @@ fn main() { let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability - let _ = &*ATOMIC_TUPLE.1; //~ ERROR interior mutability + let _ = &*ATOMIC_TUPLE.1; let _ = &ATOMIC_TUPLE.2; let _ = (&&&&ATOMIC_TUPLE).0; let _ = (&&&&ATOMIC_TUPLE).2; @@ -124,9 +98,6 @@ fn main() { assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3); assert!(STATIC_TUPLE.1.is_empty()); - u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability - assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability - assert_eq!(NO_ANN.to_string(), "70"); // should never lint this. let _ = &CELL_REF.0; diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr similarity index 68% rename from src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr rename to src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr index ed726a6b46e64..9a908cf30e945 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr @@ -1,22 +1,14 @@ error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:44:18 - | -LL | let _ = &Self::ASSOC; //~ ERROR interior mutability - | ^^^^^^^^^^^ - | - = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:80:5 + --> $DIR/others.rs:54:5 | LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ | + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:81:16 + --> $DIR/others.rs:55:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -24,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:84:22 + --> $DIR/others.rs:58:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -32,7 +24,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:85:25 + --> $DIR/others.rs:59:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -40,7 +32,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:86:27 + --> $DIR/others.rs:60:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -48,7 +40,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:87:26 + --> $DIR/others.rs:61:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -56,7 +48,7 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:98:14 + --> $DIR/others.rs:72:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -64,7 +56,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:99:14 + --> $DIR/others.rs:73:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -72,7 +64,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:100:19 + --> $DIR/others.rs:74:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -80,7 +72,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:101:14 + --> $DIR/others.rs:75:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -88,7 +80,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:102:13 + --> $DIR/others.rs:76:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -96,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:108:13 + --> $DIR/others.rs:82:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -104,7 +96,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:113:5 + --> $DIR/others.rs:87:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -112,28 +104,12 @@ LL | CELL.set(2); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:114:16 + --> $DIR/others.rs:88:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ | = help: assign this const to a local or static variable, and use the variable here -error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:127:5 - | -LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability - | ^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:128:16 - | -LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability - | ^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: aborting due to 17 previous errors +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs new file mode 100644 index 0000000000000..06b5d62e8f9a8 --- /dev/null +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs @@ -0,0 +1,202 @@ +#![warn(clippy::borrow_interior_mutable_const)] +#![allow(clippy::declare_interior_mutable_const)] + +// this file replicates its `declare` counterpart. Please see it for more discussions. + +use std::borrow::Cow; +use std::cell::Cell; +use std::sync::atomic::{AtomicUsize, Ordering}; + +trait ConcreteTypes { + const ATOMIC: AtomicUsize; + const STRING: String; + + fn function() { + let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::STRING; + } +} + +impl ConcreteTypes for u64 { + const ATOMIC: AtomicUsize = AtomicUsize::new(9); + const STRING: String = String::new(); + + fn function() { + // Lint this again since implementers can choose not to borrow it. + let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::STRING; + } +} + +// a helper trait used below +trait ConstDefault { + const DEFAULT: Self; +} + +trait GenericTypes { + const TO_REMAIN_GENERIC: T; + const TO_BE_CONCRETE: U; + + fn function() { + let _ = &Self::TO_REMAIN_GENERIC; + } +} + +impl GenericTypes for Vec { + const TO_REMAIN_GENERIC: T = T::DEFAULT; + const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); + + fn function() { + let _ = &Self::TO_REMAIN_GENERIC; + let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable + } +} + +// a helper type used below +pub struct Wrapper(T); + +trait AssocTypes { + type ToBeFrozen; + type ToBeUnfrozen; + type ToBeGenericParam; + + const TO_BE_FROZEN: Self::ToBeFrozen; + const TO_BE_UNFROZEN: Self::ToBeUnfrozen; + const WRAPPED_TO_BE_UNFROZEN: Wrapper; + const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper; + + fn function() { + let _ = &Self::TO_BE_FROZEN; + let _ = &Self::WRAPPED_TO_BE_UNFROZEN; + } +} + +impl AssocTypes for Vec { + type ToBeFrozen = u16; + type ToBeUnfrozen = AtomicUsize; + type ToBeGenericParam = T; + + const TO_BE_FROZEN: Self::ToBeFrozen = 12; + const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); + const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); + const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); + + fn function() { + let _ = &Self::TO_BE_FROZEN; + let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable + let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable + let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM; + } +} + +// a helper trait used below +trait AssocTypesHelper { + type NotToBeBounded; + type ToBeBounded; + + const NOT_TO_BE_BOUNDED: Self::NotToBeBounded; +} + +trait AssocTypesFromGenericParam +where + T: AssocTypesHelper, +{ + const NOT_BOUNDED: T::NotToBeBounded; + const BOUNDED: T::ToBeBounded; + + fn function() { + let _ = &Self::NOT_BOUNDED; + let _ = &Self::BOUNDED; //~ ERROR interior mutable + } +} + +impl AssocTypesFromGenericParam for Vec +where + T: AssocTypesHelper, +{ + const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; + const BOUNDED: T::ToBeBounded = AtomicUsize::new(15); + + fn function() { + let _ = &Self::NOT_BOUNDED; + let _ = &Self::BOUNDED; //~ ERROR interior mutable + } +} + +trait SelfType: Sized { + const SELF: Self; + const WRAPPED_SELF: Option; + + fn function() { + let _ = &Self::SELF; + let _ = &Self::WRAPPED_SELF; + } +} + +impl SelfType for u64 { + const SELF: Self = 16; + const WRAPPED_SELF: Option = Some(20); + + fn function() { + let _ = &Self::SELF; + let _ = &Self::WRAPPED_SELF; + } +} + +impl SelfType for AtomicUsize { + const SELF: Self = AtomicUsize::new(17); + const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); + + fn function() { + let _ = &Self::SELF; //~ ERROR interior mutable + let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable + } +} + +trait BothOfCellAndGeneric { + const DIRECT: Cell; + const INDIRECT: Cell<*const T>; + + fn function() { + let _ = &Self::DIRECT; + let _ = &Self::INDIRECT; //~ ERROR interior mutable + } +} + +impl BothOfCellAndGeneric for Vec { + const DIRECT: Cell = Cell::new(T::DEFAULT); + const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); + + fn function() { + let _ = &Self::DIRECT; + let _ = &Self::INDIRECT; //~ ERROR interior mutable + } +} + +struct Local(T); + +impl Local +where + T: ConstDefault + AssocTypesHelper, +{ + const ATOMIC: AtomicUsize = AtomicUsize::new(18); + const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); + + const GENERIC_TYPE: T = T::DEFAULT; + + const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; + const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); + + fn function() { + let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::COW; + let _ = &Self::GENERIC_TYPE; + let _ = &Self::ASSOC_TYPE; + let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable + } +} + +fn main() { + u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability + assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability +} diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr new file mode 100644 index 0000000000000..8f26403abd3ee --- /dev/null +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -0,0 +1,123 @@ +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:15:18 + | +LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable + | ^^^^^^^^^^^^ + | + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:26:18 + | +LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:51:18 + | +LL | let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:86:18 + | +LL | let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:87:18 + | +LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:109:18 + | +LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable + | ^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:122:18 + | +LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable + | ^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:151:18 + | +LL | let _ = &Self::SELF; //~ ERROR interior mutable + | ^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:152:18 + | +LL | let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:162:18 + | +LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:172:18 + | +LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:191:18 + | +LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:195:18 + | +LL | let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:200:5 + | +LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability + | ^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:201:16 + | +LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability + | ^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: aborting due to 15 previous errors + diff --git a/src/tools/clippy/tests/ui/crashes/ice-360.stderr b/src/tools/clippy/tests/ui/crashes/ice-360.stderr index bb03ce4035533..0eb7bb12b3546 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-360.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-360.stderr @@ -19,7 +19,7 @@ LL | loop {} | ^^^^^^^ | = note: `-D clippy::empty-loop` implied by `-D warnings` - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/crashes/ice-6332.rs b/src/tools/clippy/tests/ui/crashes/ice-6332.rs new file mode 100644 index 0000000000000..9dc92aa500b2f --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-6332.rs @@ -0,0 +1,11 @@ +fn cmark_check() { + let mut link_err = false; + macro_rules! cmark_error { + ($bad:expr) => { + *$bad = true; + }; + } + cmark_error!(&mut link_err); +} + +pub fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/implements-trait.rs b/src/tools/clippy/tests/ui/crashes/implements-trait.rs new file mode 100644 index 0000000000000..4502b0147a83e --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/implements-trait.rs @@ -0,0 +1,5 @@ +#[allow(clippy::needless_borrowed_reference)] +fn main() { + let mut v = Vec::::new(); + let _ = v.iter_mut().filter(|&ref a| a.is_empty()); +} diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs new file mode 100644 index 0000000000000..f44518694b89c --- /dev/null +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs @@ -0,0 +1,123 @@ +#![warn(clippy::declare_interior_mutable_const)] + +use std::cell::Cell; +use std::sync::atomic::AtomicUsize; + +enum OptionalCell { + Unfrozen(Cell), + Frozen, +} + +// a constant with enums should be linted only when the used variant is unfrozen (#3962). +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable +const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + +const fn unfrozen_variant() -> OptionalCell { + OptionalCell::Unfrozen(Cell::new(false)) +} + +const fn frozen_variant() -> OptionalCell { + OptionalCell::Frozen +} + +const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable +const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant(); + +enum NestedInnermost { + Unfrozen(AtomicUsize), + Frozen, +} + +struct NestedInner { + inner: NestedInnermost, +} + +enum NestedOuter { + NestedInner(NestedInner), + NotNested(usize), +} + +struct NestedOutermost { + outer: NestedOuter, +} + +// a constant with enums should be linted according to its value, no matter how structs involve. +const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { + outer: NestedOuter::NestedInner(NestedInner { + inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), + }), +}; //~ ERROR interior mutable +const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost { + outer: NestedOuter::NestedInner(NestedInner { + inner: NestedInnermost::Frozen, + }), +}; + +trait AssocConsts { + // When there's no default value, lint it only according to its type. + // Further details are on the corresponding code (`NonCopyConst::check_trait_item`). + const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + + // Lint default values accordingly. + const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable + const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; +} + +// The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it +// has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'. +impl AssocConsts for u64 { + const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + + // even if this sets an unfrozen variant, the lint ignores it. + const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); +} + +// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters +// here are values; and I think substituted generics at definitions won't appear in MIR. +trait AssocTypes { + type ToBeUnfrozen; + + const TO_BE_UNFROZEN_VARIANT: Option; + const TO_BE_FROZEN_VARIANT: Option; +} + +impl AssocTypes for u64 { + type ToBeUnfrozen = AtomicUsize; + + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + const TO_BE_FROZEN_VARIANT: Option = None; +} + +// Use raw pointers since direct generics have a false negative at the type level. +enum BothOfCellAndGeneric { + Unfrozen(Cell<*const T>), + Generic(*const T), + Frozen(usize), +} + +impl BothOfCellAndGeneric { + const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + + // This is a false positive. The argument about this is on `is_value_unfrozen_raw` + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + + const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); + + // This is what is likely to be a false negative when one tries to fix + // the `GENERIC_VARIANT` false positive. + const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable +} + +// associated types here is basically the same as the one above. +trait BothOfCellAndGenericWithAssocType { + type AssocType; + + const UNFROZEN_VARIANT: BothOfCellAndGeneric = + BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr new file mode 100644 index 0000000000000..84198d5461578 --- /dev/null +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr @@ -0,0 +1,89 @@ +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:12:1 + | +LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + | + = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:23:1 + | +LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:45:1 + | +LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { + | ^---- + | | + | _make this a static item (maybe with lazy_static) + | | +LL | | outer: NestedOuter::NestedInner(NestedInner { +LL | | inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), +LL | | }), +LL | | }; //~ ERROR interior mutable + | |__^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:59:5 + | +LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:60:5 + | +LL | const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:63:5 + | +LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:89:5 + | +LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:101:5 + | +LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mut... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:104:5 + | +LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:110:5 + | +LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:117:5 + | +LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric = +LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + | |____________________________________________________________________^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:119:5 + | +LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mu... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs new file mode 100644 index 0000000000000..48c5e9537d6d0 --- /dev/null +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs @@ -0,0 +1,34 @@ +#![warn(clippy::declare_interior_mutable_const)] + +use std::borrow::Cow; +use std::cell::Cell; +use std::fmt::Display; +use std::sync::atomic::AtomicUsize; +use std::sync::Once; + +const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable +const CELL: Cell = Cell::new(6); //~ ERROR interior mutable +const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); +//~^ ERROR interior mutable + +macro_rules! declare_const { + ($name:ident: $ty:ty = $e:expr) => { + const $name: $ty = $e; + }; +} +declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable + +// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. + +const INTEGER: u8 = 8; +const STRING: String = String::new(); +const STR: &str = "012345"; +const COW: Cow = Cow::Borrowed("abcdef"); +//^ note: a const item of Cow is used in the `postgres` package. + +const NO_ANN: &dyn Display = &70; + +static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); +//^ there should be no lints on this line + +fn main() {} diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr new file mode 100644 index 0000000000000..6153c96edc4f4 --- /dev/null +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr @@ -0,0 +1,39 @@ +error: a `const` item should never be interior mutable + --> $DIR/others.rs:9:1 + | +LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + | + = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` + +error: a `const` item should never be interior mutable + --> $DIR/others.rs:10:1 + | +LL | const CELL: Cell = Cell::new(6); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + +error: a `const` item should never be interior mutable + --> $DIR/others.rs:11:1 + | +LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + +error: a `const` item should never be interior mutable + --> $DIR/others.rs:16:9 + | +LL | const $name: $ty = $e; + | ^^^^^^^^^^^^^^^^^^^^^^ +... +LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable + | ------------------------------------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs similarity index 84% rename from src/tools/clippy/tests/ui/declare_interior_mutable_const.rs rename to src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs index 3afcdca2f04dd..535147ccc6451 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs @@ -2,37 +2,13 @@ use std::borrow::Cow; use std::cell::Cell; -use std::fmt::Display; use std::sync::atomic::AtomicUsize; -use std::sync::Once; - -const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable -const CELL: Cell = Cell::new(6); //~ ERROR interior mutable -const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); -//~^ ERROR interior mutable macro_rules! declare_const { ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; } -declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable - -// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. - -const INTEGER: u8 = 8; -const STRING: String = String::new(); -const STR: &str = "012345"; -const COW: Cow = Cow::Borrowed("abcdef"); -//^ note: a const item of Cow is used in the `postgres` package. - -const NO_ANN: &dyn Display = &70; - -static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); -//^ there should be no lints on this line - -#[allow(clippy::declare_interior_mutable_const)] -const ONCE_INIT: Once = Once::new(); // a constant whose type is a concrete type should be linted at the definition site. trait ConcreteTypes { diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr similarity index 56% rename from src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr rename to src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr index 5cb10be88d89c..bb77f39b62c1f 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr @@ -1,48 +1,13 @@ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:9:1 - | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) - | - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:10:1 - | -LL | const CELL: Cell = Cell::new(6); //~ ERROR interior mutable - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:11:1 - | -LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:16:9 - | -LL | const $name: $ty = $e; - | ^^^^^^^^^^^^^^^^^^^^^^ -... -LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable - | ------------------------------------------ in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:39:5 + --> $DIR/traits.rs:15:5 | LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:16:9 + --> $DIR/traits.rs:9:9 | LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -53,58 +18,58 @@ LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR i = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:67:5 + --> $DIR/traits.rs:43:5 | LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:92:5 + --> $DIR/traits.rs:68:5 | LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:93:5 + --> $DIR/traits.rs:69:5 | LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:112:5 + --> $DIR/traits.rs:88:5 | LL | const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:140:5 + --> $DIR/traits.rs:116:5 | LL | const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:141:5 + --> $DIR/traits.rs:117:5 | LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:149:5 + --> $DIR/traits.rs:125:5 | LL | const INDIRECT: Cell<*const T>; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:165:5 + --> $DIR/traits.rs:141:5 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:171:5 + --> $DIR/traits.rs:147:5 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs index 56755596c97fc..4cbc5630d759d 100644 --- a/src/tools/clippy/tests/ui/deprecated.rs +++ b/src/tools/clippy/tests/ui/deprecated.rs @@ -10,5 +10,6 @@ #[warn(clippy::regex_macro)] #[warn(clippy::drop_bounds)] #[warn(clippy::temporary_cstring_as_ptr)] +#[warn(clippy::panic_params)] fn main() {} diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr index 37b726fc00f1c..a348d01d734fe 100644 --- a/src/tools/clippy/tests/ui/deprecated.stderr +++ b/src/tools/clippy/tests/ui/deprecated.stderr @@ -72,11 +72,17 @@ error: lint `clippy::temporary_cstring_as_ptr` has been removed: `this lint has LL | #[warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: lint `clippy::panic_params` has been removed: `this lint has been uplifted to rustc and is now called `panic_fmt`` + --> $DIR/deprecated.rs:13:8 + | +LL | #[warn(clippy::panic_params)] + | ^^^^^^^^^^^^^^^^^^^^ + error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::str_to_string)] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/deref_addrof.fixed b/src/tools/clippy/tests/ui/deref_addrof.fixed index 9e5b51d6d5e6d..0795900558b69 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.fixed +++ b/src/tools/clippy/tests/ui/deref_addrof.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![warn(clippy::deref_addrof)] fn get_number() -> usize { 10 @@ -10,7 +11,6 @@ fn get_reference(n: &usize) -> &usize { #[allow(clippy::many_single_char_names, clippy::double_parens)] #[allow(unused_variables, unused_parens)] -#[warn(clippy::deref_addrof)] fn main() { let a = 10; let aref = &a; @@ -37,3 +37,27 @@ fn main() { let b = *aref; } + +#[rustfmt::skip] +macro_rules! m { + ($visitor: expr) => { + $visitor + }; +} + +#[rustfmt::skip] +macro_rules! m_mut { + ($visitor: expr) => { + $visitor + }; +} + +pub struct S; +impl S { + pub fn f(&self) -> &Self { + m!(self) + } + pub fn f_mut(&self) -> &Self { + m_mut!(self) + } +} diff --git a/src/tools/clippy/tests/ui/deref_addrof.rs b/src/tools/clippy/tests/ui/deref_addrof.rs index 5641a73cbc1cb..60c4318601bc8 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.rs +++ b/src/tools/clippy/tests/ui/deref_addrof.rs @@ -1,4 +1,5 @@ // run-rustfix +#![warn(clippy::deref_addrof)] fn get_number() -> usize { 10 @@ -10,7 +11,6 @@ fn get_reference(n: &usize) -> &usize { #[allow(clippy::many_single_char_names, clippy::double_parens)] #[allow(unused_variables, unused_parens)] -#[warn(clippy::deref_addrof)] fn main() { let a = 10; let aref = &a; @@ -37,3 +37,27 @@ fn main() { let b = **&aref; } + +#[rustfmt::skip] +macro_rules! m { + ($visitor: expr) => { + *& $visitor + }; +} + +#[rustfmt::skip] +macro_rules! m_mut { + ($visitor: expr) => { + *& mut $visitor + }; +} + +pub struct S; +impl S { + pub fn f(&self) -> &Self { + m!(self) + } + pub fn f_mut(&self) -> &Self { + m_mut!(self) + } +} diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr index bc51719e8a7a0..e85b30fa56eb8 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.stderr +++ b/src/tools/clippy/tests/ui/deref_addrof.stderr @@ -48,5 +48,27 @@ error: immediately dereferencing a reference LL | let b = **&aref; | ^^^^^^ help: try this: `aref` -error: aborting due to 8 previous errors +error: immediately dereferencing a reference + --> $DIR/deref_addrof.rs:44:9 + | +LL | *& $visitor + | ^^^^^^^^^^^ help: try this: `$visitor` +... +LL | m!(self) + | -------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: immediately dereferencing a reference + --> $DIR/deref_addrof.rs:51:9 + | +LL | *& mut $visitor + | ^^^^^^^^^^^^^^^ help: try this: `$visitor` +... +LL | m_mut!(self) + | ------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs index b82dc518a3ba6..6f12d36d777dc 100644 --- a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs +++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs @@ -1,4 +1,5 @@ #![warn(clippy::derive_ord_xor_partial_ord)] +#![allow(clippy::unnecessary_wraps)] use std::cmp::Ordering; diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr index 66bc4d42ce8c3..97b46a4aa8982 100644 --- a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr +++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr @@ -1,12 +1,12 @@ error: you are deriving `Ord` but have implemented `PartialOrd` explicitly - --> $DIR/derive_ord_xor_partial_ord.rs:20:10 + --> $DIR/derive_ord_xor_partial_ord.rs:21:10 | LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | = note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings` note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:23:1 + --> $DIR/derive_ord_xor_partial_ord.rs:24:1 | LL | / impl PartialOrd for DeriveOrd { LL | | fn partial_cmp(&self, other: &Self) -> Option { @@ -17,13 +17,13 @@ LL | | } = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Ord` but have implemented `PartialOrd` explicitly - --> $DIR/derive_ord_xor_partial_ord.rs:29:10 + --> $DIR/derive_ord_xor_partial_ord.rs:30:10 | LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:32:1 + --> $DIR/derive_ord_xor_partial_ord.rs:33:1 | LL | / impl PartialOrd for DeriveOrdWithExplicitTypeVariable { LL | | fn partial_cmp(&self, other: &Self) -> Option { @@ -34,7 +34,7 @@ LL | | } = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` - --> $DIR/derive_ord_xor_partial_ord.rs:41:1 + --> $DIR/derive_ord_xor_partial_ord.rs:42:1 | LL | / impl std::cmp::Ord for DerivePartialOrd { LL | | fn cmp(&self, other: &Self) -> Ordering { @@ -44,14 +44,14 @@ LL | | } | |_^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:38:10 + --> $DIR/derive_ord_xor_partial_ord.rs:39:10 | LL | #[derive(PartialOrd, PartialEq, Eq)] | ^^^^^^^^^^ = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` - --> $DIR/derive_ord_xor_partial_ord.rs:61:5 + --> $DIR/derive_ord_xor_partial_ord.rs:62:5 | LL | / impl Ord for DerivePartialOrdInUseOrd { LL | | fn cmp(&self, other: &Self) -> Ordering { @@ -61,7 +61,7 @@ LL | | } | |_____^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:58:14 + --> $DIR/derive_ord_xor_partial_ord.rs:59:14 | LL | #[derive(PartialOrd, PartialEq, Eq)] | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/doc_errors.rs b/src/tools/clippy/tests/ui/doc_errors.rs index f47b81a450ea9..c77a74a58f22c 100644 --- a/src/tools/clippy/tests/ui/doc_errors.rs +++ b/src/tools/clippy/tests/ui/doc_errors.rs @@ -1,6 +1,7 @@ // edition:2018 #![warn(clippy::missing_errors_doc)] #![allow(clippy::result_unit_err)] +#![allow(clippy::unnecessary_wraps)] use std::io; diff --git a/src/tools/clippy/tests/ui/doc_errors.stderr b/src/tools/clippy/tests/ui/doc_errors.stderr index c7b616e289708..b5a81419daee3 100644 --- a/src/tools/clippy/tests/ui/doc_errors.stderr +++ b/src/tools/clippy/tests/ui/doc_errors.stderr @@ -1,5 +1,5 @@ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:7:1 + --> $DIR/doc_errors.rs:8:1 | LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::missing-errors-doc` implied by `-D warnings` error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:11:1 + --> $DIR/doc_errors.rs:12:1 | LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -17,7 +17,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:16:1 + --> $DIR/doc_errors.rs:17:1 | LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -25,7 +25,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:21:1 + --> $DIR/doc_errors.rs:22:1 | LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -33,7 +33,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:51:5 + --> $DIR/doc_errors.rs:52:5 | LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -41,7 +41,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:56:5 + --> $DIR/doc_errors.rs:57:5 | LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -49,7 +49,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:85:5 + --> $DIR/doc_errors.rs:86:5 | LL | fn trait_method_missing_errors_header() -> Result<(), ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/drop_ref.rs b/src/tools/clippy/tests/ui/drop_ref.rs index 6b5bcdaa78e27..e1a15c609fd23 100644 --- a/src/tools/clippy/tests/ui/drop_ref.rs +++ b/src/tools/clippy/tests/ui/drop_ref.rs @@ -1,6 +1,7 @@ #![warn(clippy::drop_ref)] #![allow(clippy::toplevel_ref_arg)] #![allow(clippy::map_err_ignore)] +#![allow(clippy::unnecessary_wraps)] use std::mem::drop; diff --git a/src/tools/clippy/tests/ui/drop_ref.stderr b/src/tools/clippy/tests/ui/drop_ref.stderr index 7974bf56d44cf..10087cb4820a7 100644 --- a/src/tools/clippy/tests/ui/drop_ref.stderr +++ b/src/tools/clippy/tests/ui/drop_ref.stderr @@ -1,108 +1,108 @@ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:10:5 + --> $DIR/drop_ref.rs:11:5 | LL | drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::drop-ref` implied by `-D warnings` note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:10:10 + --> $DIR/drop_ref.rs:11:10 | LL | drop(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:13:5 + --> $DIR/drop_ref.rs:14:5 | LL | drop(&owned1); | ^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:13:10 + --> $DIR/drop_ref.rs:14:10 | LL | drop(&owned1); | ^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:14:5 + --> $DIR/drop_ref.rs:15:5 | LL | drop(&&owned1); | ^^^^^^^^^^^^^^ | note: argument has type `&&SomeStruct` - --> $DIR/drop_ref.rs:14:10 + --> $DIR/drop_ref.rs:15:10 | LL | drop(&&owned1); | ^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:15:5 + --> $DIR/drop_ref.rs:16:5 | LL | drop(&mut owned1); | ^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:15:10 + --> $DIR/drop_ref.rs:16:10 | LL | drop(&mut owned1); | ^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:19:5 + --> $DIR/drop_ref.rs:20:5 | LL | drop(reference1); | ^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:19:10 + --> $DIR/drop_ref.rs:20:10 | LL | drop(reference1); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:22:5 + --> $DIR/drop_ref.rs:23:5 | LL | drop(reference2); | ^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:22:10 + --> $DIR/drop_ref.rs:23:10 | LL | drop(reference2); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:25:5 + --> $DIR/drop_ref.rs:26:5 | LL | drop(reference3); | ^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:25:10 + --> $DIR/drop_ref.rs:26:10 | LL | drop(reference3); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:30:5 + --> $DIR/drop_ref.rs:31:5 | LL | drop(&val); | ^^^^^^^^^^ | note: argument has type `&T` - --> $DIR/drop_ref.rs:30:10 + --> $DIR/drop_ref.rs:31:10 | LL | drop(&val); | ^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:38:5 + --> $DIR/drop_ref.rs:39:5 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:38:20 + --> $DIR/drop_ref.rs:39:20 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/empty_loop.stderr b/src/tools/clippy/tests/ui/empty_loop.stderr index fd3979f259a14..555f3d3d884a9 100644 --- a/src/tools/clippy/tests/ui/empty_loop.stderr +++ b/src/tools/clippy/tests/ui/empty_loop.stderr @@ -5,7 +5,7 @@ LL | loop {} | ^^^^^^^ | = note: `-D clippy::empty-loop` implied by `-D warnings` - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop.rs:11:9 @@ -13,7 +13,7 @@ error: empty `loop {}` wastes CPU cycles LL | loop {} | ^^^^^^^ | - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop.rs:15:9 @@ -21,7 +21,7 @@ error: empty `loop {}` wastes CPU cycles LL | 'inner: loop {} | ^^^^^^^^^^^^^^^ | - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.rs b/src/tools/clippy/tests/ui/empty_loop_no_std.rs index 879d1d5d916e4..4553d3ec505a3 100644 --- a/src/tools/clippy/tests/ui/empty_loop_no_std.rs +++ b/src/tools/clippy/tests/ui/empty_loop_no_std.rs @@ -10,13 +10,18 @@ use core::panic::PanicInfo; #[start] fn main(argc: isize, argv: *const *const u8) -> isize { + // This should trigger the lint loop {} } #[panic_handler] fn panic(_info: &PanicInfo) -> ! { + // This should NOT trigger the lint loop {} } #[lang = "eh_personality"] -extern "C" fn eh_personality() {} +extern "C" fn eh_personality() { + // This should also trigger the lint + loop {} +} diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr new file mode 100644 index 0000000000000..520248fcb689c --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr @@ -0,0 +1,19 @@ +error: empty `loop {}` wastes CPU cycles + --> $DIR/empty_loop_no_std.rs:14:5 + | +LL | loop {} + | ^^^^^^^ + | + = note: `-D clippy::empty-loop` implied by `-D warnings` + = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body + +error: empty `loop {}` wastes CPU cycles + --> $DIR/empty_loop_no_std.rs:26:5 + | +LL | loop {} + | ^^^^^^^ + | + = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/filter_methods.rs b/src/tools/clippy/tests/ui/filter_methods.rs index ef434245fd70c..5145024161926 100644 --- a/src/tools/clippy/tests/ui/filter_methods.rs +++ b/src/tools/clippy/tests/ui/filter_methods.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] fn main() { diff --git a/src/tools/clippy/tests/ui/filter_methods.stderr b/src/tools/clippy/tests/ui/filter_methods.stderr index 91718dd11755b..119226813793c 100644 --- a/src/tools/clippy/tests/ui/filter_methods.stderr +++ b/src/tools/clippy/tests/ui/filter_methods.stderr @@ -1,5 +1,5 @@ error: called `filter(..).map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:5:21 + --> $DIR/filter_methods.rs:6:21 | LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * = help: this is more succinctly expressed by calling `.filter_map(..)` instead error: called `filter(..).flat_map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:7:21 + --> $DIR/filter_methods.rs:8:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ @@ -20,7 +20,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` error: called `filter_map(..).flat_map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:13:21 + --> $DIR/filter_methods.rs:14:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ @@ -32,7 +32,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` error: called `filter_map(..).map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:19:21 + --> $DIR/filter_methods.rs:20:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ diff --git a/src/tools/clippy/tests/ui/forget_ref.rs b/src/tools/clippy/tests/ui/forget_ref.rs index 447fdbe1fac53..c49e6756a6c5b 100644 --- a/src/tools/clippy/tests/ui/forget_ref.rs +++ b/src/tools/clippy/tests/ui/forget_ref.rs @@ -1,5 +1,6 @@ #![warn(clippy::forget_ref)] #![allow(clippy::toplevel_ref_arg)] +#![allow(clippy::unnecessary_wraps)] use std::mem::forget; diff --git a/src/tools/clippy/tests/ui/forget_ref.stderr b/src/tools/clippy/tests/ui/forget_ref.stderr index f90bcc2762cee..b2c7f2023bfbf 100644 --- a/src/tools/clippy/tests/ui/forget_ref.stderr +++ b/src/tools/clippy/tests/ui/forget_ref.stderr @@ -1,108 +1,108 @@ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:9:5 + --> $DIR/forget_ref.rs:10:5 | LL | forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::forget-ref` implied by `-D warnings` note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:9:12 + --> $DIR/forget_ref.rs:10:12 | LL | forget(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:12:5 + --> $DIR/forget_ref.rs:13:5 | LL | forget(&owned); | ^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:12:12 + --> $DIR/forget_ref.rs:13:12 | LL | forget(&owned); | ^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:13:5 + --> $DIR/forget_ref.rs:14:5 | LL | forget(&&owned); | ^^^^^^^^^^^^^^^ | note: argument has type `&&SomeStruct` - --> $DIR/forget_ref.rs:13:12 + --> $DIR/forget_ref.rs:14:12 | LL | forget(&&owned); | ^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:14:5 + --> $DIR/forget_ref.rs:15:5 | LL | forget(&mut owned); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:14:12 + --> $DIR/forget_ref.rs:15:12 | LL | forget(&mut owned); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:18:5 + --> $DIR/forget_ref.rs:19:5 | LL | forget(&*reference1); | ^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:18:12 + --> $DIR/forget_ref.rs:19:12 | LL | forget(&*reference1); | ^^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:21:5 + --> $DIR/forget_ref.rs:22:5 | LL | forget(reference2); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:21:12 + --> $DIR/forget_ref.rs:22:12 | LL | forget(reference2); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:24:5 + --> $DIR/forget_ref.rs:25:5 | LL | forget(reference3); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:24:12 + --> $DIR/forget_ref.rs:25:12 | LL | forget(reference3); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:29:5 + --> $DIR/forget_ref.rs:30:5 | LL | forget(&val); | ^^^^^^^^^^^^ | note: argument has type `&T` - --> $DIR/forget_ref.rs:29:12 + --> $DIR/forget_ref.rs:30:12 | LL | forget(&val); | ^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:37:5 + --> $DIR/forget_ref.rs:38:5 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:37:22 + --> $DIR/forget_ref.rs:38:22 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/let_underscore_drop.rs b/src/tools/clippy/tests/ui/let_underscore_drop.rs new file mode 100644 index 0000000000000..98593edb9c591 --- /dev/null +++ b/src/tools/clippy/tests/ui/let_underscore_drop.rs @@ -0,0 +1,19 @@ +#![warn(clippy::let_underscore_drop)] + +struct Droppable; + +impl Drop for Droppable { + fn drop(&mut self) {} +} + +fn main() { + let unit = (); + let boxed = Box::new(()); + let droppable = Droppable; + let optional = Some(Droppable); + + let _ = (); + let _ = Box::new(()); + let _ = Droppable; + let _ = Some(Droppable); +} diff --git a/src/tools/clippy/tests/ui/let_underscore_drop.stderr b/src/tools/clippy/tests/ui/let_underscore_drop.stderr new file mode 100644 index 0000000000000..66069e0c5e13f --- /dev/null +++ b/src/tools/clippy/tests/ui/let_underscore_drop.stderr @@ -0,0 +1,27 @@ +error: non-binding `let` on a type that implements `Drop` + --> $DIR/let_underscore_drop.rs:16:5 + | +LL | let _ = Box::new(()); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::let-underscore-drop` implied by `-D warnings` + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding `let` on a type that implements `Drop` + --> $DIR/let_underscore_drop.rs:17:5 + | +LL | let _ = Droppable; + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding `let` on a type that implements `Drop` + --> $DIR/let_underscore_drop.rs:18:5 + | +LL | let _ = Some(Droppable); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/let_underscore_must_use.rs b/src/tools/clippy/tests/ui/let_underscore_must_use.rs index 27dda606067aa..a842e872a37b1 100644 --- a/src/tools/clippy/tests/ui/let_underscore_must_use.rs +++ b/src/tools/clippy/tests/ui/let_underscore_must_use.rs @@ -1,4 +1,5 @@ #![warn(clippy::let_underscore_must_use)] +#![allow(clippy::unnecessary_wraps)] // Debug implementations can fire this lint, // so we shouldn't lint external macros diff --git a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr index 447f2419e3bdb..5b751ea56deff 100644 --- a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr @@ -1,5 +1,5 @@ error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:66:5 + --> $DIR/let_underscore_must_use.rs:67:5 | LL | let _ = f(); | ^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = f(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:67:5 + --> $DIR/let_underscore_must_use.rs:68:5 | LL | let _ = g(); | ^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = g(); = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:69:5 + --> $DIR/let_underscore_must_use.rs:70:5 | LL | let _ = l(0_u32); | ^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _ = l(0_u32); = help: consider explicitly using function result error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:73:5 + --> $DIR/let_underscore_must_use.rs:74:5 | LL | let _ = s.f(); | ^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let _ = s.f(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:74:5 + --> $DIR/let_underscore_must_use.rs:75:5 | LL | let _ = s.g(); | ^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let _ = s.g(); = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:77:5 + --> $DIR/let_underscore_must_use.rs:78:5 | LL | let _ = S::h(); | ^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let _ = S::h(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:78:5 + --> $DIR/let_underscore_must_use.rs:79:5 | LL | let _ = S::p(); | ^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = S::p(); = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:80:5 + --> $DIR/let_underscore_must_use.rs:81:5 | LL | let _ = S::a(); | ^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _ = S::a(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:82:5 + --> $DIR/let_underscore_must_use.rs:83:5 | LL | let _ = if true { Ok(()) } else { Err(()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _ = if true { Ok(()) } else { Err(()) }; = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:86:5 + --> $DIR/let_underscore_must_use.rs:87:5 | LL | let _ = a.is_ok(); | ^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let _ = a.is_ok(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:88:5 + --> $DIR/let_underscore_must_use.rs:89:5 | LL | let _ = a.map(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = a.map(|_| ()); = help: consider explicitly using expression value error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:90:5 + --> $DIR/let_underscore_must_use.rs:91:5 | LL | let _ = a; | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/manual_async_fn.fixed b/src/tools/clippy/tests/ui/manual_async_fn.fixed index 4f551690c4370..5184f6fdb88b3 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.fixed +++ b/src/tools/clippy/tests/ui/manual_async_fn.fixed @@ -7,7 +7,19 @@ use std::future::Future; async fn fut() -> i32 { 42 } -async fn empty_fut() {} +#[rustfmt::skip] +async fn fut2() -> i32 { 42 } + +#[rustfmt::skip] +async fn fut3() -> i32 { 42 } + +async fn empty_fut() {} + +#[rustfmt::skip] +async fn empty_fut2() {} + +#[rustfmt::skip] +async fn empty_fut3() {} async fn core_fut() -> i32 { 42 } diff --git a/src/tools/clippy/tests/ui/manual_async_fn.rs b/src/tools/clippy/tests/ui/manual_async_fn.rs index 6ed60309947a8..68c0e591f0b6e 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.rs +++ b/src/tools/clippy/tests/ui/manual_async_fn.rs @@ -9,10 +9,30 @@ fn fut() -> impl Future { async { 42 } } +#[rustfmt::skip] +fn fut2() ->impl Future { + async { 42 } +} + +#[rustfmt::skip] +fn fut3()-> impl Future { + async { 42 } +} + fn empty_fut() -> impl Future { async {} } +#[rustfmt::skip] +fn empty_fut2() ->impl Future { + async {} +} + +#[rustfmt::skip] +fn empty_fut3()-> impl Future { + async {} +} + fn core_fut() -> impl core::future::Future { async move { 42 } } diff --git a/src/tools/clippy/tests/ui/manual_async_fn.stderr b/src/tools/clippy/tests/ui/manual_async_fn.stderr index ccd828674276b..fdd43db3255ee 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.stderr +++ b/src/tools/clippy/tests/ui/manual_async_fn.stderr @@ -15,14 +15,44 @@ LL | fn fut() -> impl Future { 42 } | ^^^^^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:12:1 + --> $DIR/manual_async_fn.rs:13:1 + | +LL | fn fut2() ->impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | async fn fut2() -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn fut2() ->impl Future { 42 } + | ^^^^^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:18:1 + | +LL | fn fut3()-> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | async fn fut3() -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn fut3()-> impl Future { 42 } + | ^^^^^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:22:1 | LL | fn empty_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and remove the return type | -LL | async fn empty_fut() { +LL | async fn empty_fut() { | ^^^^^^^^^^^^^^^^^^^^ help: move the body of the async block to the enclosing function | @@ -30,7 +60,37 @@ LL | fn empty_fut() -> impl Future {} | ^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:16:1 + --> $DIR/manual_async_fn.rs:27:1 + | +LL | fn empty_fut2() ->impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and remove the return type + | +LL | async fn empty_fut2() { + | ^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn empty_fut2() ->impl Future {} + | ^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:32:1 + | +LL | fn empty_fut3()-> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and remove the return type + | +LL | async fn empty_fut3() { + | ^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn empty_fut3()-> impl Future {} + | ^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:36:1 | LL | fn core_fut() -> impl core::future::Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +105,7 @@ LL | fn core_fut() -> impl core::future::Future { 42 } | ^^^^^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:38:5 + --> $DIR/manual_async_fn.rs:58:5 | LL | fn inh_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -65,7 +125,7 @@ LL | let c = 21; ... error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:73:1 + --> $DIR/manual_async_fn.rs:93:1 | LL | fn elided(_: &i32) -> impl Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +140,7 @@ LL | fn elided(_: &i32) -> impl Future + '_ { 42 } | ^^^^^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:82:1 + --> $DIR/manual_async_fn.rs:102:1 | LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -94,5 +154,5 @@ help: move the body of the async block to the enclosing function LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { 42 } | ^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/manual_ok_or.fixed b/src/tools/clippy/tests/ui/manual_ok_or.fixed index b42e94bd727de..887a97d7a0173 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.fixed +++ b/src/tools/clippy/tests/ui/manual_ok_or.fixed @@ -28,7 +28,7 @@ fn main() { // not applicable, or side isn't `Result::Err` foo.map_or(Ok::(1), |v| Ok(v)); - // not applicatble, expr is not a `Result` value + // not applicable, expr is not a `Result` value foo.map_or(42, |v| v); // TODO patterns not covered yet diff --git a/src/tools/clippy/tests/ui/manual_ok_or.rs b/src/tools/clippy/tests/ui/manual_ok_or.rs index e5a6056fbf5cc..3c99872f5022a 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.rs +++ b/src/tools/clippy/tests/ui/manual_ok_or.rs @@ -32,7 +32,7 @@ fn main() { // not applicable, or side isn't `Result::Err` foo.map_or(Ok::(1), |v| Ok(v)); - // not applicatble, expr is not a `Result` value + // not applicable, expr is not a `Result` value foo.map_or(42, |v| v); // TODO patterns not covered yet diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed index 5aa5a43cb92cf..81d903c15d32a 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code)] -#![allow(unused_variables)] +#![allow(unused_variables, clippy::unnecessary_wraps)] fn option_unwrap_or() { // int case diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs index df534031f54c3..16105d379c305 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code)] -#![allow(unused_variables)] +#![allow(unused_variables, clippy::unnecessary_wraps)] fn option_unwrap_or() { // int case diff --git a/src/tools/clippy/tests/ui/map_clone.fixed b/src/tools/clippy/tests/ui/map_clone.fixed index 81c7f659efb1f..178d8705c2f02 100644 --- a/src/tools/clippy/tests/ui/map_clone.fixed +++ b/src/tools/clippy/tests/ui/map_clone.fixed @@ -2,6 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::iter_cloned_collect)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::redundant_closure_for_method_calls)] #![allow(clippy::many_single_char_names)] @@ -44,4 +45,19 @@ fn main() { let v = vec![&mut d]; let _: Vec = v.into_iter().map(|&mut x| x).collect(); } + + // Issue #6299 + { + let mut aa = 5; + let mut bb = 3; + let items = vec![&mut aa, &mut bb]; + let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect(); + } + + // Issue #6239 deref coercion and clone deref + { + use std::cell::RefCell; + + let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone()); + } } diff --git a/src/tools/clippy/tests/ui/map_clone.rs b/src/tools/clippy/tests/ui/map_clone.rs index 8ed164f0ed51d..c73d81713b8a3 100644 --- a/src/tools/clippy/tests/ui/map_clone.rs +++ b/src/tools/clippy/tests/ui/map_clone.rs @@ -2,6 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::iter_cloned_collect)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::redundant_closure_for_method_calls)] #![allow(clippy::many_single_char_names)] @@ -44,4 +45,19 @@ fn main() { let v = vec![&mut d]; let _: Vec = v.into_iter().map(|&mut x| x).collect(); } + + // Issue #6299 + { + let mut aa = 5; + let mut bb = 3; + let items = vec![&mut aa, &mut bb]; + let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect(); + } + + // Issue #6239 deref coercion and clone deref + { + use std::cell::RefCell; + + let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone()); + } } diff --git a/src/tools/clippy/tests/ui/map_clone.stderr b/src/tools/clippy/tests/ui/map_clone.stderr index 4f43cff502444..d84a5bf8d4de6 100644 --- a/src/tools/clippy/tests/ui/map_clone.stderr +++ b/src/tools/clippy/tests/ui/map_clone.stderr @@ -1,5 +1,5 @@ error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:10:22 + --> $DIR/map_clone.rs:11:22 | LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()` @@ -7,31 +7,31 @@ LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); = note: `-D clippy::map-clone` implied by `-D warnings` error: you are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:11:26 + --> $DIR/map_clone.rs:12:26 | LL | let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:12:23 + --> $DIR/map_clone.rs:13:23 | LL | let _: Vec = vec![42, 43].iter().map(|&x| x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()` error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:14:26 + --> $DIR/map_clone.rs:15:26 | LL | let _: Option = Some(&16).map(|b| *b); | ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()` error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:15:25 + --> $DIR/map_clone.rs:16:25 | LL | let _: Option = Some(&1).map(|x| x.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()` error: you are needlessly cloning iterator elements - --> $DIR/map_clone.rs:26:29 + --> $DIR/map_clone.rs:27:29 | LL | let _ = std::env::args().map(|v| v.clone()); | ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call diff --git a/src/tools/clippy/tests/ui/map_err.rs b/src/tools/clippy/tests/ui/map_err.rs index 617b642287264..05b9949f10217 100644 --- a/src/tools/clippy/tests/ui/map_err.rs +++ b/src/tools/clippy/tests/ui/map_err.rs @@ -1,4 +1,5 @@ #![warn(clippy::map_err_ignore)] +#![allow(clippy::unnecessary_wraps)] use std::convert::TryFrom; use std::error::Error; use std::fmt; diff --git a/src/tools/clippy/tests/ui/map_err.stderr b/src/tools/clippy/tests/ui/map_err.stderr index 7273f46038078..390d7ce2e4e7b 100644 --- a/src/tools/clippy/tests/ui/map_err.stderr +++ b/src/tools/clippy/tests/ui/map_err.stderr @@ -1,5 +1,5 @@ error: `map_err(|_|...` ignores the original error - --> $DIR/map_err.rs:22:32 + --> $DIR/map_err.rs:23:32 | LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); | ^^^ diff --git a/src/tools/clippy/tests/ui/map_flatten.fixed b/src/tools/clippy/tests/ui/map_flatten.fixed index a5fdf7df613d3..773b5914439d3 100644 --- a/src/tools/clippy/tests/ui/map_flatten.fixed +++ b/src/tools/clippy/tests/ui/map_flatten.fixed @@ -1,8 +1,10 @@ // run-rustfix #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] +#![allow(clippy::unnecessary_wraps)] fn main() { // mapping to Option on Iterator diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs index abbc4e16e5679..578bd87726795 100644 --- a/src/tools/clippy/tests/ui/map_flatten.rs +++ b/src/tools/clippy/tests/ui/map_flatten.rs @@ -1,8 +1,10 @@ // run-rustfix #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] +#![allow(clippy::unnecessary_wraps)] fn main() { // mapping to Option on Iterator diff --git a/src/tools/clippy/tests/ui/map_flatten.stderr b/src/tools/clippy/tests/ui/map_flatten.stderr index b6479cd69eac4..756e6e818ad44 100644 --- a/src/tools/clippy/tests/ui/map_flatten.stderr +++ b/src/tools/clippy/tests/ui/map_flatten.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:14:46 + --> $DIR/map_flatten.rs:16:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)` @@ -7,31 +7,31 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll = note: `-D clippy::map-flatten` implied by `-D warnings` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:15:46 + --> $DIR/map_flatten.rs:17:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:16:46 + --> $DIR/map_flatten.rs:18:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:17:46 + --> $DIR/map_flatten.rs:19:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:20:46 + --> $DIR/map_flatten.rs:22:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)` error: called `map(..).flatten()` on an `Option` - --> $DIR/map_flatten.rs:23:39 + --> $DIR/map_flatten.rs:25:39 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs index d93e5b114ecfa..513d930e05687 100644 --- a/src/tools/clippy/tests/ui/methods.rs +++ b/src/tools/clippy/tests/ui/methods.rs @@ -133,50 +133,6 @@ fn filter_next() { let _ = foo.filter().next(); } -/// Checks implementation of `SEARCH_IS_SOME` lint. -#[rustfmt::skip] -fn search_is_some() { - let v = vec![3, 2, 1, 0, -1, -2, -3]; - let y = &&42; - - // Check `find().is_some()`, single-line case. - let _ = v.iter().find(|&x| *x < 0).is_some(); - let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - let _ = (0..1).find(|x| *x == 0).is_some(); - let _ = v.iter().find(|x| **x == 0).is_some(); - - // Check `find().is_some()`, multi-line case. - let _ = v.iter().find(|&x| { - *x < 0 - } - ).is_some(); - - // Check `position().is_some()`, single-line case. - let _ = v.iter().position(|&x| x < 0).is_some(); - - // Check `position().is_some()`, multi-line case. - let _ = v.iter().position(|&x| { - x < 0 - } - ).is_some(); - - // Check `rposition().is_some()`, single-line case. - let _ = v.iter().rposition(|&x| x < 0).is_some(); - - // Check `rposition().is_some()`, multi-line case. - let _ = v.iter().rposition(|&x| { - x < 0 - } - ).is_some(); - - // Check that we don't lint if the caller is not an `Iterator`. - let foo = IteratorFalsePositives { foo: 0 }; - let _ = foo.find().is_some(); - let _ = foo.position().is_some(); - let _ = foo.rposition().is_some(); -} - fn main() { filter_next(); - search_is_some(); } diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr index 8a281c2dbd25c..33aba630a5304 100644 --- a/src/tools/clippy/tests/ui/methods.stderr +++ b/src/tools/clippy/tests/ui/methods.stderr @@ -20,73 +20,5 @@ LL | | ).next(); | = note: `-D clippy::filter-next` implied by `-D warnings` -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:143:22 - | -LL | let _ = v.iter().find(|&x| *x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` - | - = note: `-D clippy::search-is-some` implied by `-D warnings` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:144:20 - | -LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:145:20 - | -LL | let _ = (0..1).find(|x| *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:146:22 - | -LL | let _ = v.iter().find(|x| **x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:149:13 - | -LL | let _ = v.iter().find(|&x| { - | _____________^ -LL | | *x < 0 -LL | | } -LL | | ).is_some(); - | |______________________________^ - -error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:155:22 - | -LL | let _ = v.iter().position(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` - -error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:158:13 - | -LL | let _ = v.iter().position(|&x| { - | _____________^ -LL | | x < 0 -LL | | } -LL | | ).is_some(); - | |______________________________^ - -error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:164:22 - | -LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` - -error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:167:13 - | -LL | let _ = v.iter().rposition(|&x| { - | _____________^ -LL | | x < 0 -LL | | } -LL | | ).is_some(); - | |______________________________^ - -error: aborting due to 11 previous errors +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index 6001ef37eb781..44972c8c63964 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_lifetimes)] -#![allow(dead_code, clippy::needless_pass_by_value)] +#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed index 96d1c54946c0b..7d29445e66c8b 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed @@ -2,6 +2,7 @@ #![warn(clippy::option_map_unit_fn)] #![allow(unused)] +#![allow(clippy::unnecessary_wraps)] fn do_nothing(_: T) {} diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs index 931ffc1866593..b6f834f686f9f 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs @@ -2,6 +2,7 @@ #![warn(clippy::option_map_unit_fn)] #![allow(unused)] +#![allow(clippy::unnecessary_wraps)] fn do_nothing(_: T) {} diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr index d7d45ef9b0b33..8abdbcafb6e93 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr @@ -1,5 +1,5 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:38:5 + --> $DIR/option_map_unit_fn_fixable.rs:39:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -9,7 +9,7 @@ LL | x.field.map(do_nothing); = note: `-D clippy::option-map-unit-fn` implied by `-D warnings` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:40:5 + --> $DIR/option_map_unit_fn_fixable.rs:41:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | x.field.map(do_nothing); | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:42:5 + --> $DIR/option_map_unit_fn_fixable.rs:43:5 | LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- @@ -25,7 +25,7 @@ LL | x.field.map(diverge); | help: try this: `if let Some(x_field) = x.field { diverge(x_field) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:48:5 + --> $DIR/option_map_unit_fn_fixable.rs:49:5 | LL | x.field.map(|value| x.do_option_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -33,7 +33,7 @@ LL | x.field.map(|value| x.do_option_nothing(value + captured)); | help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:50:5 + --> $DIR/option_map_unit_fn_fixable.rs:51:5 | LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -41,7 +41,7 @@ LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:53:5 + --> $DIR/option_map_unit_fn_fixable.rs:54:5 | LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -49,7 +49,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:55:5 + --> $DIR/option_map_unit_fn_fixable.rs:56:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -57,7 +57,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:57:5 + --> $DIR/option_map_unit_fn_fixable.rs:58:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -65,7 +65,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:59:5 + --> $DIR/option_map_unit_fn_fixable.rs:60:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -73,7 +73,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:62:5 + --> $DIR/option_map_unit_fn_fixable.rs:63:5 | LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -81,7 +81,7 @@ LL | x.field.map(|value| diverge(value + captured)); | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:64:5 + --> $DIR/option_map_unit_fn_fixable.rs:65:5 | LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -89,7 +89,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:66:5 + --> $DIR/option_map_unit_fn_fixable.rs:67:5 | LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -97,7 +97,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:68:5 + --> $DIR/option_map_unit_fn_fixable.rs:69:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -105,7 +105,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:73:5 + --> $DIR/option_map_unit_fn_fixable.rs:74:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -113,7 +113,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:75:5 + --> $DIR/option_map_unit_fn_fixable.rs:76:5 | LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -121,7 +121,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:77:5 + --> $DIR/option_map_unit_fn_fixable.rs:78:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -129,7 +129,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:80:5 + --> $DIR/option_map_unit_fn_fixable.rs:81:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -137,7 +137,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) }); | help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:82:5 + --> $DIR/option_map_unit_fn_fixable.rs:83:5 | LL | option().map(do_nothing);} | ^^^^^^^^^^^^^^^^^^^^^^^^- diff --git a/src/tools/clippy/tests/ui/option_option.rs b/src/tools/clippy/tests/ui/option_option.rs index a2617a13ecace..6859ba8e5bb8f 100644 --- a/src/tools/clippy/tests/ui/option_option.rs +++ b/src/tools/clippy/tests/ui/option_option.rs @@ -1,4 +1,5 @@ #![deny(clippy::option_option)] +#![allow(clippy::unnecessary_wraps)] fn input(_: Option>) {} @@ -72,8 +73,6 @@ mod issue_4298 { #[serde(skip_serializing_if = "Option::is_none")] #[serde(default)] #[serde(borrow)] - // FIXME: should not lint here - #[allow(clippy::option_option)] foo: Option>>, } diff --git a/src/tools/clippy/tests/ui/option_option.stderr b/src/tools/clippy/tests/ui/option_option.stderr index 0cd4c96eb4f9a..ad7f081c71392 100644 --- a/src/tools/clippy/tests/ui/option_option.stderr +++ b/src/tools/clippy/tests/ui/option_option.stderr @@ -1,5 +1,5 @@ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:3:13 + --> $DIR/option_option.rs:4:13 | LL | fn input(_: Option>) {} | ^^^^^^^^^^^^^^^^^^ @@ -11,55 +11,55 @@ LL | #![deny(clippy::option_option)] | ^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:5:16 + --> $DIR/option_option.rs:6:16 | LL | fn output() -> Option> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:9:27 + --> $DIR/option_option.rs:10:27 | LL | fn output_nested() -> Vec>> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:14:30 + --> $DIR/option_option.rs:15:30 | LL | fn output_nested_nested() -> Option>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:19:8 + --> $DIR/option_option.rs:20:8 | LL | x: Option>, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:23:23 + --> $DIR/option_option.rs:24:23 | LL | fn struct_fn() -> Option> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:29:22 + --> $DIR/option_option.rs:30:22 | LL | fn trait_fn() -> Option>; | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:33:11 + --> $DIR/option_option.rs:34:11 | LL | Tuple(Option>), | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:34:17 + --> $DIR/option_option.rs:35:17 | LL | Struct { x: Option> }, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:77:14 + --> $DIR/option_option.rs:76:14 | LL | foo: Option>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed index 2045ffdb5f09d..2a63318c8c7a8 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.fixed +++ b/src/tools/clippy/tests/ui/or_fun_call.fixed @@ -2,6 +2,7 @@ #![warn(clippy::or_fun_call)] #![allow(dead_code)] +#![allow(clippy::unnecessary_wraps)] use std::collections::BTreeMap; use std::collections::HashMap; @@ -70,6 +71,15 @@ fn or_fun_call() { let opt = Some(1); let hello = "Hello"; let _ = opt.ok_or(format!("{} world.", hello)); + + // index + let map = HashMap::::new(); + let _ = Some(1).unwrap_or_else(|| map[&1]); + let map = BTreeMap::::new(); + let _ = Some(1).unwrap_or_else(|| map[&1]); + // don't lint index vec + let vec = vec![1]; + let _ = Some(1).unwrap_or(vec[1]); } struct Foo(u8); diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs index 522f31b72d01f..026ef437caa1a 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.rs +++ b/src/tools/clippy/tests/ui/or_fun_call.rs @@ -2,6 +2,7 @@ #![warn(clippy::or_fun_call)] #![allow(dead_code)] +#![allow(clippy::unnecessary_wraps)] use std::collections::BTreeMap; use std::collections::HashMap; @@ -70,6 +71,15 @@ fn or_fun_call() { let opt = Some(1); let hello = "Hello"; let _ = opt.ok_or(format!("{} world.", hello)); + + // index + let map = HashMap::::new(); + let _ = Some(1).unwrap_or(map[&1]); + let map = BTreeMap::::new(); + let _ = Some(1).unwrap_or(map[&1]); + // don't lint index vec + let vec = vec![1]; + let _ = Some(1).unwrap_or(vec[1]); } struct Foo(u8); diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr index bc5978b538f16..fb8bf339828f4 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.stderr +++ b/src/tools/clippy/tests/ui/or_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:32:19 + --> $DIR/or_fun_call.rs:33:19 | LL | with_const_fn.unwrap_or(Duration::from_secs(5)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))` @@ -7,88 +7,100 @@ LL | with_const_fn.unwrap_or(Duration::from_secs(5)); = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:35:22 + --> $DIR/or_fun_call.rs:36:22 | LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:38:5 + --> $DIR/or_fun_call.rs:39:5 | LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:41:21 + --> $DIR/or_fun_call.rs:42:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:44:14 + --> $DIR/or_fun_call.rs:45:14 | LL | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:47:19 + --> $DIR/or_fun_call.rs:48:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:50:5 + --> $DIR/or_fun_call.rs:51:5 | LL | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:53:5 + --> $DIR/or_fun_call.rs:54:5 | LL | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:56:5 + --> $DIR/or_fun_call.rs:57:5 | LL | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_vec.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:59:21 + --> $DIR/or_fun_call.rs:60:21 | LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:62:19 + --> $DIR/or_fun_call.rs:63:19 | LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:65:21 + --> $DIR/or_fun_call.rs:66:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:68:21 + --> $DIR/or_fun_call.rs:69:21 | LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:77:21 + | +LL | let _ = Some(1).unwrap_or(map[&1]); + | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:79:21 + | +LL | let _ = Some(1).unwrap_or(map[&1]); + | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:93:35 + --> $DIR/or_fun_call.rs:103:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:97:10 + --> $DIR/or_fun_call.rs:107:10 | LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.rs b/src/tools/clippy/tests/ui/panic_in_result_fn.rs index 287726f7a2d4e..3d3c19a1be519 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn.rs +++ b/src/tools/clippy/tests/ui/panic_in_result_fn.rs @@ -1,4 +1,5 @@ #![warn(clippy::panic_in_result_fn)] +#![allow(clippy::unnecessary_wraps)] struct A; diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr index c6936fd86923c..ca73ac5a41114 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr +++ b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr @@ -1,5 +1,5 @@ error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:6:5 + --> $DIR/panic_in_result_fn.rs:7:5 | LL | / fn result_with_panic() -> Result // should emit lint LL | | { @@ -10,14 +10,14 @@ LL | | } = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:8:9 + --> $DIR/panic_in_result_fn.rs:9:9 | LL | panic!("error"); | ^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:11:5 + --> $DIR/panic_in_result_fn.rs:12:5 | LL | / fn result_with_unimplemented() -> Result // should emit lint LL | | { @@ -27,14 +27,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:13:9 + --> $DIR/panic_in_result_fn.rs:14:9 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:16:5 + --> $DIR/panic_in_result_fn.rs:17:5 | LL | / fn result_with_unreachable() -> Result // should emit lint LL | | { @@ -44,14 +44,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:18:9 + --> $DIR/panic_in_result_fn.rs:19:9 | LL | unreachable!(); | ^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:21:5 + --> $DIR/panic_in_result_fn.rs:22:5 | LL | / fn result_with_todo() -> Result // should emit lint LL | | { @@ -61,14 +61,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:23:9 + --> $DIR/panic_in_result_fn.rs:24:9 | LL | todo!("Finish this"); | ^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:52:1 + --> $DIR/panic_in_result_fn.rs:53:1 | LL | / fn function_result_with_panic() -> Result // should emit lint LL | | { @@ -78,14 +78,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:54:5 + --> $DIR/panic_in_result_fn.rs:55:5 | LL | panic!("error"); | ^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:67:1 + --> $DIR/panic_in_result_fn.rs:68:1 | LL | / fn main() -> Result<(), String> { LL | | todo!("finish main method"); @@ -95,7 +95,7 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:68:5 + --> $DIR/panic_in_result_fn.rs:69:5 | LL | todo!("finish main method"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed index 11dff94a28865..0b5746cb52270 100644 --- a/src/tools/clippy/tests/ui/question_mark.fixed +++ b/src/tools/clippy/tests/ui/question_mark.fixed @@ -1,5 +1,6 @@ // run-rustfix #![allow(unreachable_code)] +#![allow(clippy::unnecessary_wraps)] fn some_func(a: Option) -> Option { a?; diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs index 1d0ee82b4f778..0f0825c933467 100644 --- a/src/tools/clippy/tests/ui/question_mark.rs +++ b/src/tools/clippy/tests/ui/question_mark.rs @@ -1,5 +1,6 @@ // run-rustfix #![allow(unreachable_code)] +#![allow(clippy::unnecessary_wraps)] fn some_func(a: Option) -> Option { if a.is_none() { diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr index 502615fb175a1..6f330cfa385dd 100644 --- a/src/tools/clippy/tests/ui/question_mark.stderr +++ b/src/tools/clippy/tests/ui/question_mark.stderr @@ -1,5 +1,5 @@ error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:5:5 + --> $DIR/question_mark.rs:6:5 | LL | / if a.is_none() { LL | | return None; @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::question-mark` implied by `-D warnings` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:50:9 + --> $DIR/question_mark.rs:51:9 | LL | / if (self.opt).is_none() { LL | | return None; @@ -17,7 +17,7 @@ LL | | } | |_________^ help: replace it with: `(self.opt)?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:54:9 + --> $DIR/question_mark.rs:55:9 | LL | / if self.opt.is_none() { LL | | return None @@ -25,7 +25,7 @@ LL | | } | |_________^ help: replace it with: `self.opt?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:58:17 + --> $DIR/question_mark.rs:59:17 | LL | let _ = if self.opt.is_none() { | _________________^ @@ -36,7 +36,7 @@ LL | | }; | |_________^ help: replace it with: `Some(self.opt?)` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:64:17 + --> $DIR/question_mark.rs:65:17 | LL | let _ = if let Some(x) = self.opt { | _________________^ @@ -47,7 +47,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:81:9 + --> $DIR/question_mark.rs:82:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -55,7 +55,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:89:9 + --> $DIR/question_mark.rs:90:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -63,7 +63,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:97:9 + --> $DIR/question_mark.rs:98:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -71,7 +71,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:104:26 + --> $DIR/question_mark.rs:105:26 | LL | let v: &Vec<_> = if let Some(ref v) = self.opt { | __________________________^ @@ -82,7 +82,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt.as_ref()?` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:114:17 + --> $DIR/question_mark.rs:115:17 | LL | let v = if let Some(v) = self.opt { | _________________^ @@ -93,7 +93,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:129:5 + --> $DIR/question_mark.rs:130:5 | LL | / if f().is_none() { LL | | return None; diff --git a/src/tools/clippy/tests/ui/range_contains.fixed b/src/tools/clippy/tests/ui/range_contains.fixed index 632a6592a28b8..048874a7f8294 100644 --- a/src/tools/clippy/tests/ui/range_contains.fixed +++ b/src/tools/clippy/tests/ui/range_contains.fixed @@ -38,4 +38,9 @@ fn main() { x >= 8 || x >= 12; x < 12 || 12 < x; x >= 8 || x <= 12; + + // Fix #6315 + let y = 3.; + (0. ..1.).contains(&y); + !(0. ..=1.).contains(&y); } diff --git a/src/tools/clippy/tests/ui/range_contains.rs b/src/tools/clippy/tests/ui/range_contains.rs index 6af0d034ef617..60ad259f404d8 100644 --- a/src/tools/clippy/tests/ui/range_contains.rs +++ b/src/tools/clippy/tests/ui/range_contains.rs @@ -38,4 +38,9 @@ fn main() { x >= 8 || x >= 12; x < 12 || 12 < x; x >= 8 || x <= 12; + + // Fix #6315 + let y = 3.; + y >= 0. && y < 1.; + y < 0. || y > 1.; } diff --git a/src/tools/clippy/tests/ui/range_contains.stderr b/src/tools/clippy/tests/ui/range_contains.stderr index 69b009eafc30a..bc79f1bca8463 100644 --- a/src/tools/clippy/tests/ui/range_contains.stderr +++ b/src/tools/clippy/tests/ui/range_contains.stderr @@ -72,5 +72,17 @@ error: manual `!RangeInclusive::contains` implementation LL | 999 < x || 1 > x; | ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)` -error: aborting due to 12 previous errors +error: manual `Range::contains` implementation + --> $DIR/range_contains.rs:44:5 + | +LL | y >= 0. && y < 1.; + | ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)` + +error: manual `!RangeInclusive::contains` implementation + --> $DIR/range_contains.rs:45:5 + | +LL | y < 0. || y > 1.; + | ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)` + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed index fe8f62503b767..aa20512296aa1 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed @@ -7,6 +7,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::unnecessary_wraps, deprecated )] diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching.rs index 09426a6e59082..d76f9c288ffdb 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.rs @@ -7,6 +7,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::unnecessary_wraps, deprecated )] diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr index 3473ceea00e22..aeb309f5ba12a 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:15:12 + --> $DIR/redundant_pattern_matching.rs:16:12 | LL | if let Ok(_) = &result {} | -------^^^^^---------- help: try this: `if result.is_ok()` @@ -7,31 +7,31 @@ LL | if let Ok(_) = &result {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:17:12 + --> $DIR/redundant_pattern_matching.rs:18:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:19:12 + --> $DIR/redundant_pattern_matching.rs:20:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:21:15 + --> $DIR/redundant_pattern_matching.rs:22:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:23:15 + --> $DIR/redundant_pattern_matching.rs:24:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:33:5 + --> $DIR/redundant_pattern_matching.rs:34:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:38:5 + --> $DIR/redundant_pattern_matching.rs:39:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:43:5 + --> $DIR/redundant_pattern_matching.rs:44:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:48:5 + --> $DIR/redundant_pattern_matching.rs:49:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -67,73 +67,73 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:53:20 + --> $DIR/redundant_pattern_matching.rs:54:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:59:20 + --> $DIR/redundant_pattern_matching.rs:60:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:61:19 + --> $DIR/redundant_pattern_matching.rs:62:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:84:19 + --> $DIR/redundant_pattern_matching.rs:85:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:85:16 + --> $DIR/redundant_pattern_matching.rs:86:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:91:12 + --> $DIR/redundant_pattern_matching.rs:92:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:92:15 + --> $DIR/redundant_pattern_matching.rs:93:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:110:12 + --> $DIR/redundant_pattern_matching.rs:111:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:112:12 + --> $DIR/redundant_pattern_matching.rs:113:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:114:15 + --> $DIR/redundant_pattern_matching.rs:115:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:116:15 + --> $DIR/redundant_pattern_matching.rs:117:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:118:5 + --> $DIR/redundant_pattern_matching.rs:119:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:123:5 + --> $DIR/redundant_pattern_matching.rs:124:5 | LL | / match Err::(42) { LL | | Ok(_) => false, diff --git a/src/tools/clippy/tests/ui/result_unit_error.rs b/src/tools/clippy/tests/ui/result_unit_error.rs index a66f581b2159f..5e57c752b5a03 100644 --- a/src/tools/clippy/tests/ui/result_unit_error.rs +++ b/src/tools/clippy/tests/ui/result_unit_error.rs @@ -1,3 +1,4 @@ +#![allow(clippy::unnecessary_wraps)] #[warn(clippy::result_unit_err)] #[allow(unused)] diff --git a/src/tools/clippy/tests/ui/result_unit_error.stderr b/src/tools/clippy/tests/ui/result_unit_error.stderr index b8230032491b6..12901b354f916 100644 --- a/src/tools/clippy/tests/ui/result_unit_error.stderr +++ b/src/tools/clippy/tests/ui/result_unit_error.stderr @@ -1,5 +1,5 @@ error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:4:1 + --> $DIR/result_unit_error.rs:5:1 | LL | pub fn returns_unit_error() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pub fn returns_unit_error() -> Result { = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:13:5 + --> $DIR/result_unit_error.rs:14:5 | LL | fn get_that_error(&self) -> Result; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | fn get_that_error(&self) -> Result; = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:15:5 + --> $DIR/result_unit_error.rs:16:5 | LL | fn get_this_one_too(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | fn get_this_one_too(&self) -> Result { = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:33:5 + --> $DIR/result_unit_error.rs:34:5 | LL | pub fn unit_error(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/search_is_some.rs b/src/tools/clippy/tests/ui/search_is_some.rs new file mode 100644 index 0000000000000..f0dc3b3d06bbc --- /dev/null +++ b/src/tools/clippy/tests/ui/search_is_some.rs @@ -0,0 +1,38 @@ +// aux-build:option_helpers.rs +extern crate option_helpers; +use option_helpers::IteratorFalsePositives; + +#[warn(clippy::search_is_some)] +#[rustfmt::skip] +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + + // Check `find().is_some()`, multi-line case. + let _ = v.iter().find(|&x| { + *x < 0 + } + ).is_some(); + + // Check `position().is_some()`, multi-line case. + let _ = v.iter().position(|&x| { + x < 0 + } + ).is_some(); + + // Check `rposition().is_some()`, multi-line case. + let _ = v.iter().rposition(|&x| { + x < 0 + } + ).is_some(); + + // Check that we don't lint if the caller is not an `Iterator` or string + let falsepos = IteratorFalsePositives { foo: 0 }; + let _ = falsepos.find().is_some(); + let _ = falsepos.position().is_some(); + let _ = falsepos.rposition().is_some(); + // check that we don't lint if `find()` is called with + // `Pattern` that is not a string + let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some(); +} diff --git a/src/tools/clippy/tests/ui/search_is_some.stderr b/src/tools/clippy/tests/ui/search_is_some.stderr new file mode 100644 index 0000000000000..c601f568c609b --- /dev/null +++ b/src/tools/clippy/tests/ui/search_is_some.stderr @@ -0,0 +1,39 @@ +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:13:13 + | +LL | let _ = v.iter().find(|&x| { + | _____________^ +LL | | *x < 0 +LL | | } +LL | | ).is_some(); + | |______________________________^ + | + = note: `-D clippy::search-is-some` implied by `-D warnings` + = help: this is more succinctly expressed by calling `any()` + +error: called `is_some()` after searching an `Iterator` with `position` + --> $DIR/search_is_some.rs:19:13 + | +LL | let _ = v.iter().position(|&x| { + | _____________^ +LL | | x < 0 +LL | | } +LL | | ).is_some(); + | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` + +error: called `is_some()` after searching an `Iterator` with `rposition` + --> $DIR/search_is_some.rs:25:13 + | +LL | let _ = v.iter().rposition(|&x| { + | _____________^ +LL | | x < 0 +LL | | } +LL | | ).is_some(); + | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable.fixed new file mode 100644 index 0000000000000..dc3f290e56246 --- /dev/null +++ b/src/tools/clippy/tests/ui/search_is_some_fixable.fixed @@ -0,0 +1,35 @@ +// run-rustfix + +#![warn(clippy::search_is_some)] + +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + // Check `find().is_some()`, single-line case. + let _ = v.iter().any(|x| *x < 0); + let _ = (0..1).any(|x| **y == x); // one dereference less + let _ = (0..1).any(|x| x == 0); + let _ = v.iter().any(|x| *x == 0); + + // Check `position().is_some()`, single-line case. + let _ = v.iter().any(|&x| x < 0); + + // Check `rposition().is_some()`, single-line case. + let _ = v.iter().any(|&x| x < 0); + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + // caller of `find()` is a `&`static str` + let _ = "hello world".contains("world"); + let _ = "hello world".contains(&s2); + let _ = "hello world".contains(&s2[2..]); + // caller of `find()` is a `String` + let _ = s1.contains("world"); + let _ = s1.contains(&s2); + let _ = s1.contains(&s2[2..]); + // caller of `find()` is slice of `String` + let _ = s1[2..].contains("world"); + let _ = s1[2..].contains(&s2); + let _ = s1[2..].contains(&s2[2..]); +} diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable.rs b/src/tools/clippy/tests/ui/search_is_some_fixable.rs new file mode 100644 index 0000000000000..146cf5adf1b0f --- /dev/null +++ b/src/tools/clippy/tests/ui/search_is_some_fixable.rs @@ -0,0 +1,35 @@ +// run-rustfix + +#![warn(clippy::search_is_some)] + +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + // Check `find().is_some()`, single-line case. + let _ = v.iter().find(|&x| *x < 0).is_some(); + let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + let _ = (0..1).find(|x| *x == 0).is_some(); + let _ = v.iter().find(|x| **x == 0).is_some(); + + // Check `position().is_some()`, single-line case. + let _ = v.iter().position(|&x| x < 0).is_some(); + + // Check `rposition().is_some()`, single-line case. + let _ = v.iter().rposition(|&x| x < 0).is_some(); + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + // caller of `find()` is a `&`static str` + let _ = "hello world".find("world").is_some(); + let _ = "hello world".find(&s2).is_some(); + let _ = "hello world".find(&s2[2..]).is_some(); + // caller of `find()` is a `String` + let _ = s1.find("world").is_some(); + let _ = s1.find(&s2).is_some(); + let _ = s1.find(&s2[2..]).is_some(); + // caller of `find()` is slice of `String` + let _ = s1[2..].find("world").is_some(); + let _ = s1[2..].find(&s2).is_some(); + let _ = s1[2..].find(&s2[2..]).is_some(); +} diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable.stderr new file mode 100644 index 0000000000000..23c1d9a901b97 --- /dev/null +++ b/src/tools/clippy/tests/ui/search_is_some_fixable.stderr @@ -0,0 +1,94 @@ +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:10:22 + | +LL | let _ = v.iter().find(|&x| *x < 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)` + | + = note: `-D clippy::search-is-some` implied by `-D warnings` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:11:20 + | +LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:12:20 + | +LL | let _ = (0..1).find(|x| *x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:13:22 + | +LL | let _ = v.iter().find(|x| **x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)` + +error: called `is_some()` after searching an `Iterator` with `position` + --> $DIR/search_is_some_fixable.rs:16:22 + | +LL | let _ = v.iter().position(|&x| x < 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` + +error: called `is_some()` after searching an `Iterator` with `rposition` + --> $DIR/search_is_some_fixable.rs:19:22 + | +LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:24:27 + | +LL | let _ = "hello world".find("world").is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:25:27 + | +LL | let _ = "hello world".find(&s2).is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:26:27 + | +LL | let _ = "hello world".find(&s2[2..]).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:28:16 + | +LL | let _ = s1.find("world").is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:29:16 + | +LL | let _ = s1.find(&s2).is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:30:16 + | +LL | let _ = s1.find(&s2[2..]).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:32:21 + | +LL | let _ = s1[2..].find("world").is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:33:21 + | +LL | let _ = s1[2..].find(&s2).is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:34:21 + | +LL | let _ = s1[2..].find(&s2[2..]).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + +error: aborting due to 15 previous errors + diff --git a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed new file mode 100644 index 0000000000000..6e665cdd56302 --- /dev/null +++ b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed @@ -0,0 +1,6 @@ +// run-rustfix +#![warn(clippy::string_from_utf8_as_bytes)] + +fn main() { + let _ = Some(&"Hello World!"[6..11]); +} diff --git a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs new file mode 100644 index 0000000000000..670d206d3679c --- /dev/null +++ b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs @@ -0,0 +1,6 @@ +// run-rustfix +#![warn(clippy::string_from_utf8_as_bytes)] + +fn main() { + let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); +} diff --git a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.stderr b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.stderr new file mode 100644 index 0000000000000..bf5e5d33e8f9a --- /dev/null +++ b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.stderr @@ -0,0 +1,10 @@ +error: calling a slice of `as_bytes()` with `from_utf8` should be not necessary + --> $DIR/string_from_utf8_as_bytes.rs:5:13 + | +LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&"Hello World!"[6..11])` + | + = note: `-D clippy::string-from-utf8-as-bytes` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed index 9e77dcd873164..652b611208b73 100644 --- a/src/tools/clippy/tests/ui/try_err.fixed +++ b/src/tools/clippy/tests/ui/try_err.fixed @@ -2,6 +2,7 @@ // aux-build:macro_rules.rs #![deny(clippy::try_err)] +#![allow(clippy::unnecessary_wraps)] #[macro_use] extern crate macro_rules; @@ -78,12 +79,46 @@ fn nested_error() -> Result { Ok(1) } +// Bad suggestion when in macro (see #6242) +macro_rules! try_validation { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => return Err(1), + } + }}; +} + +macro_rules! ret_one { + () => { + 1 + }; +} + +macro_rules! try_validation_in_macro { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => return Err(ret_one!()), + } + }}; +} + +fn calling_macro() -> Result { + // macro + try_validation!(Ok::<_, i32>(5)); + // `Err` arg is another macro + try_validation_in_macro!(Ok::<_, i32>(5)); + Ok(5) +} + fn main() { basic_test().unwrap(); into_test().unwrap(); negative_test().unwrap(); closure_matches_test().unwrap(); closure_into_test().unwrap(); + calling_macro().unwrap(); // We don't want to lint in external macros try_err!(); diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs index 41bcb0a189e76..6bd479657b70b 100644 --- a/src/tools/clippy/tests/ui/try_err.rs +++ b/src/tools/clippy/tests/ui/try_err.rs @@ -2,6 +2,7 @@ // aux-build:macro_rules.rs #![deny(clippy::try_err)] +#![allow(clippy::unnecessary_wraps)] #[macro_use] extern crate macro_rules; @@ -78,12 +79,46 @@ fn nested_error() -> Result { Ok(1) } +// Bad suggestion when in macro (see #6242) +macro_rules! try_validation { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => Err(1)?, + } + }}; +} + +macro_rules! ret_one { + () => { + 1 + }; +} + +macro_rules! try_validation_in_macro { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => Err(ret_one!())?, + } + }}; +} + +fn calling_macro() -> Result { + // macro + try_validation!(Ok::<_, i32>(5)); + // `Err` arg is another macro + try_validation_in_macro!(Ok::<_, i32>(5)); + Ok(5) +} + fn main() { basic_test().unwrap(); into_test().unwrap(); negative_test().unwrap(); closure_matches_test().unwrap(); closure_into_test().unwrap(); + calling_macro().unwrap(); // We don't want to lint in external macros try_err!(); diff --git a/src/tools/clippy/tests/ui/try_err.stderr b/src/tools/clippy/tests/ui/try_err.stderr index 3f1cbc17e72d0..2c01d37192e8e 100644 --- a/src/tools/clippy/tests/ui/try_err.stderr +++ b/src/tools/clippy/tests/ui/try_err.stderr @@ -1,5 +1,5 @@ error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:18:9 + --> $DIR/try_err.rs:19:9 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err)` @@ -11,46 +11,68 @@ LL | #![deny(clippy::try_err)] | ^^^^^^^^^^^^^^^ error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:28:9 + --> $DIR/try_err.rs:29:9 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:48:17 + --> $DIR/try_err.rs:49:17 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err)` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:67:17 + --> $DIR/try_err.rs:68:17 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:106:9 + --> $DIR/try_err.rs:87:23 + | +LL | Err(_) => Err(1)?, + | ^^^^^^^ help: try this: `return Err(1)` +... +LL | try_validation!(Ok::<_, i32>(5)); + | --------------------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: returning an `Err(_)` with the `?` operator + --> $DIR/try_err.rs:102:23 + | +LL | Err(_) => Err(ret_one!())?, + | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())` +... +LL | try_validation_in_macro!(Ok::<_, i32>(5)); + | ------------------------------------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: returning an `Err(_)` with the `?` operator + --> $DIR/try_err.rs:141:9 | LL | Err(foo!())?; | ^^^^^^^^^^^^ help: try this: `return Err(foo!())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:113:9 + --> $DIR/try_err.rs:148:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:115:9 + --> $DIR/try_err.rs:150:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:123:9 + --> $DIR/try_err.rs:158:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs index fec115ff29d66..9ad16d365094e 100644 --- a/src/tools/clippy/tests/ui/unit_arg.rs +++ b/src/tools/clippy/tests/ui/unit_arg.rs @@ -4,6 +4,7 @@ unused_must_use, unused_variables, clippy::unused_unit, + clippy::unnecessary_wraps, clippy::or_fun_call )] diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index 90fee3aab23b0..c3a839a9bf812 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:29:5 + --> $DIR/unit_arg.rs:30:5 | LL | / foo({ LL | | 1; @@ -20,7 +20,7 @@ LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:32:5 + --> $DIR/unit_arg.rs:33:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:33:5 + --> $DIR/unit_arg.rs:34:5 | LL | / foo({ LL | | foo(1); @@ -54,7 +54,7 @@ LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:38:5 + --> $DIR/unit_arg.rs:39:5 | LL | / b.bar({ LL | | 1; @@ -74,7 +74,7 @@ LL | b.bar(()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:41:5 + --> $DIR/unit_arg.rs:42:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:42:5 + --> $DIR/unit_arg.rs:43:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -110,7 +110,7 @@ LL | taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:46:5 + --> $DIR/unit_arg.rs:47:5 | LL | / taking_multiple_units( LL | | { @@ -140,7 +140,7 @@ LL | foo(2); ... error: passing a unit value to a function - --> $DIR/unit_arg.rs:57:13 + --> $DIR/unit_arg.rs:58:13 | LL | None.or(Some(foo(2))); | ^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | }); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:60:5 + --> $DIR/unit_arg.rs:61:5 | LL | foo(foo(())) | ^^^^^^^^^^^^ @@ -166,7 +166,7 @@ LL | foo(()) | error: passing a unit value to a function - --> $DIR/unit_arg.rs:93:5 + --> $DIR/unit_arg.rs:94:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.rs b/src/tools/clippy/tests/ui/unnecessary_clone.rs index e785ac02feb32..6770a7fac90fd 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.rs +++ b/src/tools/clippy/tests/ui/unnecessary_clone.rs @@ -1,7 +1,7 @@ // does not test any rustfixable lints #![warn(clippy::clone_on_ref_ptr)] -#![allow(unused, clippy::redundant_clone)] +#![allow(unused, clippy::redundant_clone, clippy::unnecessary_wraps)] use std::cell::RefCell; use std::rc::{self, Rc}; diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs new file mode 100644 index 0000000000000..2e923bc97a2ef --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -0,0 +1,18 @@ +#![warn(clippy::unnecessary_lazy_evaluations)] + +struct Deep(Option); + +#[derive(Copy, Clone)] +struct SomeStruct { + some_field: usize, +} + +fn main() { + // fix will break type inference + let _ = Ok(1).unwrap_or_else(|()| 2); + mod e { + pub struct E; + } + let _ = Ok(1).unwrap_or_else(|e::E| 2); + let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr new file mode 100644 index 0000000000000..581d641cbf54b --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -0,0 +1,22 @@ +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:12:13 + | +LL | let _ = Ok(1).unwrap_or_else(|()| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + | + = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:16:13 + | +LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:17:13 + | +LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.rs b/src/tools/clippy/tests/ui/unnecessary_wraps.rs new file mode 100644 index 0000000000000..a53dec8f91ac5 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.rs @@ -0,0 +1,116 @@ +#![warn(clippy::unnecessary_wraps)] +#![allow(clippy::no_effect)] +#![allow(clippy::needless_return)] +#![allow(clippy::if_same_then_else)] +#![allow(dead_code)] + +// should be linted +fn func1(a: bool, b: bool) -> Option { + if a && b { + return Some(42); + } + if a { + Some(-1); + Some(2) + } else { + return Some(1337); + } +} + +// should be linted +fn func2(a: bool, b: bool) -> Option { + if a && b { + return Some(10); + } + if a { + Some(20) + } else { + Some(30) + } +} + +// public fns should not be linted +pub fn func3(a: bool) -> Option { + if a { + Some(1) + } else { + Some(1) + } +} + +// should not be linted +fn func4(a: bool) -> Option { + if a { + Some(1) + } else { + None + } +} + +// should be linted +fn func5() -> Option { + Some(1) +} + +// should not be linted +fn func6() -> Option { + None +} + +// should be linted +fn func7() -> Result { + Ok(1) +} + +// should not be linted +fn func8(a: bool) -> Result { + if a { + Ok(1) + } else { + Err(()) + } +} + +// should not be linted +fn func9(a: bool) -> Result { + Err(()) +} + +// should not be linted +fn func10() -> Option<()> { + unimplemented!() +} + +struct A; + +impl A { + // should not be linted + pub fn func11() -> Option { + Some(1) + } + + // should be linted + fn func12() -> Option { + Some(1) + } +} + +trait B { + // trait impls are not linted + fn func13() -> Option { + Some(1) + } +} + +impl B for A { + // trait impls are not linted + fn func13() -> Option { + Some(0) + } +} + +fn main() { + // method calls are not linted + func1(true, true); + func2(true, true); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr new file mode 100644 index 0000000000000..410f054b8efca --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr @@ -0,0 +1,106 @@ +error: this function's return value is unnecessarily wrapped by `Option` + --> $DIR/unnecessary_wraps.rs:8:1 + | +LL | / fn func1(a: bool, b: bool) -> Option { +LL | | if a && b { +LL | | return Some(42); +LL | | } +... | +LL | | } +LL | | } + | |_^ + | + = note: `-D clippy::unnecessary-wraps` implied by `-D warnings` +help: remove `Option` from the return type... + | +LL | fn func1(a: bool, b: bool) -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | return 42; +LL | } +LL | if a { +LL | Some(-1); +LL | 2 +LL | } else { + ... + +error: this function's return value is unnecessarily wrapped by `Option` + --> $DIR/unnecessary_wraps.rs:21:1 + | +LL | / fn func2(a: bool, b: bool) -> Option { +LL | | if a && b { +LL | | return Some(10); +LL | | } +... | +LL | | } +LL | | } + | |_^ + | +help: remove `Option` from the return type... + | +LL | fn func2(a: bool, b: bool) -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | return 10; +LL | } +LL | if a { +LL | 20 +LL | } else { +LL | 30 + | + +error: this function's return value is unnecessarily wrapped by `Option` + --> $DIR/unnecessary_wraps.rs:51:1 + | +LL | / fn func5() -> Option { +LL | | Some(1) +LL | | } + | |_^ + | +help: remove `Option` from the return type... + | +LL | fn func5() -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | 1 + | + +error: this function's return value is unnecessarily wrapped by `Result` + --> $DIR/unnecessary_wraps.rs:61:1 + | +LL | / fn func7() -> Result { +LL | | Ok(1) +LL | | } + | |_^ + | +help: remove `Result` from the return type... + | +LL | fn func7() -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | 1 + | + +error: this function's return value is unnecessarily wrapped by `Option` + --> $DIR/unnecessary_wraps.rs:93:5 + | +LL | / fn func12() -> Option { +LL | | Some(1) +LL | | } + | |_____^ + | +help: remove `Option` from the return type... + | +LL | fn func12() -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | 1 + | + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 8a9b0cd3cf019..03977de9455eb 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -1,6 +1,7 @@ // run-rustfix #![deny(clippy::useless_conversion)] +#![allow(clippy::unnecessary_wraps)] fn test_generic(val: T) -> T { let _ = val; diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index 4faa1572973bc..f6e094c16616c 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -1,6 +1,7 @@ // run-rustfix #![deny(clippy::useless_conversion)] +#![allow(clippy::unnecessary_wraps)] fn test_generic(val: T) -> T { let _ = T::from(val); diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index 11c6efb25ccea..26a33595031bd 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> $DIR/useless_conversion.rs:6:13 + --> $DIR/useless_conversion.rs:7:13 | LL | let _ = T::from(val); | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` @@ -11,61 +11,61 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> $DIR/useless_conversion.rs:7:5 + --> $DIR/useless_conversion.rs:8:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:19:22 + --> $DIR/useless_conversion.rs:20:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:60:21 + --> $DIR/useless_conversion.rs:61:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:61:21 + --> $DIR/useless_conversion.rs:62:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:62:13 + --> $DIR/useless_conversion.rs:63:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:63:13 + --> $DIR/useless_conversion.rs:64:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines` - --> $DIR/useless_conversion.rs:64:13 + --> $DIR/useless_conversion.rs:65:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter` - --> $DIR/useless_conversion.rs:65:13 + --> $DIR/useless_conversion.rs:66:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:66:21 + --> $DIR/useless_conversion.rs:67:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:71:13 + --> $DIR/useless_conversion.rs:72:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` diff --git a/src/tools/clippy/tests/ui/vec_box_sized.fixed b/src/tools/clippy/tests/ui/vec_box_sized.fixed index d0bee2460dd84..4fa28b525c3c2 100644 --- a/src/tools/clippy/tests/ui/vec_box_sized.fixed +++ b/src/tools/clippy/tests/ui/vec_box_sized.fixed @@ -35,4 +35,18 @@ mod should_not_trigger { } } +mod inner_mod { + mod inner { + pub struct S; + } + + mod inner2 { + use super::inner::S; + + pub fn f() -> Vec { + vec![] + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/vec_box_sized.rs b/src/tools/clippy/tests/ui/vec_box_sized.rs index 500a0ae263ea5..7dc735cd90be7 100644 --- a/src/tools/clippy/tests/ui/vec_box_sized.rs +++ b/src/tools/clippy/tests/ui/vec_box_sized.rs @@ -35,4 +35,18 @@ mod should_not_trigger { } } +mod inner_mod { + mod inner { + pub struct S; + } + + mod inner2 { + use super::inner::S; + + pub fn f() -> Vec> { + vec![] + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/vec_box_sized.stderr b/src/tools/clippy/tests/ui/vec_box_sized.stderr index 29bf7069e8adb..57e2f1fdf9a74 100644 --- a/src/tools/clippy/tests/ui/vec_box_sized.stderr +++ b/src/tools/clippy/tests/ui/vec_box_sized.stderr @@ -18,5 +18,11 @@ error: `Vec` is already on the heap, the boxing is unnecessary. LL | struct B(Vec>>); | ^^^^^^^^^^^^^^^ help: try: `Vec` -error: aborting due to 3 previous errors +error: `Vec` is already on the heap, the boxing is unnecessary. + --> $DIR/vec_box_sized.rs:46:23 + | +LL | pub fn f() -> Vec> { + | ^^^^^^^^^^^ help: try: `Vec` + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed index 287f8935327c5..ee9c9045fff55 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed @@ -4,6 +4,7 @@ #![warn(clippy::wildcard_imports)] //#![allow(clippy::redundant_pub_crate)] #![allow(unused)] +#![allow(clippy::unnecessary_wraps)] #![warn(unused_imports)] extern crate wildcard_imports_helper; diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs index 1f261159f4a94..efaa8f9ef6641 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.rs +++ b/src/tools/clippy/tests/ui/wildcard_imports.rs @@ -4,6 +4,7 @@ #![warn(clippy::wildcard_imports)] //#![allow(clippy::redundant_pub_crate)] #![allow(unused)] +#![allow(clippy::unnecessary_wraps)] #![warn(unused_imports)] extern crate wildcard_imports_helper; diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr index 351988f31ead5..66267dd27b84f 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr @@ -1,5 +1,5 @@ error: usage of wildcard import - --> $DIR/wildcard_imports.rs:11:5 + --> $DIR/wildcard_imports.rs:12:5 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` @@ -7,85 +7,85 @@ LL | use crate::fn_mod::*; = note: `-D clippy::wildcard-imports` implied by `-D warnings` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:12:5 + --> $DIR/wildcard_imports.rs:13:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:13:5 + --> $DIR/wildcard_imports.rs:14:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:15:5 + --> $DIR/wildcard_imports.rs:16:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:19:5 + --> $DIR/wildcard_imports.rs:20:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:20:5 + --> $DIR/wildcard_imports.rs:21:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:91:13 + --> $DIR/wildcard_imports.rs:92:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:97:75 + --> $DIR/wildcard_imports.rs:98:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:98:13 + --> $DIR/wildcard_imports.rs:99:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:109:20 + --> $DIR/wildcard_imports.rs:110:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:109:30 + --> $DIR/wildcard_imports.rs:110:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:116:13 + --> $DIR/wildcard_imports.rs:117:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:145:9 + --> $DIR/wildcard_imports.rs:146:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:154:9 + --> $DIR/wildcard_imports.rs:155:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:155:9 + --> $DIR/wildcard_imports.rs:156:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,31 +93,31 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:166:13 + --> $DIR/wildcard_imports.rs:167:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:201:17 + --> $DIR/wildcard_imports.rs:202:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:209:13 + --> $DIR/wildcard_imports.rs:210:13 | LL | use super_imports::*; | ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:218:17 + --> $DIR/wildcard_imports.rs:219:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:227:13 + --> $DIR/wildcard_imports.rs:228:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`