diff --git a/crates/cli/src/human.rs b/crates/cli/src/human.rs
index 7c64cac2..07161738 100644
--- a/crates/cli/src/human.rs
+++ b/crates/cli/src/human.rs
@@ -52,7 +52,7 @@ impl error::Error for ParseSizeError {
 }
 
 impl fmt::Display for ParseSizeError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use self::ParseSizeErrorKind::*;
 
         match self.kind {
diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs
index 059f42c4..c9a6aa9c 100644
--- a/crates/cli/src/lib.rs
+++ b/crates/cli/src/lib.rs
@@ -158,18 +158,12 @@ error message is crafted that typically tells the user how to fix the problem.
 
 #![deny(missing_docs)]
 
-extern crate atty;
-extern crate bstr;
-extern crate globset;
+use atty;
+
 #[macro_use]
 extern crate lazy_static;
 #[macro_use]
 extern crate log;
-extern crate regex;
-extern crate same_file;
-extern crate termcolor;
-#[cfg(windows)]
-extern crate winapi_util;
 
 mod decompress;
 mod escape;
diff --git a/crates/cli/src/pattern.rs b/crates/cli/src/pattern.rs
index c59f2801..9662d526 100644
--- a/crates/cli/src/pattern.rs
+++ b/crates/cli/src/pattern.rs
@@ -35,7 +35,7 @@ impl error::Error for InvalidPatternError {
 }
 
 impl fmt::Display for InvalidPatternError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
             f,
             "found invalid UTF-8 in pattern at byte offset {}: {} \
diff --git a/crates/cli/src/process.rs b/crates/cli/src/process.rs
index 42224a92..d0d490c2 100644
--- a/crates/cli/src/process.rs
+++ b/crates/cli/src/process.rs
@@ -47,7 +47,7 @@ impl error::Error for CommandError {
 }
 
 impl fmt::Display for CommandError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.kind {
             CommandErrorKind::Io(ref e) => e.fmt(f),
             CommandErrorKind::Stderr(ref bytes) => {
diff --git a/crates/core/args.rs b/crates/core/args.rs
index ca7d6069..6623cbd5 100644
--- a/crates/core/args.rs
+++ b/crates/core/args.rs
@@ -1720,7 +1720,7 @@ impl ArgMatches {
         self.0.value_of_os(name)
     }
 
-    fn values_of_os(&self, name: &str) -> Option<clap::OsValues> {
+    fn values_of_os(&self, name: &str) -> Option<clap::OsValues<'_>> {
         self.0.values_of_os(name)
     }
 }
diff --git a/crates/core/logger.rs b/crates/core/logger.rs
index f12f0b19..0fe063f1 100644
--- a/crates/core/logger.rs
+++ b/crates/core/logger.rs
@@ -24,13 +24,13 @@ impl Logger {
 }
 
 impl Log for Logger {
-    fn enabled(&self, _: &log::Metadata) -> bool {
+    fn enabled(&self, _: &log::Metadata<'_>) -> bool {
         // We set the log level via log::set_max_level, so we don't need to
         // implement filtering here.
         true
     }
 
-    fn log(&self, record: &log::Record) {
+    fn log(&self, record: &log::Record<'_>) {
         match (record.file(), record.line()) {
             (Some(file), Some(line)) => {
                 eprintln!(
diff --git a/crates/globset/benches/bench.rs b/crates/globset/benches/bench.rs
index 088b48da..c2619813 100644
--- a/crates/globset/benches/bench.rs
+++ b/crates/globset/benches/bench.rs
@@ -4,9 +4,9 @@ tool itself, see the benchsuite directory.
 */
 #![feature(test)]
 
-extern crate glob;
-extern crate globset;
-extern crate regex;
+use glob;
+
+
 extern crate test;
 
 use globset::{Candidate, Glob, GlobMatcher, GlobSet, GlobSetBuilder};
diff --git a/crates/globset/src/glob.rs b/crates/globset/src/glob.rs
index ce7dc665..71cd8bbb 100644
--- a/crates/globset/src/glob.rs
+++ b/crates/globset/src/glob.rs
@@ -98,7 +98,7 @@ impl hash::Hash for Glob {
 }
 
 impl fmt::Display for Glob {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.glob.fmt(f)
     }
 }
@@ -127,7 +127,7 @@ impl GlobMatcher {
     }
 
     /// Tests whether the given path matches this pattern or not.
-    pub fn is_match_candidate(&self, path: &Candidate) -> bool {
+    pub fn is_match_candidate(&self, path: &Candidate<'_>) -> bool {
         self.re.is_match(&path.path)
     }
 
@@ -157,7 +157,7 @@ impl GlobStrategic {
     }
 
     /// Tests whether the given path matches this pattern or not.
-    fn is_match_candidate(&self, candidate: &Candidate) -> bool {
+    fn is_match_candidate(&self, candidate: &Candidate<'_>) -> bool {
         let byte_path = &*candidate.path;
 
         match self.strategy {
diff --git a/crates/globset/src/lib.rs b/crates/globset/src/lib.rs
index 8831dc75..f5273e02 100644
--- a/crates/globset/src/lib.rs
+++ b/crates/globset/src/lib.rs
@@ -103,12 +103,12 @@ or to enable case insensitive matching.
 
 #![deny(missing_docs)]
 
-extern crate aho_corasick;
-extern crate bstr;
-extern crate fnv;
+
+
+use fnv;
 #[macro_use]
 extern crate log;
-extern crate regex;
+use regex;
 
 #[cfg(feature = "serde1")]
 extern crate serde;
@@ -228,7 +228,7 @@ impl ErrorKind {
 }
 
 impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.glob {
             None => self.kind.fmt(f),
             Some(ref glob) => {
@@ -239,7 +239,7 @@ impl fmt::Display for Error {
 }
 
 impl fmt::Display for ErrorKind {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             ErrorKind::InvalidRecursive
             | ErrorKind::UnclosedClass
@@ -317,7 +317,7 @@ impl GlobSet {
     ///
     /// This takes a Candidate as input, which can be used to amortize the
     /// cost of preparing a path for matching.
-    pub fn is_match_candidate(&self, path: &Candidate) -> bool {
+    pub fn is_match_candidate(&self, path: &Candidate<'_>) -> bool {
         if self.is_empty() {
             return false;
         }
@@ -340,7 +340,7 @@ impl GlobSet {
     ///
     /// This takes a Candidate as input, which can be used to amortize the
     /// cost of preparing a path for matching.
-    pub fn matches_candidate(&self, path: &Candidate) -> Vec<usize> {
+    pub fn matches_candidate(&self, path: &Candidate<'_>) -> Vec<usize> {
         let mut into = vec![];
         if self.is_empty() {
             return into;
@@ -374,7 +374,7 @@ impl GlobSet {
     /// cost of preparing a path for matching.
     pub fn matches_candidate_into(
         &self,
-        path: &Candidate,
+        path: &Candidate<'_>,
         into: &mut Vec<usize>,
     ) {
         into.clear();
@@ -543,7 +543,7 @@ enum GlobSetMatchStrategy {
 }
 
 impl GlobSetMatchStrategy {
-    fn is_match(&self, candidate: &Candidate) -> bool {
+    fn is_match(&self, candidate: &Candidate<'_>) -> bool {
         use self::GlobSetMatchStrategy::*;
         match *self {
             Literal(ref s) => s.is_match(candidate),
@@ -556,7 +556,7 @@ impl GlobSetMatchStrategy {
         }
     }
 
-    fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
+    fn matches_into(&self, candidate: &Candidate<'_>, matches: &mut Vec<usize>) {
         use self::GlobSetMatchStrategy::*;
         match *self {
             Literal(ref s) => s.matches_into(candidate, matches),
@@ -582,12 +582,12 @@ impl LiteralStrategy {
         self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index);
     }
 
-    fn is_match(&self, candidate: &Candidate) -> bool {
+    fn is_match(&self, candidate: &Candidate<'_>) -> bool {
         self.0.contains_key(candidate.path.as_bytes())
     }
 
     #[inline(never)]
-    fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
+    fn matches_into(&self, candidate: &Candidate<'_>, matches: &mut Vec<usize>) {
         if let Some(hits) = self.0.get(candidate.path.as_bytes()) {
             matches.extend(hits);
         }
@@ -606,7 +606,7 @@ impl BasenameLiteralStrategy {
         self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index);
     }
 
-    fn is_match(&self, candidate: &Candidate) -> bool {
+    fn is_match(&self, candidate: &Candidate<'_>) -> bool {
         if candidate.basename.is_empty() {
             return false;
         }
@@ -614,7 +614,7 @@ impl BasenameLiteralStrategy {
     }
 
     #[inline(never)]
-    fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
+    fn matches_into(&self, candidate: &Candidate<'_>, matches: &mut Vec<usize>) {
         if candidate.basename.is_empty() {
             return;
         }
@@ -636,7 +636,7 @@ impl ExtensionStrategy {
         self.0.entry(ext.into_bytes()).or_insert(vec![]).push(global_index);
     }
 
-    fn is_match(&self, candidate: &Candidate) -> bool {
+    fn is_match(&self, candidate: &Candidate<'_>) -> bool {
         if candidate.ext.is_empty() {
             return false;
         }
@@ -644,7 +644,7 @@ impl ExtensionStrategy {
     }
 
     #[inline(never)]
-    fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
+    fn matches_into(&self, candidate: &Candidate<'_>, matches: &mut Vec<usize>) {
         if candidate.ext.is_empty() {
             return;
         }
@@ -662,7 +662,7 @@ struct PrefixStrategy {
 }
 
 impl PrefixStrategy {
-    fn is_match(&self, candidate: &Candidate) -> bool {
+    fn is_match(&self, candidate: &Candidate<'_>) -> bool {
         let path = candidate.path_prefix(self.longest);
         for m in self.matcher.find_overlapping_iter(path) {
             if m.start() == 0 {
@@ -672,7 +672,7 @@ impl PrefixStrategy {
         false
     }
 
-    fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
+    fn matches_into(&self, candidate: &Candidate<'_>, matches: &mut Vec<usize>) {
         let path = candidate.path_prefix(self.longest);
         for m in self.matcher.find_overlapping_iter(path) {
             if m.start() == 0 {
@@ -690,7 +690,7 @@ struct SuffixStrategy {
 }
 
 impl SuffixStrategy {
-    fn is_match(&self, candidate: &Candidate) -> bool {
+    fn is_match(&self, candidate: &Candidate<'_>) -> bool {
         let path = candidate.path_suffix(self.longest);
         for m in self.matcher.find_overlapping_iter(path) {
             if m.end() == path.len() {
@@ -700,7 +700,7 @@ impl SuffixStrategy {
         false
     }
 
-    fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
+    fn matches_into(&self, candidate: &Candidate<'_>, matches: &mut Vec<usize>) {
         let path = candidate.path_suffix(self.longest);
         for m in self.matcher.find_overlapping_iter(path) {
             if m.end() == path.len() {
@@ -714,7 +714,7 @@ impl SuffixStrategy {
 struct RequiredExtensionStrategy(HashMap<Vec<u8>, Vec<(usize, Regex)>, Fnv>);
 
 impl RequiredExtensionStrategy {
-    fn is_match(&self, candidate: &Candidate) -> bool {
+    fn is_match(&self, candidate: &Candidate<'_>) -> bool {
         if candidate.ext.is_empty() {
             return false;
         }
@@ -732,7 +732,7 @@ impl RequiredExtensionStrategy {
     }
 
     #[inline(never)]
-    fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
+    fn matches_into(&self, candidate: &Candidate<'_>, matches: &mut Vec<usize>) {
         if candidate.ext.is_empty() {
             return;
         }
@@ -753,11 +753,11 @@ struct RegexSetStrategy {
 }
 
 impl RegexSetStrategy {
-    fn is_match(&self, candidate: &Candidate) -> bool {
+    fn is_match(&self, candidate: &Candidate<'_>) -> bool {
         self.matcher.is_match(candidate.path.as_bytes())
     }
 
-    fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
+    fn matches_into(&self, candidate: &Candidate<'_>, matches: &mut Vec<usize>) {
         for i in self.matcher.matches(candidate.path.as_bytes()) {
             matches.push(self.map[i]);
         }
diff --git a/crates/globset/src/pathutil.rs b/crates/globset/src/pathutil.rs
index 26b496d3..2bd34e1d 100644
--- a/crates/globset/src/pathutil.rs
+++ b/crates/globset/src/pathutil.rs
@@ -60,7 +60,7 @@ pub fn file_name_ext<'a>(name: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
 /// Normalizes a path to use `/` as a separator everywhere, even on platforms
 /// that recognize other characters as separators.
 #[cfg(unix)]
-pub fn normalize_path(path: Cow<[u8]>) -> Cow<[u8]> {
+pub fn normalize_path(path: Cow<'_, [u8]>) -> Cow<'_, [u8]> {
     // UNIX only uses /, so we're good.
     path
 }
diff --git a/crates/grep/examples/simplegrep.rs b/crates/grep/examples/simplegrep.rs
index 749cff26..218b6935 100644
--- a/crates/grep/examples/simplegrep.rs
+++ b/crates/grep/examples/simplegrep.rs
@@ -1,7 +1,3 @@
-extern crate grep;
-extern crate termcolor;
-extern crate walkdir;
-
 use std::env;
 use std::error::Error;
 use std::ffi::OsString;
diff --git a/crates/ignore/examples/walk.rs b/crates/ignore/examples/walk.rs
index 1f2a3cea..969bd1cb 100644
--- a/crates/ignore/examples/walk.rs
+++ b/crates/ignore/examples/walk.rs
@@ -1,6 +1,6 @@
 extern crate crossbeam_channel as channel;
-extern crate ignore;
-extern crate walkdir;
+use ignore;
+use walkdir;
 
 use std::env;
 use std::io::{self, Write};
diff --git a/crates/ignore/src/dir.rs b/crates/ignore/src/dir.rs
index 7a77aad4..18ab9abf 100644
--- a/crates/ignore/src/dir.rs
+++ b/crates/ignore/src/dir.rs
@@ -495,7 +495,7 @@ impl Ignore {
     }
 
     /// Returns an iterator over parent ignore matchers, including this one.
-    pub fn parents(&self) -> Parents {
+    pub fn parents(&self) -> Parents<'_> {
         Parents(Some(self))
     }
 
diff --git a/crates/ignore/src/lib.rs b/crates/ignore/src/lib.rs
index 64b2a8bd..3c82231d 100644
--- a/crates/ignore/src/lib.rs
+++ b/crates/ignore/src/lib.rs
@@ -46,16 +46,16 @@ See the documentation for `WalkBuilder` for many other options.
 
 #![deny(missing_docs)]
 
-extern crate globset;
+
 #[macro_use]
 extern crate lazy_static;
 #[macro_use]
 extern crate log;
-extern crate memchr;
-extern crate regex;
-extern crate same_file;
-extern crate thread_local;
-extern crate walkdir;
+
+
+
+
+use walkdir;
 #[cfg(windows)]
 extern crate winapi_util;
 
@@ -334,7 +334,7 @@ impl error::Error for Error {
 }
 
 impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             Error::Partial(ref errs) => {
                 let msgs: Vec<String> =
diff --git a/crates/ignore/src/walk.rs b/crates/ignore/src/walk.rs
index 2ce66a14..fac8c279 100644
--- a/crates/ignore/src/walk.rs
+++ b/crates/ignore/src/walk.rs
@@ -252,7 +252,7 @@ struct DirEntryRaw {
 }
 
 impl fmt::Debug for DirEntryRaw {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // Leaving out FileType because it doesn't have a debug impl
         // in Rust 1.9. We could add it if we really wanted to by manually
         // querying each possibly file type. Meh. ---AG
@@ -504,7 +504,7 @@ enum Sorter {
 struct Filter(Arc<dyn Fn(&DirEntry) -> bool + Send + Sync + 'static>);
 
 impl fmt::Debug for WalkBuilder {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("WalkBuilder")
             .field("paths", &self.paths)
             .field("ig_builder", &self.ig_builder)
@@ -1226,7 +1226,7 @@ impl WalkParallel {
     /// visitor runs on only one thread, this build-up can be done without
     /// synchronization. Then, once traversal is complete, all of the results
     /// can be merged together into a single data structure.
-    pub fn visit(mut self, builder: &mut dyn ParallelVisitorBuilder) {
+    pub fn visit(mut self, builder: &mut dyn ParallelVisitorBuilder<'_>) {
         let threads = self.threads();
         let stack = Arc::new(Mutex::new(vec![]));
         {
diff --git a/crates/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs b/crates/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs
index b136b986..09ec83ad 100644
--- a/crates/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs
+++ b/crates/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs
@@ -1,5 +1,3 @@
-extern crate ignore;
-
 use std::path::Path;
 
 use ignore::gitignore::{Gitignore, GitignoreBuilder};
diff --git a/crates/matcher/src/interpolate.rs b/crates/matcher/src/interpolate.rs
index 0a73171b..42482ad3 100644
--- a/crates/matcher/src/interpolate.rs
+++ b/crates/matcher/src/interpolate.rs
@@ -92,7 +92,7 @@ impl From<usize> for Ref<'static> {
 /// starting at the beginning of `replacement`.
 ///
 /// If no such valid reference could be found, None is returned.
-fn find_cap_ref(replacement: &[u8]) -> Option<CaptureRef> {
+fn find_cap_ref(replacement: &[u8]) -> Option<CaptureRef<'_>> {
     let mut i = 0;
     if replacement.len() <= 1 || replacement[0] != b'$' {
         return None;
diff --git a/crates/matcher/src/lib.rs b/crates/matcher/src/lib.rs
index 947eb019..92365efb 100644
--- a/crates/matcher/src/lib.rs
+++ b/crates/matcher/src/lib.rs
@@ -38,8 +38,6 @@ implementations.
 
 #![deny(missing_docs)]
 
-extern crate memchr;
-
 use std::fmt;
 use std::io;
 use std::ops;
@@ -304,7 +302,7 @@ pub struct ByteSet(BitSet);
 struct BitSet([u64; 4]);
 
 impl fmt::Debug for BitSet {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut fmtd = f.debug_set();
         for b in (0..256).map(|b| b as u8) {
             if ByteSet(*self).contains(b) {
@@ -494,7 +492,7 @@ impl ::std::error::Error for NoError {
 }
 
 impl fmt::Display for NoError {
-    fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
         panic!("BUG for NoError: an impossible error occurred")
     }
 }
diff --git a/crates/matcher/tests/tests.rs b/crates/matcher/tests/tests.rs
index d58b2009..1affedae 100644
--- a/crates/matcher/tests/tests.rs
+++ b/crates/matcher/tests/tests.rs
@@ -1,6 +1,3 @@
-extern crate grep_matcher;
-extern crate regex;
-
 mod util;
 
 mod test_matcher;
diff --git a/crates/pcre2/src/error.rs b/crates/pcre2/src/error.rs
index 7d0b17bb..921179cd 100644
--- a/crates/pcre2/src/error.rs
+++ b/crates/pcre2/src/error.rs
@@ -50,7 +50,7 @@ impl error::Error for Error {
 }
 
 impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.kind {
             ErrorKind::Regex(ref s) => write!(f, "{}", s),
             ErrorKind::__Nonexhaustive => unreachable!(),
diff --git a/crates/pcre2/src/lib.rs b/crates/pcre2/src/lib.rs
index 37fa04fc..b2e50a7b 100644
--- a/crates/pcre2/src/lib.rs
+++ b/crates/pcre2/src/lib.rs
@@ -5,9 +5,6 @@ An implementation of `grep-matcher`'s `Matcher` trait for
 
 #![deny(missing_docs)]
 
-extern crate grep_matcher;
-extern crate pcre2;
-
 pub use crate::error::{Error, ErrorKind};
 pub use crate::matcher::{RegexCaptures, RegexMatcher, RegexMatcherBuilder};
 pub use pcre2::{is_jit_available, version};
diff --git a/crates/printer/src/color.rs b/crates/printer/src/color.rs
index fb091465..d1a970ea 100644
--- a/crates/printer/src/color.rs
+++ b/crates/printer/src/color.rs
@@ -60,7 +60,7 @@ impl ColorError {
 }
 
 impl fmt::Display for ColorError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             ColorError::UnrecognizedOutType(ref name) => write!(
                 f,
diff --git a/crates/printer/src/json.rs b/crates/printer/src/json.rs
index 5cf3229a..8443551b 100644
--- a/crates/printer/src/json.rs
+++ b/crates/printer/src/json.rs
@@ -507,7 +507,10 @@ impl<W: io::Write> JSON<W> {
 
     /// Write the given message followed by a new line. The new line is
     /// determined from the configuration of the given searcher.
-    fn write_message(&mut self, message: &jsont::Message) -> io::Result<()> {
+    fn write_message(
+        &mut self,
+        message: &jsont::Message<'_>,
+    ) -> io::Result<()> {
         if self.config.pretty {
             json::to_writer_pretty(&mut self.wtr, message)?;
         } else {
@@ -552,7 +555,7 @@ impl<W> JSON<W> {
 /// * `W` refers to the underlying writer that this printer is writing its
 ///   output to.
 #[derive(Debug)]
-pub struct JSONSink<'p, 's, M: Matcher, W: 's> {
+pub struct JSONSink<'p, 's, M: Matcher, W> {
     matcher: M,
     json: &'s mut JSON<W>,
     path: Option<&'p Path>,
@@ -682,7 +685,7 @@ impl<'p, 's, M: Matcher, W: io::Write> Sink for JSONSink<'p, 's, M, W> {
     fn matched(
         &mut self,
         searcher: &Searcher,
-        mat: &SinkMatch,
+        mat: &SinkMatch<'_>,
     ) -> Result<bool, io::Error> {
         self.write_begin_message()?;
 
@@ -724,7 +727,7 @@ impl<'p, 's, M: Matcher, W: io::Write> Sink for JSONSink<'p, 's, M, W> {
     fn context(
         &mut self,
         searcher: &Searcher,
-        ctx: &SinkContext,
+        ctx: &SinkContext<'_>,
     ) -> Result<bool, io::Error> {
         self.write_begin_message()?;
         self.json.matches.clear();
@@ -836,7 +839,7 @@ impl<'a> SubMatches<'a> {
     }
 
     /// Return this set of match ranges as a slice.
-    fn as_slice(&self) -> &[jsont::SubMatch] {
+    fn as_slice(&self) -> &[jsont::SubMatch<'_>] {
         match *self {
             SubMatches::Empty => &[],
             SubMatches::Small(ref x) => x,
diff --git a/crates/printer/src/jsont.rs b/crates/printer/src/jsont.rs
index 878d9691..47a99f3b 100644
--- a/crates/printer/src/jsont.rs
+++ b/crates/printer/src/jsont.rs
@@ -90,7 +90,7 @@ enum Data<'a> {
 }
 
 impl<'a> Data<'a> {
-    fn from_bytes(bytes: &[u8]) -> Data {
+    fn from_bytes(bytes: &[u8]) -> Data<'_> {
         match str::from_utf8(bytes) {
             Ok(text) => Data::Text { text: Cow::Borrowed(text) },
             Err(_) => Data::Bytes { bytes },
@@ -98,7 +98,7 @@ impl<'a> Data<'a> {
     }
 
     #[cfg(unix)]
-    fn from_path(path: &Path) -> Data {
+    fn from_path(path: &Path) -> Data<'_> {
         use std::os::unix::ffi::OsStrExt;
 
         match path.to_str() {
diff --git a/crates/printer/src/lib.rs b/crates/printer/src/lib.rs
index 86515ebf..04f4cf21 100644
--- a/crates/printer/src/lib.rs
+++ b/crates/printer/src/lib.rs
@@ -70,19 +70,17 @@ fn example() -> Result<(), Box<Error>> {
 
 #[cfg(feature = "serde1")]
 extern crate base64;
-extern crate bstr;
-extern crate grep_matcher;
-#[cfg(test)]
-extern crate grep_regex;
-extern crate grep_searcher;
-#[cfg(feature = "serde1")]
-extern crate serde;
+
+
+
+
+
 #[cfg(feature = "serde1")]
 #[macro_use]
 extern crate serde_derive;
 #[cfg(feature = "serde1")]
 extern crate serde_json;
-extern crate termcolor;
+
 
 pub use crate::color::{
     default_color_specs, ColorError, ColorSpecs, UserColorSpec,
diff --git a/crates/printer/src/standard.rs b/crates/printer/src/standard.rs
index 5ff84bb1..df4447cc 100644
--- a/crates/printer/src/standard.rs
+++ b/crates/printer/src/standard.rs
@@ -625,7 +625,7 @@ impl<W> Standard<W> {
 /// * `W` refers to the underlying writer that this printer is writing its
 ///   output to.
 #[derive(Debug)]
-pub struct StandardSink<'p, 's, M: Matcher, W: 's> {
+pub struct StandardSink<'p, 's, M: Matcher, W> {
     matcher: M,
     standard: &'s mut Standard<W>,
     replacer: Replacer<M>,
@@ -784,7 +784,7 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for StandardSink<'p, 's, M, W> {
     fn matched(
         &mut self,
         searcher: &Searcher,
-        mat: &SinkMatch,
+        mat: &SinkMatch<'_>,
     ) -> Result<bool, io::Error> {
         self.match_count += 1;
         // When we've exceeded our match count, then the remaining context
@@ -825,7 +825,7 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for StandardSink<'p, 's, M, W> {
     fn context(
         &mut self,
         searcher: &Searcher,
-        ctx: &SinkContext,
+        ctx: &SinkContext<'_>,
     ) -> Result<bool, io::Error> {
         self.standard.matches.clear();
         self.replacer.clear();
@@ -904,7 +904,7 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for StandardSink<'p, 's, M, W> {
 /// A StandardImpl is initialized every time a match or a contextual line is
 /// reported.
 #[derive(Debug)]
-struct StandardImpl<'a, M: 'a + Matcher, W: 'a> {
+struct StandardImpl<'a, M: Matcher, W> {
     searcher: &'a Searcher,
     sink: &'a StandardSink<'a, 'a, M, W>,
     sunk: Sunk<'a>,
@@ -916,7 +916,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
     /// Bundle self with a searcher and return the core implementation of Sink.
     fn new(
         searcher: &'a Searcher,
-        sink: &'a StandardSink<M, W>,
+        sink: &'a StandardSink<'_, '_, M, W>,
     ) -> StandardImpl<'a, M, W> {
         StandardImpl {
             searcher: searcher,
@@ -930,7 +930,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
     /// for use with handling matching lines.
     fn from_match(
         searcher: &'a Searcher,
-        sink: &'a StandardSink<M, W>,
+        sink: &'a StandardSink<'_, '_, M, W>,
         mat: &'a SinkMatch<'a>,
     ) -> StandardImpl<'a, M, W> {
         let sunk = Sunk::from_sink_match(
@@ -945,7 +945,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
     /// for use with handling contextual lines.
     fn from_context(
         searcher: &'a Searcher,
-        sink: &'a StandardSink<M, W>,
+        sink: &'a StandardSink<'_, '_, M, W>,
         ctx: &'a SinkContext<'a>,
     ) -> StandardImpl<'a, M, W> {
         let sunk = Sunk::from_sink_context(
diff --git a/crates/printer/src/summary.rs b/crates/printer/src/summary.rs
index a1ba0be3..1477b23e 100644
--- a/crates/printer/src/summary.rs
+++ b/crates/printer/src/summary.rs
@@ -457,7 +457,7 @@ impl<W> Summary<W> {
 /// * `W` refers to the underlying writer that this printer is writing its
 ///   output to.
 #[derive(Debug)]
-pub struct SummarySink<'p, 's, M: Matcher, W: 's> {
+pub struct SummarySink<'p, 's, M: Matcher, W> {
     matcher: M,
     summary: &'s mut Summary<W>,
     path: Option<PrinterPath<'p>>,
@@ -591,7 +591,7 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for SummarySink<'p, 's, M, W> {
     fn matched(
         &mut self,
         searcher: &Searcher,
-        mat: &SinkMatch,
+        mat: &SinkMatch<'_>,
     ) -> Result<bool, io::Error> {
         let is_multi_line = self.multi_line(searcher);
         let sink_match_count = if self.stats.is_none() && !is_multi_line {
diff --git a/crates/printer/src/util.rs b/crates/printer/src/util.rs
index e9129065..434deec7 100644
--- a/crates/printer/src/util.rs
+++ b/crates/printer/src/util.rs
@@ -29,7 +29,7 @@ struct Space<M: Matcher> {
 }
 
 impl<M: Matcher> fmt::Debug for Replacer<M> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let (dst, matches) = self.replacement().unwrap_or((&[], &[]));
         f.debug_struct("Replacer")
             .field("dst", &dst)
@@ -330,7 +330,7 @@ impl<'a> PrinterPath<'a> {
 pub struct NiceDuration(pub time::Duration);
 
 impl fmt::Display for NiceDuration {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{:0.6}s", self.fractional_seconds())
     }
 }
diff --git a/crates/regex/src/error.rs b/crates/regex/src/error.rs
index 6eba85ac..c5358551 100644
--- a/crates/regex/src/error.rs
+++ b/crates/regex/src/error.rs
@@ -72,7 +72,7 @@ impl error::Error for Error {
 }
 
 impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.kind {
             ErrorKind::Regex(ref s) => write!(f, "{}", s),
             ErrorKind::NotAllowed(ref lit) => {
diff --git a/crates/regex/src/lib.rs b/crates/regex/src/lib.rs
index 36efa858..aae98809 100644
--- a/crates/regex/src/lib.rs
+++ b/crates/regex/src/lib.rs
@@ -4,14 +4,14 @@ An implementation of `grep-matcher`'s `Matcher` trait for Rust's regex engine.
 
 #![deny(missing_docs)]
 
-extern crate aho_corasick;
-extern crate bstr;
-extern crate grep_matcher;
+
+
+
 #[macro_use]
 extern crate log;
-extern crate regex;
-extern crate regex_syntax;
-extern crate thread_local;
+
+
+
 
 pub use crate::error::{Error, ErrorKind};
 pub use crate::matcher::{RegexCaptures, RegexMatcher, RegexMatcherBuilder};
diff --git a/crates/searcher/examples/search-stdin.rs b/crates/searcher/examples/search-stdin.rs
index cd0bc4e8..8034ae6c 100644
--- a/crates/searcher/examples/search-stdin.rs
+++ b/crates/searcher/examples/search-stdin.rs
@@ -1,6 +1,3 @@
-extern crate grep_regex;
-extern crate grep_searcher;
-
 use std::env;
 use std::error::Error;
 use std::io;
diff --git a/crates/searcher/src/lib.rs b/crates/searcher/src/lib.rs
index c17f47f8..49c7e2a4 100644
--- a/crates/searcher/src/lib.rs
+++ b/crates/searcher/src/lib.rs
@@ -99,16 +99,8 @@ searches stdin.
 
 #![deny(missing_docs)]
 
-extern crate bstr;
-extern crate bytecount;
-extern crate encoding_rs;
-extern crate encoding_rs_io;
-extern crate grep_matcher;
 #[macro_use]
 extern crate log;
-extern crate memmap;
-#[cfg(test)]
-extern crate regex;
 
 pub use crate::lines::{LineIter, LineStep};
 pub use crate::searcher::{
diff --git a/crates/searcher/src/searcher/glue.rs b/crates/searcher/src/searcher/glue.rs
index 14d09feb..21a58aa4 100644
--- a/crates/searcher/src/searcher/glue.rs
+++ b/crates/searcher/src/searcher/glue.rs
@@ -10,7 +10,7 @@ use crate::searcher::core::Core;
 use crate::searcher::{Config, Range, Searcher};
 
 #[derive(Debug)]
-pub struct ReadByLine<'s, M: 's, R, S> {
+pub struct ReadByLine<'s, M, R, S> {
     config: &'s Config,
     core: Core<'s, M, S>,
     rdr: LineBufferReader<'s, R>,
@@ -87,7 +87,7 @@ where
 }
 
 #[derive(Debug)]
-pub struct SliceByLine<'s, M: 's, S> {
+pub struct SliceByLine<'s, M, S> {
     config: &'s Config,
     core: Core<'s, M, S>,
     slice: &'s [u8],
@@ -134,7 +134,7 @@ impl<'s, M: Matcher, S: Sink> SliceByLine<'s, M, S> {
 }
 
 #[derive(Debug)]
-pub struct MultiLine<'s, M: 's, S> {
+pub struct MultiLine<'s, M, S> {
     config: &'s Config,
     core: Core<'s, M, S>,
     slice: &'s [u8],
diff --git a/crates/searcher/src/searcher/mod.rs b/crates/searcher/src/searcher/mod.rs
index 917fa374..5f9cc760 100644
--- a/crates/searcher/src/searcher/mod.rs
+++ b/crates/searcher/src/searcher/mod.rs
@@ -263,7 +263,7 @@ impl ::std::error::Error for ConfigError {
 }
 
 impl fmt::Display for ConfigError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             ConfigError::SearchUnavailable => {
                 write!(f, "grep config error: no available searchers")
diff --git a/crates/searcher/src/sink.rs b/crates/searcher/src/sink.rs
index bcbad578..41f425cc 100644
--- a/crates/searcher/src/sink.rs
+++ b/crates/searcher/src/sink.rs
@@ -121,7 +121,7 @@ pub trait Sink {
     fn matched(
         &mut self,
         _searcher: &Searcher,
-        _mat: &SinkMatch,
+        _mat: &SinkMatch<'_>,
     ) -> Result<bool, Self::Error>;
 
     /// This method is called whenever a context line is found, and is optional
@@ -140,7 +140,7 @@ pub trait Sink {
     fn context(
         &mut self,
         _searcher: &Searcher,
-        _context: &SinkContext,
+        _context: &SinkContext<'_>,
     ) -> Result<bool, Self::Error> {
         Ok(true)
     }
@@ -226,7 +226,7 @@ impl<'a, S: Sink> Sink for &'a mut S {
     fn matched(
         &mut self,
         searcher: &Searcher,
-        mat: &SinkMatch,
+        mat: &SinkMatch<'_>,
     ) -> Result<bool, S::Error> {
         (**self).matched(searcher, mat)
     }
@@ -235,7 +235,7 @@ impl<'a, S: Sink> Sink for &'a mut S {
     fn context(
         &mut self,
         searcher: &Searcher,
-        context: &SinkContext,
+        context: &SinkContext<'_>,
     ) -> Result<bool, S::Error> {
         (**self).context(searcher, context)
     }
@@ -279,7 +279,7 @@ impl<S: Sink + ?Sized> Sink for Box<S> {
     fn matched(
         &mut self,
         searcher: &Searcher,
-        mat: &SinkMatch,
+        mat: &SinkMatch<'_>,
     ) -> Result<bool, S::Error> {
         (**self).matched(searcher, mat)
     }
@@ -288,7 +288,7 @@ impl<S: Sink + ?Sized> Sink for Box<S> {
     fn context(
         &mut self,
         searcher: &Searcher,
-        context: &SinkContext,
+        context: &SinkContext<'_>,
     ) -> Result<bool, S::Error> {
         (**self).context(searcher, context)
     }
@@ -545,7 +545,7 @@ pub mod sinks {
         fn matched(
             &mut self,
             _searcher: &Searcher,
-            mat: &SinkMatch,
+            mat: &SinkMatch<'_>,
         ) -> Result<bool, io::Error> {
             let matched = match str::from_utf8(mat.bytes()) {
                 Ok(matched) => matched,
@@ -593,7 +593,7 @@ pub mod sinks {
         fn matched(
             &mut self,
             _searcher: &Searcher,
-            mat: &SinkMatch,
+            mat: &SinkMatch<'_>,
         ) -> Result<bool, io::Error> {
             use std::borrow::Cow;
 
@@ -643,7 +643,7 @@ pub mod sinks {
         fn matched(
             &mut self,
             _searcher: &Searcher,
-            mat: &SinkMatch,
+            mat: &SinkMatch<'_>,
         ) -> Result<bool, io::Error> {
             let line_number = match mat.line_number() {
                 Some(line_number) => line_number,
diff --git a/crates/searcher/src/testutil.rs b/crates/searcher/src/testutil.rs
index 62dc0db2..659f9cd4 100644
--- a/crates/searcher/src/testutil.rs
+++ b/crates/searcher/src/testutil.rs
@@ -129,7 +129,7 @@ impl Sink for KitchenSink {
     fn matched(
         &mut self,
         _searcher: &Searcher,
-        mat: &SinkMatch,
+        mat: &SinkMatch<'_>,
     ) -> Result<bool, io::Error> {
         assert!(!mat.bytes().is_empty());
         assert!(mat.lines().count() >= 1);
@@ -152,7 +152,7 @@ impl Sink for KitchenSink {
     fn context(
         &mut self,
         _searcher: &Searcher,
-        context: &SinkContext,
+        context: &SinkContext<'_>,
     ) -> Result<bool, io::Error> {
         assert!(!context.bytes().is_empty());
         assert!(context.lines().count() == 1);