about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-08-17 20:51:59 +0000
committerbors <bors@rust-lang.org>2020-08-17 20:51:59 +0000
commit792c645ca7d11a8d254df307d019c5bf01445c37 (patch)
tree0d3b37228ed6a094e0ac3bd3b3746b4607a498f9
parent33c96b4d9782cf6364e47cb2c904e66b06c22bb4 (diff)
parentf1ce2948dba9b314b3f0205a6e9b125bdf186b8e (diff)
downloadrust-792c645ca7d11a8d254df307d019c5bf01445c37.tar.gz
rust-792c645ca7d11a8d254df307d019c5bf01445c37.zip
Auto merge of #75145 - davidtwco:issue-60607-preallocate-defid-for-lang-items, r=petrochenkov
Reference lang items during AST lowering

Fixes #60607 and fixes #61019.

This PR introduces `QPath::LangItem` to the HIR and uses it in AST lowering instead of constructing a `hir::Path` from a slice of symbols:

- Credit for much of this work goes to @matthewjasper, I basically just [rebased their earlier work](https://github.com/matthewjasper/rust/commit/a227c706b7809ff07021baf3856b7540d5b57f8a#diff-c0f791ead38d2d02916faaad0f56f41d).
- ~~Changes to Clippy might not be correct, they compile but attempting to run tests through `./x.py` produced failures which appeared spurious, so I didn't run any clippy tests.~~
- Changes to save analysis might not be correct - tests pass but I don't have a lot of confidence in those changes being correct.
- I've used `GenericBounds::LangItemTrait` rather than changing `PolyTraitRef`, as suggested by @matthewjasper [in this comment](https://github.com/matthewjasper/rust/commit/a227c706b7809ff07021baf3856b7540d5b57f8a#r40107992) but I'd prefer that be left for a follow-up.
- I've split things into smaller commits fairly arbitrarily to make the diff easier to review, each commit should compile but might not pass tests until the final commit.

r? @oli-obk
cc @matthewjasper
-rw-r--r--library/core/src/convert/mod.rs1
-rw-r--r--library/core/src/future/future.rs1
-rw-r--r--library/core/src/future/mod.rs2
-rw-r--r--library/core/src/iter/traits/collect.rs1
-rw-r--r--library/core/src/iter/traits/iterator.rs1
-rw-r--r--library/core/src/ops/range.rs7
-rw-r--r--library/core/src/ops/try.rs3
-rw-r--r--library/core/src/option.rs2
-rw-r--r--library/core/src/pin.rs1
-rw-r--r--library/core/src/result.rs2
-rw-r--r--library/core/src/task/poll.rs2
-rw-r--r--src/librustc_ast_lowering/expr.rs161
-rw-r--r--src/librustc_ast_lowering/lib.rs110
-rw-r--r--src/librustc_hir/hir.rs110
-rw-r--r--src/librustc_hir/intravisit.rs5
-rw-r--r--src/librustc_hir/lang_items.rs36
-rw-r--r--src/librustc_hir/target.rs2
-rw-r--r--src/librustc_hir_pretty/lib.rs10
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_lint/context.rs2
-rw-r--r--src/librustc_lint/types.rs4
-rw-r--r--src/librustc_middle/ty/context.rs2
-rw-r--r--src/librustc_passes/lang_items.rs8
-rw-r--r--src/librustc_passes/liveness.rs6
-rw-r--r--src/librustc_privacy/lib.rs6
-rw-r--r--src/librustc_resolve/late/lifetimes.rs28
-rw-r--r--src/librustc_resolve/lib.rs31
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs26
-rw-r--r--src/librustc_save_analysis/lib.rs39
-rw-r--r--src/librustc_save_analysis/sig.rs3
-rw-r--r--src/librustc_span/symbol.rs2
-rw-r--r--src/librustc_typeck/astconv.rs46
-rw-r--r--src/librustc_typeck/check/demand.rs2
-rw-r--r--src/librustc_typeck/check/expr.rs18
-rw-r--r--src/librustc_typeck/check/mod.rs38
-rw-r--r--src/librustc_typeck/check/pat.rs8
-rw-r--r--src/librustc_typeck/collect.rs26
-rw-r--r--src/librustdoc/clean/mod.rs20
-rw-r--r--src/librustdoc/clean/utils.rs1
-rw-r--r--src/test/ui/hygiene/hir-res-hygiene.rs18
-rw-r--r--src/test/ui/range/range-1.stderr6
-rw-r--r--src/tools/clippy/clippy_lints/src/default_trait_access.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/match_on_vec_items.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/try_err.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/types.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/higher.rs98
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/hir_utils.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/inspector.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/paths.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/sugg.rs8
-rw-r--r--src/tools/clippy/tests/ui/author/for_loop.stdout16
61 files changed, 588 insertions, 458 deletions
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 03b798d57db..fcd07befae5 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -385,6 +385,7 @@ pub trait Into<T>: Sized {
 ))]
 pub trait From<T>: Sized {
     /// Performs the conversion.
+    #[cfg_attr(not(bootstrap), lang = "from")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn from(_: T) -> Self;
 }
diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs
index 733ebdc0e97..8169c146137 100644
--- a/library/core/src/future/future.rs
+++ b/library/core/src/future/future.rs
@@ -96,6 +96,7 @@ pub trait Future {
     /// [`Context`]: ../task/struct.Context.html
     /// [`Waker`]: ../task/struct.Waker.html
     /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake
+    #[cfg_attr(not(bootstrap), lang = "poll")]
     #[stable(feature = "futures_api", since = "1.36.0")]
     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
 }
diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index 6d1ad9db744..d44ef857c13 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -53,6 +53,7 @@ unsafe impl Sync for ResumeTy {}
 /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
 /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
 // This is `const` to avoid extra errors after we recover from `const async fn`
+#[cfg_attr(not(bootstrap), lang = "from_generator")]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[inline]
@@ -85,6 +86,7 @@ where
     GenFuture(gen)
 }
 
+#[cfg_attr(not(bootstrap), lang = "get_context")]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[inline]
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 9d20022b6ed..84c7787a18f 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -235,6 +235,7 @@ pub trait IntoIterator {
     /// assert_eq!(Some(3), iter.next());
     /// assert_eq!(None, iter.next());
     /// ```
+    #[cfg_attr(not(bootstrap), lang = "into_iter")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn into_iter(self) -> Self::IntoIter;
 }
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index f89b616c4e2..81d8f27ec19 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -129,6 +129,7 @@ pub trait Iterator {
     /// assert_eq!(None, iter.next());
     /// assert_eq!(None, iter.next());
     /// ```
+    #[cfg_attr(not(bootstrap), lang = "next")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn next(&mut self) -> Option<Self::Item>;
 
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index 179038d1977..e9ab82b5398 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -38,6 +38,7 @@ use crate::hash::Hash;
 /// [`IntoIterator`]: ../iter/trait.Iterator.html
 /// [`Iterator`]: ../iter/trait.IntoIterator.html
 /// [slicing index]: ../slice/trait.SliceIndex.html
+#[cfg_attr(not(bootstrap), lang = "RangeFull")]
 #[doc(alias = "..")]
 #[derive(Copy, Clone, Default, PartialEq, Eq, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -70,6 +71,7 @@ impl fmt::Debug for RangeFull {
 /// assert_eq!(arr[1.. 3], [  1,2    ]);  // Range
 /// assert_eq!(arr[1..=3], [  1,2,3  ]);
 /// ```
+#[cfg_attr(not(bootstrap), lang = "Range")]
 #[doc(alias = "..")]
 #[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -178,6 +180,7 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
 /// ```
 ///
 /// [`Iterator`]: ../iter/trait.IntoIterator.html
+#[cfg_attr(not(bootstrap), lang = "RangeFrom")]
 #[doc(alias = "..")]
 #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -260,6 +263,7 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
 /// [`IntoIterator`]: ../iter/trait.Iterator.html
 /// [`Iterator`]: ../iter/trait.IntoIterator.html
 /// [slicing index]: ../slice/trait.SliceIndex.html
+#[cfg_attr(not(bootstrap), lang = "RangeTo")]
 #[doc(alias = "..")]
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -328,6 +332,7 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
 /// assert_eq!(arr[1.. 3], [  1,2    ]);
 /// assert_eq!(arr[1..=3], [  1,2,3  ]);  // RangeInclusive
 /// ```
+#[cfg_attr(not(bootstrap), lang = "RangeInclusive")]
 #[doc(alias = "..=")]
 #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
 #[stable(feature = "inclusive_range", since = "1.26.0")]
@@ -359,6 +364,7 @@ impl<Idx> RangeInclusive<Idx> {
     ///
     /// assert_eq!(3..=5, RangeInclusive::new(3, 5));
     /// ```
+    #[cfg_attr(not(bootstrap), lang = "range_inclusive_new")]
     #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     #[rustc_promotable]
@@ -555,6 +561,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
 /// [`IntoIterator`]: ../iter/trait.Iterator.html
 /// [`Iterator`]: ../iter/trait.IntoIterator.html
 /// [slicing index]: ../slice/trait.SliceIndex.html
+#[cfg_attr(not(bootstrap), lang = "RangeToInclusive")]
 #[doc(alias = "..=")]
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[stable(feature = "inclusive_range", since = "1.26.0")]
diff --git a/library/core/src/ops/try.rs b/library/core/src/ops/try.rs
index 9bc35ae1f5c..e6b05cc641e 100644
--- a/library/core/src/ops/try.rs
+++ b/library/core/src/ops/try.rs
@@ -43,16 +43,19 @@ pub trait Try {
     /// in the return type of the enclosing scope (which must itself implement
     /// `Try`). Specifically, the value `X::from_error(From::from(e))`
     /// is returned, where `X` is the return type of the enclosing function.
+    #[cfg_attr(not(bootstrap), lang = "into_result")]
     #[unstable(feature = "try_trait", issue = "42327")]
     fn into_result(self) -> Result<Self::Ok, Self::Error>;
 
     /// Wrap an error value to construct the composite result. For example,
     /// `Result::Err(x)` and `Result::from_error(x)` are equivalent.
+    #[cfg_attr(not(bootstrap), lang = "from_error")]
     #[unstable(feature = "try_trait", issue = "42327")]
     fn from_error(v: Self::Error) -> Self;
 
     /// Wrap an OK value to construct the composite result. For example,
     /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent.
+    #[cfg_attr(not(bootstrap), lang = "from_ok")]
     #[unstable(feature = "try_trait", issue = "42327")]
     fn from_ok(v: Self::Ok) -> Self;
 }
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 6d078fb0a54..b6aa2c66971 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -144,9 +144,11 @@ use crate::{
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum Option<T> {
     /// No value
+    #[cfg_attr(not(bootstrap), lang = "None")]
     #[stable(feature = "rust1", since = "1.0.0")]
     None,
     /// Some value `T`
+    #[cfg_attr(not(bootstrap), lang = "Some")]
     #[stable(feature = "rust1", since = "1.0.0")]
     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
 }
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 960cccc0fb2..b63219a4403 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -569,6 +569,7 @@ impl<P: Deref> Pin<P> {
     ///  ```
     ///
     /// [`mem::swap`]: ../../std/mem/fn.swap.html
+    #[cfg_attr(not(bootstrap), lang = "new_unchecked")]
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub unsafe fn new_unchecked(pointer: P) -> Pin<P> {
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index e68dbf5215f..5eddcb2172a 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -246,10 +246,12 @@ use crate::{convert, fmt};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum Result<T, E> {
     /// Contains the success value
+    #[cfg_attr(not(bootstrap), lang = "Ok")]
     #[stable(feature = "rust1", since = "1.0.0")]
     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
 
     /// Contains the error value
+    #[cfg_attr(not(bootstrap), lang = "Err")]
     #[stable(feature = "rust1", since = "1.0.0")]
     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
 }
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index b3a4bd20b8f..fea396d20ff 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -10,6 +10,7 @@ use crate::result::Result;
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub enum Poll<T> {
     /// Represents that a value is immediately ready.
+    #[cfg_attr(not(bootstrap), lang = "Ready")]
     #[stable(feature = "futures_api", since = "1.36.0")]
     Ready(#[stable(feature = "futures_api", since = "1.36.0")] T),
 
@@ -18,6 +19,7 @@ pub enum Poll<T> {
     /// When a function returns `Pending`, the function *must* also
     /// ensure that the current task is scheduled to be awoken when
     /// progress can be made.
+    #[cfg_attr(not(bootstrap), lang = "Pending")]
     #[stable(feature = "futures_api", since = "1.36.0")]
     Pending,
 }
diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index f9e54903a66..65c9cd2e203 100644
--- a/src/librustc_ast_lowering/expr.rs
+++ b/src/librustc_ast_lowering/expr.rs
@@ -449,7 +449,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
             // `::std::ops::Try::from_ok($tail_expr)`
             block.expr = Some(this.wrap_in_try_constructor(
-                sym::from_ok,
+                hir::LangItem::TryFromOk,
                 try_span,
                 tail_expr,
                 ok_wrapped_span,
@@ -461,14 +461,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn wrap_in_try_constructor(
         &mut self,
-        method: Symbol,
+        lang_item: hir::LangItem,
         method_span: Span,
         expr: &'hir hir::Expr<'hir>,
         overall_span: Span,
     ) -> &'hir hir::Expr<'hir> {
-        let path = &[sym::ops, sym::Try, method];
         let constructor =
-            self.arena.alloc(self.expr_std_path(method_span, path, None, ThinVec::new()));
+            self.arena.alloc(self.expr_lang_item_path(method_span, lang_item, ThinVec::new()));
         self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
     }
 
@@ -558,12 +557,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // `future::from_generator`:
         let unstable_span =
             self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
-        let gen_future = self.expr_std_path(
-            unstable_span,
-            &[sym::future, sym::from_generator],
-            None,
-            ThinVec::new(),
-        );
+        let gen_future =
+            self.expr_lang_item_path(unstable_span, hir::LangItem::FromGenerator, ThinVec::new());
 
         // `future::from_generator(generator)`:
         hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator])
@@ -630,23 +625,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 // Use of `await` outside of an async context, we cannot use `task_context` here.
                 self.expr_err(span)
             };
-            let pin_ty_id = self.next_id();
-            let new_unchecked_expr_kind = self.expr_call_std_assoc_fn(
-                pin_ty_id,
+            let new_unchecked = self.expr_call_lang_item_fn_mut(
                 span,
-                &[sym::pin, sym::Pin],
-                "new_unchecked",
+                hir::LangItem::PinNewUnchecked,
                 arena_vec![self; ref_mut_pinned],
             );
-            let new_unchecked = self.expr(span, new_unchecked_expr_kind, ThinVec::new());
-            let get_context = self.expr_call_std_path_mut(
+            let get_context = self.expr_call_lang_item_fn_mut(
                 gen_future_span,
-                &[sym::future, sym::get_context],
+                hir::LangItem::GetContext,
                 arena_vec![self; task_context],
             );
-            let call = self.expr_call_std_path(
+            let call = self.expr_call_lang_item_fn(
                 span,
-                &[sym::future, sym::Future, sym::poll],
+                hir::LangItem::FuturePoll,
                 arena_vec![self; new_unchecked, get_context],
             );
             self.arena.alloc(self.expr_unsafe(call))
@@ -659,11 +650,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let x_ident = Ident::with_dummy_span(sym::result);
             let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
             let x_expr = self.expr_ident(span, x_ident, x_pat_hid);
-            let ready_pat = self.pat_std_enum(
-                span,
-                &[sym::task, sym::Poll, sym::Ready],
-                arena_vec![self; x_pat],
-            );
+            let ready_field = self.single_pat_field(span, x_pat);
+            let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
             let break_x = self.with_loop_scope(loop_node_id, move |this| {
                 let expr_break =
                     hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
@@ -674,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         // `::std::task::Poll::Pending => {}`
         let pending_arm = {
-            let pending_pat = self.pat_std_enum(span, &[sym::task, sym::Poll, sym::Pending], &[]);
+            let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
             let empty_block = self.expr_block_empty(span);
             self.arm(pending_pat, empty_block)
         };
@@ -842,16 +830,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
     fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
-        let id = self.next_id();
         let e1 = self.lower_expr_mut(e1);
         let e2 = self.lower_expr_mut(e2);
-        self.expr_call_std_assoc_fn(
-            id,
-            span,
-            &[sym::ops, sym::RangeInclusive],
-            "new",
-            arena_vec![self; e1, e2],
-        )
+        let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span);
+        let fn_expr =
+            self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
+        hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
     }
 
     fn lower_expr_range(
@@ -863,12 +847,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
     ) -> hir::ExprKind<'hir> {
         use rustc_ast::ast::RangeLimits::*;
 
-        let path = match (e1, e2, lims) {
-            (None, None, HalfOpen) => sym::RangeFull,
-            (Some(..), None, HalfOpen) => sym::RangeFrom,
-            (None, Some(..), HalfOpen) => sym::RangeTo,
-            (Some(..), Some(..), HalfOpen) => sym::Range,
-            (None, Some(..), Closed) => sym::RangeToInclusive,
+        let lang_item = match (e1, e2, lims) {
+            (None, None, HalfOpen) => hir::LangItem::RangeFull,
+            (Some(..), None, HalfOpen) => hir::LangItem::RangeFrom,
+            (None, Some(..), HalfOpen) => hir::LangItem::RangeTo,
+            (Some(..), Some(..), HalfOpen) => hir::LangItem::Range,
+            (None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
             (Some(..), Some(..), Closed) => unreachable!(),
             (_, None, Closed) => {
                 self.diagnostic().span_fatal(span, "inclusive range with no end").raise()
@@ -883,16 +867,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }),
         );
 
-        let is_unit = fields.is_empty();
-        let struct_path = [sym::ops, path];
-        let struct_path = self.std_path(span, &struct_path, None, is_unit);
-        let struct_path = hir::QPath::Resolved(None, struct_path);
-
-        if is_unit {
-            hir::ExprKind::Path(struct_path)
-        } else {
-            hir::ExprKind::Struct(self.arena.alloc(struct_path), fields, None)
-        }
+        hir::ExprKind::Struct(self.arena.alloc(hir::QPath::LangItem(lang_item, span)), fields, None)
     }
 
     fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
@@ -1412,9 +1387,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let match_expr = {
             let iter = self.expr_ident(desugared_span, iter, iter_pat_nid);
             let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
-            let next_path = &[sym::iter, sym::Iterator, sym::next];
-            let next_expr =
-                self.expr_call_std_path(desugared_span, next_path, arena_vec![self; ref_mut_iter]);
+            let next_expr = self.expr_call_lang_item_fn(
+                desugared_span,
+                hir::LangItem::IteratorNext,
+                arena_vec![self; ref_mut_iter],
+            );
             let arms = arena_vec![self; pat_arm, break_arm];
 
             self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
@@ -1472,8 +1449,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
         let into_iter_expr = {
-            let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter];
-            self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head])
+            self.expr_call_lang_item_fn(
+                into_iter_span,
+                hir::LangItem::IntoIterIntoIter,
+                arena_vec![self; head],
+            )
         };
 
         let match_expr = self.arena.alloc(self.expr_match(
@@ -1521,8 +1501,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
             // expand <expr>
             let sub_expr = self.lower_expr_mut(sub_expr);
 
-            let path = &[sym::ops, sym::Try, sym::into_result];
-            self.expr_call_std_path(unstable_span, path, arena_vec![self; sub_expr])
+            self.expr_call_lang_item_fn(
+                unstable_span,
+                hir::LangItem::TryIntoResult,
+                arena_vec![self; sub_expr],
+            )
         };
 
         // `#[allow(unreachable_code)]`
@@ -1558,12 +1541,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let err_ident = Ident::with_dummy_span(sym::err);
             let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
             let from_expr = {
-                let from_path = &[sym::convert, sym::From, sym::from];
                 let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid);
-                self.expr_call_std_path(try_span, from_path, arena_vec![self; err_expr])
+                self.expr_call_lang_item_fn(
+                    try_span,
+                    hir::LangItem::FromFrom,
+                    arena_vec![self; err_expr],
+                )
             };
-            let from_err_expr =
-                self.wrap_in_try_constructor(sym::from_error, unstable_span, from_expr, try_span);
+            let from_err_expr = self.wrap_in_try_constructor(
+                hir::LangItem::TryFromError,
+                unstable_span,
+                from_expr,
+                try_span,
+            );
             let thin_attrs = ThinVec::from(attrs);
             let catch_scope = self.catch_scopes.last().copied();
             let ret_expr = if let Some(catch_node) = catch_scope {
@@ -1674,63 +1664,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
         self.arena.alloc(self.expr_call_mut(span, e, args))
     }
 
-    // Note: associated functions must use `expr_call_std_path`.
-    fn expr_call_std_path_mut(
+    fn expr_call_lang_item_fn_mut(
         &mut self,
         span: Span,
-        path_components: &[Symbol],
+        lang_item: hir::LangItem,
         args: &'hir [hir::Expr<'hir>],
     ) -> hir::Expr<'hir> {
-        let path =
-            self.arena.alloc(self.expr_std_path(span, path_components, None, ThinVec::new()));
+        let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new()));
         self.expr_call_mut(span, path, args)
     }
 
-    fn expr_call_std_path(
+    fn expr_call_lang_item_fn(
         &mut self,
         span: Span,
-        path_components: &[Symbol],
+        lang_item: hir::LangItem,
         args: &'hir [hir::Expr<'hir>],
     ) -> &'hir hir::Expr<'hir> {
-        self.arena.alloc(self.expr_call_std_path_mut(span, path_components, args))
-    }
-
-    // Create an expression calling an associated function of an std type.
-    //
-    // Associated functions cannot be resolved through the normal `std_path` function,
-    // as they are resolved differently and so cannot use `expr_call_std_path`.
-    //
-    // This function accepts the path component (`ty_path_components`) separately from
-    // the name of the associated function (`assoc_fn_name`) in order to facilitate
-    // separate resolution of the type and creation of a path referring to its associated
-    // function.
-    fn expr_call_std_assoc_fn(
-        &mut self,
-        ty_path_id: hir::HirId,
-        span: Span,
-        ty_path_components: &[Symbol],
-        assoc_fn_name: &str,
-        args: &'hir [hir::Expr<'hir>],
-    ) -> hir::ExprKind<'hir> {
-        let ty_path = self.std_path(span, ty_path_components, None, false);
-        let ty =
-            self.arena.alloc(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path)));
-        let fn_seg = self.arena.alloc(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name)));
-        let fn_path = hir::QPath::TypeRelative(ty, fn_seg);
-        let fn_expr =
-            self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
-        hir::ExprKind::Call(fn_expr, args)
+        self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args))
     }
 
-    fn expr_std_path(
+    fn expr_lang_item_path(
         &mut self,
         span: Span,
-        components: &[Symbol],
-        params: Option<&'hir hir::GenericArgs<'hir>>,
+        lang_item: hir::LangItem,
         attrs: AttrVec,
     ) -> hir::Expr<'hir> {
-        let path = self.std_path(span, components, params, true);
-        self.expr(span, hir::ExprKind::Path(hir::QPath::Resolved(None, path)), attrs)
+        self.expr(span, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, span)), attrs)
     }
 
     pub(super) fn expr_ident(
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index 7cfde3fc6d2..a2962008a6b 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -85,8 +85,6 @@ const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
 rustc_hir::arena_types!(rustc_arena::declare_arena, [], 'tcx);
 
 struct LoweringContext<'a, 'hir: 'a> {
-    crate_root: Option<Symbol>,
-
     /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
     sess: &'a Session,
 
@@ -189,16 +187,6 @@ pub trait ResolverAstLowering {
     /// This should only return `None` during testing.
     fn definitions(&mut self) -> &mut Definitions;
 
-    /// Given suffix `["b", "c", "d"]`, creates an AST path for `[::crate_root]::b::c::d` and
-    /// resolves it based on `is_value`.
-    fn resolve_str_path(
-        &mut self,
-        span: Span,
-        crate_root: Option<Symbol>,
-        components: &[Symbol],
-        ns: Namespace,
-    ) -> (ast::Path, Res<NodeId>);
-
     fn lint_buffer(&mut self) -> &mut LintBuffer;
 
     fn next_node_id(&mut self) -> NodeId;
@@ -305,7 +293,6 @@ pub fn lower_crate<'a, 'hir>(
     let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
 
     LoweringContext {
-        crate_root: sess.parse_sess.injected_crate_name.get().copied(),
         sess,
         resolver,
         nt_to_tokenstream,
@@ -2064,23 +2051,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         };
 
         // "<Output = T>"
-        let future_params = self.arena.alloc(hir::GenericArgs {
+        let future_args = self.arena.alloc(hir::GenericArgs {
             args: &[],
             bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
             parenthesized: false,
         });
 
-        // ::std::future::Future<future_params>
-        let future_path =
-            self.std_path(span, &[sym::future, sym::Future], Some(future_params), false);
-
-        hir::GenericBound::Trait(
-            hir::PolyTraitRef {
-                trait_ref: hir::TraitRef { path: future_path, hir_ref_id: self.next_id() },
-                bound_generic_params: &[],
-                span,
-            },
-            hir::TraitBoundModifier::None,
+        hir::GenericBound::LangItemTrait(
+            // ::std::future::Future<future_params>
+            hir::LangItem::FutureTraitLangItem,
+            span,
+            self.next_id(),
+            future_args,
         )
     }
 
@@ -2480,35 +2462,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
-        self.pat_std_enum(span, &[sym::result, sym::Result, sym::Ok], arena_vec![self; pat])
+        let field = self.single_pat_field(span, pat);
+        self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field)
     }
 
     fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
-        self.pat_std_enum(span, &[sym::result, sym::Result, sym::Err], arena_vec![self; pat])
+        let field = self.single_pat_field(span, pat);
+        self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field)
     }
 
     fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
-        self.pat_std_enum(span, &[sym::option, sym::Option, sym::Some], arena_vec![self; pat])
+        let field = self.single_pat_field(span, pat);
+        self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field)
     }
 
     fn pat_none(&mut self, span: Span) -> &'hir hir::Pat<'hir> {
-        self.pat_std_enum(span, &[sym::option, sym::Option, sym::None], &[])
+        self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[])
     }
 
-    fn pat_std_enum(
+    fn single_pat_field(
         &mut self,
         span: Span,
-        components: &[Symbol],
-        subpats: &'hir [&'hir hir::Pat<'hir>],
-    ) -> &'hir hir::Pat<'hir> {
-        let path = self.std_path(span, components, None, true);
-        let qpath = hir::QPath::Resolved(None, path);
-        let pt = if subpats.is_empty() {
-            hir::PatKind::Path(qpath)
-        } else {
-            hir::PatKind::TupleStruct(qpath, subpats, None)
+        pat: &'hir hir::Pat<'hir>,
+    ) -> &'hir [hir::FieldPat<'hir>] {
+        let field = hir::FieldPat {
+            hir_id: self.next_id(),
+            ident: Ident::new(sym::integer(0), span),
+            is_shorthand: false,
+            pat,
+            span,
         };
-        self.pat(span, pt)
+        arena_vec![self; field]
+    }
+
+    fn pat_lang_item_variant(
+        &mut self,
+        span: Span,
+        lang_item: hir::LangItem,
+        fields: &'hir [hir::FieldPat<'hir>],
+    ) -> &'hir hir::Pat<'hir> {
+        let qpath = hir::QPath::LangItem(lang_item, span);
+        self.pat(span, hir::PatKind::Struct(qpath, fields, false))
     }
 
     fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) {
@@ -2541,42 +2535,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.arena.alloc(hir::Pat { hir_id: self.next_id(), kind, span })
     }
 
-    /// Given a suffix `["b", "c", "d"]`, returns path `::std::b::c::d` when
-    /// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
-    /// The path is also resolved according to `is_value`.
-    fn std_path(
-        &mut self,
-        span: Span,
-        components: &[Symbol],
-        params: Option<&'hir hir::GenericArgs<'hir>>,
-        is_value: bool,
-    ) -> &'hir hir::Path<'hir> {
-        let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS };
-        let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns);
-
-        let mut segments: Vec<_> = path
-            .segments
-            .iter()
-            .map(|segment| {
-                let res = self.expect_full_res(segment.id);
-                hir::PathSegment {
-                    ident: segment.ident,
-                    hir_id: Some(self.lower_node_id(segment.id)),
-                    res: Some(self.lower_res(res)),
-                    infer_args: true,
-                    args: None,
-                }
-            })
-            .collect();
-        segments.last_mut().unwrap().args = params;
-
-        self.arena.alloc(hir::Path {
-            span,
-            res: res.map_id(|_| panic!("unexpected `NodeId`")),
-            segments: self.arena.alloc_from_iter(segments),
-        })
-    }
-
     fn ty_path(
         &mut self,
         mut hir_id: hir::HirId,
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index 928235adac3..bfcb506f132 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -1,7 +1,7 @@
 use crate::def::{DefKind, Namespace, Res};
 use crate::def_id::DefId;
 crate use crate::hir_id::HirId;
-use crate::itemlikevisit;
+use crate::{itemlikevisit, LangItem};
 
 use rustc_ast::ast::{self, CrateSugar, LlvmAsmDialect};
 use rustc_ast::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy};
@@ -13,7 +13,7 @@ use rustc_ast::util::parser::ExprPrecedence;
 use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
 use rustc_macros::HashStable_Generic;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::{SourceMap, Spanned};
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -363,6 +363,8 @@ pub enum TraitBoundModifier {
 #[derive(Debug, HashStable_Generic)]
 pub enum GenericBound<'hir> {
     Trait(PolyTraitRef<'hir>, TraitBoundModifier),
+    // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
+    LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>),
     Outlives(Lifetime),
 }
 
@@ -377,6 +379,7 @@ impl GenericBound<'_> {
     pub fn span(&self) -> Span {
         match self {
             &GenericBound::Trait(ref t, ..) => t.span,
+            &GenericBound::LangItemTrait(_, span, ..) => span,
             &GenericBound::Outlives(ref l) => l.span,
         }
     }
@@ -1419,10 +1422,10 @@ impl Expr<'_> {
         self.is_place_expr(|_| true)
     }
 
-    // Whether this is a place expression.
-    // `allow_projections_from` should return `true` if indexing a field or
-    // index expression based on the given expression should be considered a
-    // place expression.
+    /// Whether this is a place expression.
+    ///
+    /// `allow_projections_from` should return `true` if indexing a field or index expression based
+    /// on the given expression should be considered a place expression.
     pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool {
         match self.kind {
             ExprKind::Path(QPath::Resolved(_, ref path)) => match path.res {
@@ -1441,6 +1444,9 @@ impl Expr<'_> {
                 allow_projections_from(base) || base.is_place_expr(allow_projections_from)
             }
 
+            // Lang item paths cannot currently be local variables or statics.
+            ExprKind::Path(QPath::LangItem(..)) => false,
+
             // Partially qualified paths in expressions can only legally
             // refer to associated items which are always rvalues.
             ExprKind::Path(QPath::TypeRelative(..))
@@ -1489,58 +1495,28 @@ impl Expr<'_> {
 
 /// Checks if the specified expression is a built-in range literal.
 /// (See: `LoweringContext::lower_expr()`).
-///
-/// FIXME(#60607): This function is a hack. If and when we have `QPath::Lang(...)`,
-/// we can use that instead as simpler, more reliable mechanism, as opposed to using `SourceMap`.
-pub fn is_range_literal(sm: &SourceMap, expr: &Expr<'_>) -> bool {
-    // Returns whether the given path represents a (desugared) range,
-    // either in std or core, i.e. has either a `::std::ops::Range` or
-    // `::core::ops::Range` prefix.
-    fn is_range_path(path: &Path<'_>) -> bool {
-        let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.to_string()).collect();
-        let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect();
-
-        // "{{root}}" is the equivalent of `::` prefix in `Path`.
-        if let ["{{root}}", std_core, "ops", range] = segs.as_slice() {
-            (*std_core == "std" || *std_core == "core") && range.starts_with("Range")
-        } else {
-            false
-        }
-    };
-
-    // Check whether a span corresponding to a range expression is a
-    // range literal, rather than an explicit struct or `new()` call.
-    fn is_lit(sm: &SourceMap, span: &Span) -> bool {
-        sm.span_to_snippet(*span).map(|range_src| range_src.contains("..")).unwrap_or(false)
-    };
-
+pub fn is_range_literal(expr: &Expr<'_>) -> bool {
     match expr.kind {
         // All built-in range literals but `..=` and `..` desugar to `Struct`s.
-        ExprKind::Struct(ref qpath, _, _) => {
-            if let QPath::Resolved(None, ref path) = **qpath {
-                return is_range_path(&path) && is_lit(sm, &expr.span);
-            }
-        }
-
-        // `..` desugars to its struct path.
-        ExprKind::Path(QPath::Resolved(None, ref path)) => {
-            return is_range_path(&path) && is_lit(sm, &expr.span);
-        }
+        ExprKind::Struct(ref qpath, _, _) => matches!(
+            **qpath,
+            QPath::LangItem(
+                LangItem::Range
+                | LangItem::RangeTo
+                | LangItem::RangeFrom
+                | LangItem::RangeFull
+                | LangItem::RangeToInclusive,
+                _,
+            )
+        ),
 
         // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
         ExprKind::Call(ref func, _) => {
-            if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind {
-                if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind {
-                    let new_call = segment.ident.name == sym::new;
-                    return is_range_path(&path) && is_lit(sm, &expr.span) && new_call;
-                }
-            }
+            matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, _)))
         }
 
-        _ => {}
+        _ => false,
     }
-
-    false
 }
 
 #[derive(Debug, HashStable_Generic)]
@@ -1677,6 +1653,40 @@ pub enum QPath<'hir> {
     /// `<Vec>::new`, and `T::X::Y::method` into `<<<T>::X>::Y>::method`,
     /// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`.
     TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>),
+
+    /// Reference to a `#[lang = "foo"]` item.
+    LangItem(LangItem, Span),
+}
+
+impl<'hir> QPath<'hir> {
+    /// Returns the span of this `QPath`.
+    pub fn span(&self) -> Span {
+        match *self {
+            QPath::Resolved(_, path) => path.span,
+            QPath::TypeRelative(_, ps) => ps.ident.span,
+            QPath::LangItem(_, span) => span,
+        }
+    }
+
+    /// Returns the span of the qself of this `QPath`. For example, `()` in
+    /// `<() as Trait>::method`.
+    pub fn qself_span(&self) -> Span {
+        match *self {
+            QPath::Resolved(_, path) => path.span,
+            QPath::TypeRelative(qself, _) => qself.span,
+            QPath::LangItem(_, span) => span,
+        }
+    }
+
+    /// Returns the span of the last segment of this `QPath`. For example, `method` in
+    /// `<() as Trait>::method`.
+    pub fn last_segment_span(&self) -> Span {
+        match *self {
+            QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span,
+            QPath::TypeRelative(_, segment) => segment.ident.span,
+            QPath::LangItem(_, span) => span,
+        }
+    }
 }
 
 /// Hints at the original code for a let statement.
diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs
index 23d642731da..66ef0177134 100644
--- a/src/librustc_hir/intravisit.rs
+++ b/src/librustc_hir/intravisit.rs
@@ -724,6 +724,7 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(
             visitor.visit_ty(qself);
             visitor.visit_path_segment(span, segment);
         }
+        QPath::LangItem(..) => {}
     }
 }
 
@@ -838,6 +839,10 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB
         GenericBound::Trait(ref typ, modifier) => {
             visitor.visit_poly_trait_ref(typ, modifier);
         }
+        GenericBound::LangItemTrait(_, span, hir_id, args) => {
+            visitor.visit_id(hir_id);
+            visitor.visit_generic_args(span, args);
+        }
         GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
     }
 }
diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs
index b09657bd9b4..d6c295f0ddb 100644
--- a/src/librustc_hir/lang_items.rs
+++ b/src/librustc_hir/lang_items.rs
@@ -10,7 +10,7 @@
 pub use self::LangItem::*;
 
 use crate::def_id::DefId;
-use crate::Target;
+use crate::{MethodKind, Target};
 
 use rustc_ast::ast;
 use rustc_data_structures::fx::FxHashMap;
@@ -307,4 +307,38 @@ language_item_table! {
     CountCodeRegionFnLangItem,         sym::count_code_region,         count_code_region_fn,         Target::Fn;
     CoverageCounterAddFnLangItem,      sym::coverage_counter_add,      coverage_counter_add_fn,      Target::Fn;
     CoverageCounterSubtractFnLangItem, sym::coverage_counter_subtract, coverage_counter_subtract_fn, Target::Fn;
+
+    // Language items from AST lowering
+    TryFromError,                  sym::from_error,         from_error_fn,           Target::Method(MethodKind::Trait { body: false });
+    TryFromOk,                     sym::from_ok,            from_ok_fn,              Target::Method(MethodKind::Trait { body: false });
+    TryIntoResult,                 sym::into_result,        into_result_fn,          Target::Method(MethodKind::Trait { body: false });
+
+    PollReady,                     sym::Ready,              poll_ready_variant,      Target::Variant;
+    PollPending,                   sym::Pending,            poll_pending_variant,    Target::Variant;
+
+    FromGenerator,                 sym::from_generator,     from_generator_fn,       Target::Fn;
+    GetContext,                    sym::get_context,        get_context_fn,          Target::Fn;
+
+    FuturePoll,                    sym::poll,               future_poll_fn,          Target::Method(MethodKind::Trait { body: false });
+
+    FromFrom,                      sym::from,               from_fn,                 Target::Method(MethodKind::Trait { body: false });
+
+    OptionSome,                    sym::Some,               option_some_variant,     Target::Variant;
+    OptionNone,                    sym::None,               option_none_variant,     Target::Variant;
+
+    ResultOk,                      sym::Ok,                 result_ok_variant,       Target::Variant;
+    ResultErr,                     sym::Err,                result_err_variant,      Target::Variant;
+
+    IntoIterIntoIter,              sym::into_iter,          into_iter_fn,            Target::Method(MethodKind::Trait { body: false });
+    IteratorNext,                  sym::next,               next_fn,                 Target::Method(MethodKind::Trait { body: false});
+
+    PinNewUnchecked,               sym::new_unchecked,      new_unchecked_fn,        Target::Method(MethodKind::Inherent);
+
+    RangeFrom,                     sym::RangeFrom,           range_from_struct,          Target::Struct;
+    RangeFull,                     sym::RangeFull,           range_full_struct,          Target::Struct;
+    RangeInclusiveStruct,          sym::RangeInclusive,      range_inclusive_struct,     Target::Struct;
+    RangeInclusiveNew,             sym::range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent);
+    Range,                         sym::Range,               range_struct,               Target::Struct;
+    RangeToInclusive,              sym::RangeToInclusive,    range_to_inclusive_struct,  Target::Struct;
+    RangeTo,                       sym::RangeTo,             range_to_struct,            Target::Struct;
 }
diff --git a/src/librustc_hir/target.rs b/src/librustc_hir/target.rs
index 3a4485a1b17..1efc8bc3124 100644
--- a/src/librustc_hir/target.rs
+++ b/src/librustc_hir/target.rs
@@ -29,6 +29,7 @@ pub enum Target {
     TyAlias,
     OpaqueTy,
     Enum,
+    Variant,
     Struct,
     Union,
     Trait,
@@ -62,6 +63,7 @@ impl Display for Target {
                 Target::TyAlias => "type alias",
                 Target::OpaqueTy => "opaque type",
                 Target::Enum => "enum",
+                Target::Variant => "enum variant",
                 Target::Struct => "struct",
                 Target::Union => "union",
                 Target::Trait => "trait",
diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs
index 2298a80ae4f..e124db9e355 100644
--- a/src/librustc_hir_pretty/lib.rs
+++ b/src/librustc_hir_pretty/lib.rs
@@ -1729,6 +1729,11 @@ impl<'a> State<'a> {
                     colons_before_params,
                 )
             }
+            hir::QPath::LangItem(lang_item, span) => {
+                self.s.word("#[lang = \"");
+                self.print_ident(Ident::new(lang_item.name(), span));
+                self.s.word("\"]");
+            }
         }
     }
 
@@ -2142,6 +2147,11 @@ impl<'a> State<'a> {
                     }
                     self.print_poly_trait_ref(tref);
                 }
+                GenericBound::LangItemTrait(lang_item, span, ..) => {
+                    self.s.word("#[lang = \"");
+                    self.print_ident(Ident::new(lang_item.name(), *span));
+                    self.s.word("\"]");
+                }
                 GenericBound::Outlives(lt) => {
                     self.print_lifetime(lt);
                 }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 3859d0f163a..97830e6c86f 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1057,7 +1057,7 @@ impl TypeAliasBounds {
                     _ => false,
                 }
             }
-            hir::QPath::Resolved(..) => false,
+            hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false,
         }
     }
 
diff --git a/src/librustc_lint/context.rs b/src/librustc_lint/context.rs
index 31d30a264a5..5b91b77e4f0 100644
--- a/src/librustc_lint/context.rs
+++ b/src/librustc_lint/context.rs
@@ -703,7 +703,7 @@ impl<'tcx> LateContext<'tcx> {
     pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
         match *qpath {
             hir::QPath::Resolved(_, ref path) => path.res,
-            hir::QPath::TypeRelative(..) => self
+            hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
                 .maybe_typeck_results()
                 .and_then(|typeck_results| typeck_results.type_dependent_def(id))
                 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 5891abcfd9c..a1c9b05a684 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -258,7 +258,7 @@ fn lint_int_literal<'tcx>(
         let par_id = cx.tcx.hir().get_parent_node(e.hir_id);
         if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) {
             if let hir::ExprKind::Struct(..) = par_e.kind {
-                if is_range_literal(cx.sess().source_map(), par_e)
+                if is_range_literal(par_e)
                     && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str())
                 {
                     // The overflowing literal lint was overridden.
@@ -317,7 +317,7 @@ fn lint_uint_literal<'tcx>(
                         return;
                     }
                 }
-                hir::ExprKind::Struct(..) if is_range_literal(cx.sess().source_map(), par_e) => {
+                hir::ExprKind::Struct(..) if is_range_literal(par_e) => {
                     let t = t.name_str();
                     if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
                         // The overflowing literal lint was overridden.
diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs
index d7eeaafbf46..ede7d85ebb4 100644
--- a/src/librustc_middle/ty/context.rs
+++ b/src/librustc_middle/ty/context.rs
@@ -452,7 +452,7 @@ impl<'tcx> TypeckResults<'tcx> {
     pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
         match *qpath {
             hir::QPath::Resolved(_, ref path) => path.res,
-            hir::QPath::TypeRelative(..) => self
+            hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
                 .type_dependent_def(id)
                 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
         }
diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs
index 07415870549..9ec47d2d9ab 100644
--- a/src/librustc_passes/lang_items.rs
+++ b/src/librustc_passes/lang_items.rs
@@ -30,7 +30,13 @@ struct LanguageItemCollector<'tcx> {
 
 impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs)
+        self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs);
+
+        if let hir::ItemKind::Enum(def, ..) = &item.kind {
+            for variant in def.variants {
+                self.check_for_lang(Target::Variant, variant.id, variant.attrs);
+            }
+        }
     }
 
     fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs
index 6477f8da008..62c8680a857 100644
--- a/src/librustc_passes/liveness.rs
+++ b/src/librustc_passes/liveness.rs
@@ -526,7 +526,8 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) {
         | hir::ExprKind::Yield(..)
         | hir::ExprKind::Type(..)
         | hir::ExprKind::Err
-        | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
+        | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
+        | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {
             intravisit::walk_expr(ir, expr);
         }
     }
@@ -1310,7 +1311,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
             hir::ExprKind::Lit(..)
             | hir::ExprKind::Err
-            | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => succ,
+            | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
+            | hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ,
 
             // Note that labels have been resolved, so we don't need to look
             // at the label ident
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index a3f2668691f..deb4277cb38 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -1325,7 +1325,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
                 Res::Def(kind, def_id) => Some((kind, def_id)),
                 _ => None,
             },
-            hir::QPath::TypeRelative(..) => self
+            hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
                 .maybe_typeck_results
                 .and_then(|typeck_results| typeck_results.type_dependent_def(id)),
         };
@@ -1340,7 +1340,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
                 let sess = self.tcx.sess;
                 let sm = sess.source_map();
                 let name = match qpath {
-                    hir::QPath::Resolved(_, path) => sm.span_to_snippet(path.span).ok(),
+                    hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => {
+                        sm.span_to_snippet(qpath.span()).ok()
+                    }
                     hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
                 };
                 let kind = kind.descr(def_id);
diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs
index e2f0d388f7e..31360d47473 100644
--- a/src/librustc_resolve/late/lifetimes.rs
+++ b/src/librustc_resolve/late/lifetimes.rs
@@ -941,6 +941,24 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         }
     }
 
+    fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) {
+        match bound {
+            hir::GenericBound::LangItemTrait { .. } if !self.trait_ref_hack => {
+                let scope = Scope::Binder {
+                    lifetimes: FxHashMap::default(),
+                    s: self.scope,
+                    next_early_index: self.next_early_index(),
+                    track_lifetime_uses: true,
+                    opaque_type_parent: false,
+                };
+                self.with(scope, |_, this| {
+                    intravisit::walk_param_bound(this, bound);
+                });
+            }
+            _ => intravisit::walk_param_bound(self, bound),
+        }
+    }
+
     fn visit_poly_trait_ref(
         &mut self,
         trait_ref: &'tcx hir::PolyTraitRef<'tcx>,
@@ -2296,6 +2314,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 self.outer_index.shift_out(1);
             }
 
+            fn visit_param_bound(&mut self, bound: &hir::GenericBound<'_>) {
+                if let hir::GenericBound::LangItemTrait { .. } = bound {
+                    self.outer_index.shift_in(1);
+                    intravisit::walk_param_bound(self, bound);
+                    self.outer_index.shift_out(1);
+                } else {
+                    intravisit::walk_param_bound(self, bound);
+                }
+            }
+
             fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
                 if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
                     match lifetime {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 339a5ae6675..32b8ea410ad 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1076,37 +1076,6 @@ impl ResolverAstLowering for Resolver<'_> {
         self.cstore().item_generics_num_lifetimes(def_id, sess)
     }
 
-    fn resolve_str_path(
-        &mut self,
-        span: Span,
-        crate_root: Option<Symbol>,
-        components: &[Symbol],
-        ns: Namespace,
-    ) -> (ast::Path, Res) {
-        let root = if crate_root.is_some() { kw::PathRoot } else { kw::Crate };
-        let segments = iter::once(Ident::with_dummy_span(root))
-            .chain(
-                crate_root
-                    .into_iter()
-                    .chain(components.iter().cloned())
-                    .map(Ident::with_dummy_span),
-            )
-            .map(|i| self.new_ast_path_segment(i))
-            .collect::<Vec<_>>();
-
-        let path = ast::Path { span, segments };
-
-        let parent_scope = &ParentScope::module(self.graph_root);
-        let res = match self.resolve_ast_path(&path, ns, parent_scope) {
-            Ok(res) => res,
-            Err((span, error)) => {
-                self.report_error(span, error);
-                Res::Err
-            }
-        };
-        (path, res)
-    }
-
     fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes> {
         self.partial_res_map.get(&id).cloned()
     }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index f33d2f46aa2..6e56e3b9ebb 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -702,14 +702,18 @@ impl<'tcx> DumpVisitor<'tcx> {
 
         // super-traits
         for super_bound in trait_refs.iter() {
-            let trait_ref = match *super_bound {
-                hir::GenericBound::Trait(ref trait_ref, _) => trait_ref,
+            let (def_id, sub_span) = match *super_bound {
+                hir::GenericBound::Trait(ref trait_ref, _) => (
+                    self.lookup_def_id(trait_ref.trait_ref.hir_ref_id),
+                    trait_ref.trait_ref.path.segments.last().unwrap().ident.span,
+                ),
+                hir::GenericBound::LangItemTrait(lang_item, span, _, _) => {
+                    (Some(self.tcx.require_lang_item(lang_item, Some(span))), span)
+                }
                 hir::GenericBound::Outlives(..) => continue,
             };
 
-            let trait_ref = &trait_ref.trait_ref;
-            if let Some(id) = self.lookup_def_id(trait_ref.hir_ref_id) {
-                let sub_span = trait_ref.path.segments.last().unwrap().ident.span;
+            if let Some(id) = def_id {
                 if !self.span.filter_generated(sub_span) {
                     let span = self.span_from_span(sub_span);
                     self.dumper.dump_ref(Ref {
@@ -762,11 +766,7 @@ impl<'tcx> DumpVisitor<'tcx> {
     }
 
     fn process_path(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) {
-        let span = match path {
-            hir::QPath::Resolved(_, path) => path.span,
-            hir::QPath::TypeRelative(_, segment) => segment.ident.span,
-        };
-        if self.span.filter_generated(span) {
+        if self.span.filter_generated(path.span()) {
             return;
         }
         self.dump_path_ref(id, path);
@@ -783,6 +783,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 self.visit_ty(ty);
                 std::slice::from_ref(*segment)
             }
+            hir::QPath::LangItem(..) => return,
         };
         for seg in segments {
             if let Some(ref generic_args) = seg.args {
@@ -1355,10 +1356,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                 }
 
                 if let Some(id) = self.lookup_def_id(t.hir_id) {
-                    let sub_span = match path {
-                        hir::QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span,
-                        hir::QPath::TypeRelative(_, segment) => segment.ident.span,
-                    };
+                    let sub_span = path.last_segment_span();
                     let span = self.span_from_span(sub_span);
                     self.dumper.dump_ref(Ref {
                         kind: RefKind::Type,
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index ca98ada4e57..fc8a5384739 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -551,28 +551,22 @@ impl<'tcx> SaveContext<'tcx> {
                     }
                 }
             }
-            hir::ExprKind::Struct(qpath, ..) => {
-                let segment = match qpath {
-                    hir::QPath::Resolved(_, path) => path.segments.last().unwrap(),
-                    hir::QPath::TypeRelative(_, segment) => segment,
-                };
-                match ty.kind {
-                    ty::Adt(def, _) => {
-                        let sub_span = segment.ident.span;
-                        filter!(self.span_utils, sub_span);
-                        let span = self.span_from_span(sub_span);
-                        Some(Data::RefData(Ref {
-                            kind: RefKind::Type,
-                            span,
-                            ref_id: id_from_def_id(def.did),
-                        }))
-                    }
-                    _ => {
-                        debug!("expected adt, found {:?}", ty);
-                        None
-                    }
+            hir::ExprKind::Struct(qpath, ..) => match ty.kind {
+                ty::Adt(def, _) => {
+                    let sub_span = qpath.last_segment_span();
+                    filter!(self.span_utils, sub_span);
+                    let span = self.span_from_span(sub_span);
+                    Some(Data::RefData(Ref {
+                        kind: RefKind::Type,
+                        span,
+                        ref_id: id_from_def_id(def.did),
+                    }))
                 }
-            }
+                _ => {
+                    debug!("expected adt, found {:?}", ty);
+                    None
+                }
+            },
             hir::ExprKind::MethodCall(ref seg, ..) => {
                 let method_id = match self.typeck_results().type_dependent_def_id(expr.hir_id) {
                     Some(id) => id,
@@ -636,7 +630,7 @@ impl<'tcx> SaveContext<'tcx> {
             })
             | Node::Ty(&hir::Ty { kind: hir::TyKind::Path(ref qpath), .. }) => match qpath {
                 hir::QPath::Resolved(_, path) => path.res,
-                hir::QPath::TypeRelative(..) => self
+                hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
                     .maybe_typeck_results
                     .map_or(Res::Err, |typeck_results| typeck_results.qpath_res(qpath, hir_id)),
             },
@@ -653,6 +647,7 @@ impl<'tcx> SaveContext<'tcx> {
         let segment = match path {
             hir::QPath::Resolved(_, path) => path.segments.last(),
             hir::QPath::TypeRelative(_, segment) => Some(*segment),
+            hir::QPath::LangItem(..) => None,
         };
         segment.and_then(|seg| {
             self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id))
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 33355c4c558..f6869cbbfd2 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -286,6 +286,9 @@ impl<'hir> Sig for hir::Ty<'hir> {
                     refs: vec![SigElement { id, start, end }],
                 })
             }
+            hir::TyKind::Path(hir::QPath::LangItem(lang_item, _)) => {
+                Ok(text_sig(format!("#[lang = \"{}\"]", lang_item.name())))
+            }
             hir::TyKind::TraitObject(bounds, ..) => {
                 // FIXME recurse into bounds
                 let bounds: Vec<hir::GenericBound<'_>> = bounds
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index 7843c04f255..bc7efd26f46 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -706,6 +706,7 @@ symbols! {
         never_type,
         never_type_fallback,
         new,
+        new_unchecked,
         next,
         nll,
         no,
@@ -828,6 +829,7 @@ symbols! {
         quad_precision_float,
         question_mark,
         quote,
+        range_inclusive_new,
         raw_dylib,
         raw_identifiers,
         raw_ref_op,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 5170a060c5f..5e52a5ef16f 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1202,6 +1202,36 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         )
     }
 
+    pub fn instantiate_lang_item_trait_ref(
+        &self,
+        lang_item: hir::LangItem,
+        span: Span,
+        hir_id: hir::HirId,
+        args: &GenericArgs<'_>,
+        self_ty: Ty<'tcx>,
+        bounds: &mut Bounds<'tcx>,
+    ) {
+        let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span));
+
+        let (substs, assoc_bindings, _) =
+            self.create_substs_for_ast_path(span, trait_def_id, &[], args, false, Some(self_ty));
+        let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
+        bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst));
+
+        let mut dup_bindings = FxHashMap::default();
+        for binding in assoc_bindings {
+            let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding(
+                hir_id,
+                poly_trait_ref,
+                &binding,
+                bounds,
+                false,
+                &mut dup_bindings,
+                span,
+            );
+        }
+    }
+
     fn ast_path_to_mono_trait_ref(
         &self,
         span: Span,
@@ -1392,6 +1422,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     trait_bounds.push((b, Constness::NotConst))
                 }
                 hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
+                hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self
+                    .instantiate_lang_item_trait_ref(
+                        lang_item, span, hir_id, args, param_ty, bounds,
+                    ),
                 hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
             }
         }
@@ -2960,6 +2994,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     .map(|(ty, _, _)| ty)
                     .unwrap_or_else(|_| tcx.ty_error())
             }
+            hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
+                let def_id = tcx.require_lang_item(lang_item, Some(span));
+                let (substs, _, _) = self.create_substs_for_ast_path(
+                    span,
+                    def_id,
+                    &[],
+                    &GenericArgs::none(),
+                    true,
+                    None,
+                );
+                self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
+            }
             hir::TyKind::Array(ref ty, ref length) => {
                 let length_def_id = tcx.hir().local_def_id(length.hir_id);
                 let length = ty::Const::from_anon_const(tcx, length_def_id);
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 4ea76a4a9e2..ad97dbe63d8 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -485,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // parenthesize if needed (Issue #46756)
                             hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
                             // parenthesize borrows of range literals (Issue #54505)
-                            _ if is_range_literal(self.tcx.sess.source_map(), expr) => true,
+                            _ if is_range_literal(expr) => true,
                             _ => false,
                         };
                         let sugg_expr = if needs_parens { format!("({})", src) } else { src };
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index e88f13a1f3a..e2c90cce178 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -236,6 +236,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::AddrOf(kind, mutbl, ref oprnd) => {
                 self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
             }
+            ExprKind::Path(QPath::LangItem(lang_item, _)) => {
+                self.check_lang_item_path(lang_item, expr)
+            }
             ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr),
             ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
             ExprKind::LlvmInlineAsm(ref asm) => {
@@ -447,6 +450,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    fn check_lang_item_path(
+        &self,
+        lang_item: hir::LangItem,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Ty<'tcx> {
+        self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1
+    }
+
     fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
         let tcx = self.tcx;
         let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span);
@@ -1077,11 +1088,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return self.tcx.ty_error();
         };
 
-        let path_span = match *qpath {
-            QPath::Resolved(_, ref path) => path.span,
-            QPath::TypeRelative(ref qself, _) => qself.span,
-        };
-
         // Prohibit struct expressions when non-exhaustive flag is set.
         let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");
         if !adt.did.is_local() && variant.is_field_list_non_exhaustive() {
@@ -1099,7 +1105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             adt_ty,
             expected,
             expr.hir_id,
-            path_span,
+            qpath.span(),
             variant,
             fields,
             base_expr.is_none(),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a625b5ea405..c46d2388f3d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -122,10 +122,9 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts};
 use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
-use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef,
-    ToPredicate, Ty, TyCtxt, UserType, WithConstness,
-};
+use rustc_middle::ty::WithConstness;
+use rustc_middle::ty::{self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind};
+use rustc_middle::ty::{RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType};
 use rustc_session::config::{self, EntryFnType};
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
@@ -4430,10 +4429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         qpath: &QPath<'_>,
         hir_id: hir::HirId,
     ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
-        let path_span = match *qpath {
-            QPath::Resolved(_, ref path) => path.span,
-            QPath::TypeRelative(ref qself, _) => qself.span,
-        };
+        let path_span = qpath.qself_span();
         let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
         let variant = match def {
             Res::Err => {
@@ -4511,9 +4507,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
             }
+            QPath::LangItem(lang_item, span) => {
+                self.resolve_lang_item_path(lang_item, span, hir_id)
+            }
         }
     }
 
+    fn resolve_lang_item_path(
+        &self,
+        lang_item: hir::LangItem,
+        span: Span,
+        hir_id: hir::HirId,
+    ) -> (Res, Ty<'tcx>) {
+        let def_id = self.tcx.require_lang_item(lang_item, Some(span));
+        let def_kind = self.tcx.def_kind(def_id);
+
+        let item_ty = if let DefKind::Variant = def_kind {
+            self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
+        } else {
+            self.tcx.type_of(def_id)
+        };
+        let substs = self.infcx.fresh_substs_for_item(span, def_id);
+        let ty = item_ty.subst(self.tcx, substs);
+
+        self.write_resolution(hir_id, Ok((def_kind, def_id)));
+        self.add_required_obligations(span, def_id, &substs);
+        (Res::Def(def_kind, def_id), ty)
+    }
+
     /// Resolves an associated value path into a base type and associated constant, or method
     /// resolution. The newly resolved definition is written into `type_dependent_defs`.
     pub fn resolve_ty_and_res_ufcs<'b>(
@@ -4532,6 +4553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
             }
             QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
+            QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"),
         };
         if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
         {
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index 1c78bef9852..35c7b7a703c 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -947,13 +947,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 //   |
                 // L |     let A(()) = A(());
                 //   |          ^  ^
-                [] => {
-                    let qpath_span = match qpath {
-                        hir::QPath::Resolved(_, path) => path.span,
-                        hir::QPath::TypeRelative(_, ps) => ps.ident.span,
-                    };
-                    (qpath_span.shrink_to_hi(), pat_span)
-                }
+                [] => (qpath.span().shrink_to_hi(), pat_span),
                 // Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the
                 // last sub-pattern. In the case of `A(x)` the first and last may coincide.
                 // This looks like:
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index da1f3ea62f2..15743b06436 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1959,6 +1959,20 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
                             predicates.extend(bounds.predicates(tcx, ty));
                         }
 
+                        &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
+                            let mut bounds = Bounds::default();
+                            AstConv::instantiate_lang_item_trait_ref(
+                                &icx,
+                                lang_item,
+                                span,
+                                hir_id,
+                                args,
+                                ty,
+                                &mut bounds,
+                            );
+                            predicates.extend(bounds.predicates(tcx, ty));
+                        }
+
                         &hir::GenericBound::Outlives(ref lifetime) => {
                             let region = AstConv::ast_region_to_region(&icx, lifetime, None);
                             predicates.push((
@@ -2108,6 +2122,18 @@ fn predicates_from_bound<'tcx>(
             let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds);
             bounds.predicates(astconv.tcx(), param_ty)
         }
+        hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
+            let mut bounds = Bounds::default();
+            astconv.instantiate_lang_item_trait_ref(
+                lang_item,
+                span,
+                hir_id,
+                args,
+                param_ty,
+                &mut bounds,
+            );
+            bounds.predicates(astconv.tcx(), param_ty)
+        }
         hir::GenericBound::Outlives(ref lifetime) => {
             let region = astconv.ast_region_to_region(lifetime, None);
             let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region))
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 3ad357e583c..bf385fd79b0 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -17,6 +17,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
+use rustc_middle::bug;
 use rustc_middle::middle::resolve_lifetime as rl;
 use rustc_middle::middle::stability;
 use rustc_middle::ty::fold::TypeFolder;
@@ -291,6 +292,22 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
         match *self {
             hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
+            hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
+                let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
+
+                let trait_ref = ty::TraitRef::identity(cx.tcx, def_id);
+
+                let generic_args = generic_args.clean(cx);
+                let bindings = match generic_args {
+                    GenericArgs::AngleBracketed { bindings, .. } => bindings,
+                    _ => bug!("clean: parenthesized `GenericBound::LangItemTrait`"),
+                };
+
+                GenericBound::TraitBound(
+                    PolyTrait { trait_: (trait_ref, &*bindings).clean(cx), generic_params: vec![] },
+                    hir::TraitBoundModifier::None,
+                )
+            }
             hir::GenericBound::Trait(ref t, modifier) => {
                 GenericBound::TraitBound(t.clean(cx), modifier)
             }
@@ -1504,6 +1521,9 @@ impl Clean<Type> for hir::Ty<'_> {
                     trait_: box resolve_type(cx, trait_path.clean(cx), self.hir_id),
                 }
             }
+            TyKind::Path(hir::QPath::LangItem(..)) => {
+                bug!("clean: requiring documentation of lang item")
+            }
             TyKind::TraitObject(ref bounds, ref lifetime) => {
                 match bounds[0].clean(cx).trait_ {
                     ResolvedPath { path, param_names: None, did, is_generic } => {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index a7d03fcabf5..a502a27948e 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -335,6 +335,7 @@ pub fn qpath_to_string(p: &hir::QPath<'_>) -> String {
     let segments = match *p {
         hir::QPath::Resolved(_, ref path) => &path.segments,
         hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
+        hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(),
     };
 
     let mut s = String::new();
diff --git a/src/test/ui/hygiene/hir-res-hygiene.rs b/src/test/ui/hygiene/hir-res-hygiene.rs
new file mode 100644
index 00000000000..c26cf5fdb5b
--- /dev/null
+++ b/src/test/ui/hygiene/hir-res-hygiene.rs
@@ -0,0 +1,18 @@
+// check-pass
+// edition:2018
+// aux-build:not-libstd.rs
+
+// Check that paths created in HIR are not affected by in scope names.
+
+extern crate not_libstd as std;
+
+async fn the_future() {
+    async {}.await;
+}
+
+fn main() -> Result<(), ()> {
+    for i in 0..10 {}
+    for j in 0..=10 {}
+    Ok(())?;
+    Ok(())
+}
diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr
index e179feba7a7..11cb72fa2b6 100644
--- a/src/test/ui/range/range-1.stderr
+++ b/src/test/ui/range/range-1.stderr
@@ -17,9 +17,13 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi
    |
 LL |     let range = *arr..;
    |                 ^^^^^^ doesn't have a size known at compile-time
+   | 
+  ::: $SRC_DIR/core/src/ops/range.rs:LL:COL
+   |
+LL | pub struct RangeFrom<Idx> {
+   |                      --- required by this bound in `std::ops::RangeFrom`
    |
    = help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
-   = note: required by `std::ops::RangeFrom`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/clippy_lints/src/default_trait_access.rs b/src/tools/clippy/clippy_lints/src/default_trait_access.rs
index 874e19d9e9f..067ea903bdd 100644
--- a/src/tools/clippy/clippy_lints/src/default_trait_access.rs
+++ b/src/tools/clippy/clippy_lints/src/default_trait_access.rs
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess {
                             );
                          }
                     },
-                    QPath::TypeRelative(..) => {},
+                    QPath::TypeRelative(..) | QPath::LangItem(..) => {},
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index a1f58e54ae3..90b1a529be7 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Index(ref array, ref index) = &expr.kind {
             let ty = cx.typeck_results().expr_ty(array);
-            if let Some(range) = higher::range(cx, index) {
+            if let Some(range) = higher::range(index) {
                 // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
                 if let ty::Array(_, s) = ty.kind {
                     let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) {
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index e511d3ea330..129abd7d897 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -171,7 +171,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                 Finite
             }
         },
-        ExprKind::Struct(..) => higher::range(cx, expr).map_or(false, |r| r.end.is_none()).into(),
+        ExprKind::Struct(..) => higher::range(expr).map_or(false, |r| r.end.is_none()).into(),
         _ => Finite,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 00d0b8b4e5b..e5daa30f8ca 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -262,7 +262,7 @@ fn check_len(
 fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     /// Special case ranges until `range_is_empty` is stabilized. See issue 3807.
     fn should_skip_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-        higher::range(cx, expr).map_or(false, |_| {
+        higher::range(expr).map_or(false, |_| {
             !cx.tcx
                 .features()
                 .declared_lib_features
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index 8352a8a3d2c..8ffcd417d1d 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -1003,7 +1003,7 @@ fn detect_manual_memcpy<'tcx>(
         start: Some(start),
         end: Some(end),
         limits,
-    }) = higher::range(cx, arg)
+    }) = higher::range(arg)
     {
         // the var must be a single name
         if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
@@ -1177,7 +1177,7 @@ fn check_for_loop_range<'tcx>(
         start: Some(start),
         ref end,
         limits,
-    }) = higher::range(cx, arg)
+    }) = higher::range(arg)
     {
         // the var must be a single name
         if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
@@ -1679,7 +1679,7 @@ fn check_for_mut_range_bound(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'
         start: Some(start),
         end: Some(end),
         ..
-    }) = higher::range(cx, arg)
+    }) = higher::range(arg)
     {
         let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
         if mut_ids[0].is_some() || mut_ids[1].is_some() {
diff --git a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
index 4f8f2cb171d..faa20687ef6 100644
--- a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
+++ b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
@@ -1,7 +1,8 @@
-use crate::utils::{self, is_type_diagnostic_item, match_type, snippet, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg};
+use crate::utils::walk_ptrs_ty;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, MatchSource};
+use rustc_hir::{Expr, ExprKind, LangItem, MatchSource};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -96,5 +97,5 @@ fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
     let ty = walk_ptrs_ty(ty);
-    match_type(cx, ty, &utils::paths::RANGE_FULL)
+    is_type_lang_item(cx, ty, LangItem::RangeFull)
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 570ae66d595..2265a188855 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -2271,7 +2271,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
         if_chain! {
             if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
-                = higher::range(cx, index_expr);
+                = higher::range(index_expr);
             if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
             then {
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 26a1c32b6b3..482a563572d 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -433,6 +433,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
             return;
         }
         let binding = match expr.kind {
+            ExprKind::Path(hir::QPath::LangItem(..)) => None,
             ExprKind::Path(ref qpath) => {
                 let binding = last_path_segment(qpath).ident.as_str();
                 if binding.starts_with('_') &&
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index f88075798ca..7a75fc125d0 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -147,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
                     if let ExprKind::MethodCall(ref iter_path, _, ref iter_args , _) = *iter;
                     if iter_path.ident.name == sym!(iter);
                     // range expression in `.zip()` call: `0..x.len()`
-                    if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(cx, zip_arg);
+                    if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg);
                     if is_integer_const(cx, start, 0);
                     // `.len()` call
                     if let ExprKind::MethodCall(ref len_path, _, ref len_args, _) = end.kind;
@@ -180,7 +180,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
             start,
             end: Some(end),
             limits: RangeLimits::HalfOpen
-        }) = higher::range(cx, expr);
+        }) = higher::range(expr);
         if let Some(y) = y_plus_one(cx, end);
         then {
             let span = if expr.span.from_expansion() {
@@ -225,7 +225,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
 // inclusive range minus one: `x..=(y-1)`
 fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
-        if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(cx, expr);
+        if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(expr);
         if let Some(y) = y_minus_one(cx, end);
         then {
             span_lint_and_then(
@@ -279,7 +279,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
     }
 
     if_chain! {
-        if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(cx, expr);
+        if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(expr);
         let ty = cx.typeck_results().expr_ty(start);
         if let ty::Int(_) | ty::Uint(_) = ty.kind;
         if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start);
diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs
index 3bd73d9f21a..a74104e9282 100644
--- a/src/tools/clippy/clippy_lints/src/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/try_err.rs
@@ -1,10 +1,10 @@
 use crate::utils::{
-    is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite,
-    span_lint_and_sugg,
+    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;
-use rustc_hir::{Expr, ExprKind, MatchSource};
+use rustc_hir::{Expr, ExprKind, QPath, LangItem, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
             if let ExprKind::Match(ref match_arg, _, MatchSource::TryDesugar) = expr.kind;
             if let ExprKind::Call(ref match_fun, ref try_args) = match_arg.kind;
             if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
-            if match_qpath(match_fun_path, &paths::TRY_INTO_RESULT);
+            if matches!(match_fun_path, QPath::LangItem(LangItem::TryIntoResult, _));
             if let Some(ref try_arg) = try_args.get(0);
             if let ExprKind::Call(ref err_fun, ref err_args) = try_arg.kind;
             if let Some(ref err_arg) = err_args.get(0);
diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs
index c3dea447521..d1a7886a47e 100644
--- a/src/tools/clippy/clippy_lints/src/types.rs
+++ b/src/tools/clippy/clippy_lints/src/types.rs
@@ -475,6 +475,7 @@ impl Types {
                             }
                         }
                     },
+                    QPath::LangItem(..) => {},
                 }
             },
             TyKind::Rptr(ref lt, ref mut_ty) => self.check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty),
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 1580f657d77..43166d26787 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -1,4 +1,4 @@
-use crate::utils::{is_try, match_qpath, match_trait_method, paths, span_lint};
+use crate::utils::{is_try, match_trait_method, paths, span_lint};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -42,10 +42,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
         match expr.kind {
             hir::ExprKind::Match(ref res, _, _) if is_try(expr).is_some() => {
                 if let hir::ExprKind::Call(ref func, ref args) = res.kind {
-                    if let hir::ExprKind::Path(ref path) = func.kind {
-                        if match_qpath(path, &paths::TRY_INTO_RESULT) && args.len() == 1 {
-                            check_method_call(cx, &args[0], expr);
-                        }
+                    if matches!(
+                        func.kind,
+                        hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _))
+                    ) {
+                        check_method_call(cx, &args[0], expr);
                     }
                 } else {
                     check_method_call(cx, res, expr);
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 128fa87a162..9b7a268c628 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -175,9 +175,19 @@ impl PrintVisitor {
     }
 
     fn print_qpath(&mut self, path: &QPath<'_>) {
-        print!("    if match_qpath({}, &[", self.current);
-        print_path(path, &mut true);
-        println!("]);");
+        match  *path {
+            QPath::LangItem(lang_item, _) => {
+                println!(
+                    "    if matches!({}, QPath::LangItem(LangItem::{:?}, _));",
+                   self.current, lang_item,
+                );
+            },
+            _ => {
+                print!("    if match_qpath({}, &[", self.current);
+                print_path(path, &mut true);
+                println!("]);");
+            },
+        }
     }
 }
 
@@ -760,5 +770,6 @@ fn print_path(path: &QPath<'_>, first: &mut bool) {
             },
             ref other => print!("/* unimplemented: {:?}*/", other),
         },
+        QPath::LangItem(..) => panic!("print_path: called for lang item qpath"),
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/higher.rs b/src/tools/clippy/clippy_lints/src/utils/higher.rs
index f81a132c7e7..ba15456014d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/higher.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/higher.rs
@@ -3,12 +3,11 @@
 
 #![deny(clippy::missing_docs_in_private_items)]
 
-use crate::utils::{is_expn_of, match_def_path, match_qpath, paths};
+use crate::utils::{is_expn_of, match_def_path, paths};
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_middle::ty;
 
 /// Converts a hir binary operator to the corresponding `ast` type.
 #[must_use]
@@ -47,7 +46,7 @@ pub struct Range<'a> {
 }
 
 /// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
-pub fn range<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
+pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
     /// Finds the field named `name` in the field. Always return `Some` for
     /// convenience.
     fn get_field<'c>(name: &str, fields: &'c [hir::Field<'_>]) -> Option<&'c hir::Expr<'c>> {
@@ -56,94 +55,43 @@ pub fn range<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a hir::Expr<'_>) -> Optio
         Some(expr)
     }
 
-    let def_path = match cx.typeck_results().expr_ty(expr).kind {
-        ty::Adt(def, _) => cx.tcx.def_path(def.did),
-        _ => return None,
-    };
-
-    // sanity checks for std::ops::RangeXXXX
-    if def_path.data.len() != 3 {
-        return None;
-    }
-    if def_path.data.get(0)?.data.as_symbol() != sym!(ops) {
-        return None;
-    }
-    if def_path.data.get(1)?.data.as_symbol() != sym!(range) {
-        return None;
-    }
-    let type_name = def_path.data.get(2)?.data.as_symbol();
-    let range_types = [
-        "RangeFrom",
-        "RangeFull",
-        "RangeInclusive",
-        "Range",
-        "RangeTo",
-        "RangeToInclusive",
-    ];
-    if !range_types.contains(&&*type_name.as_str()) {
-        return None;
-    }
-
-    // The range syntax is expanded to literal paths starting with `core` or `std`
-    // depending on
-    // `#[no_std]`. Testing both instead of resolving the paths.
-
     match expr.kind {
-        hir::ExprKind::Path(ref path) => {
-            if match_qpath(path, &paths::RANGE_FULL_STD) || match_qpath(path, &paths::RANGE_FULL) {
-                Some(Range {
+        hir::ExprKind::Call(ref path, ref args) if matches!(
+            path.kind,
+            hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
+        ) => Some(Range {
+            start: Some(&args[0]),
+            end: Some(&args[1]),
+            limits: ast::RangeLimits::Closed,
+        }),
+        hir::ExprKind::Struct(ref path, ref fields, None) => {
+            match path {
+                hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
                     start: None,
                     end: None,
                     limits: ast::RangeLimits::HalfOpen,
-                })
-            } else {
-                None
-            }
-        },
-        hir::ExprKind::Call(ref path, ref args) => {
-            if let hir::ExprKind::Path(ref path) = path.kind {
-                if match_qpath(path, &paths::RANGE_INCLUSIVE_STD_NEW) || match_qpath(path, &paths::RANGE_INCLUSIVE_NEW)
-                {
-                    Some(Range {
-                        start: Some(&args[0]),
-                        end: Some(&args[1]),
-                        limits: ast::RangeLimits::Closed,
-                    })
-                } else {
-                    None
-                }
-            } else {
-                None
-            }
-        },
-        hir::ExprKind::Struct(ref path, ref fields, None) => {
-            if match_qpath(path, &paths::RANGE_FROM_STD) || match_qpath(path, &paths::RANGE_FROM) {
-                Some(Range {
+                }),
+                hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range {
                     start: Some(get_field("start", fields)?),
                     end: None,
                     limits: ast::RangeLimits::HalfOpen,
-                })
-            } else if match_qpath(path, &paths::RANGE_STD) || match_qpath(path, &paths::RANGE) {
-                Some(Range {
+                }),
+                hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range {
                     start: Some(get_field("start", fields)?),
                     end: Some(get_field("end", fields)?),
                     limits: ast::RangeLimits::HalfOpen,
-                })
-            } else if match_qpath(path, &paths::RANGE_TO_INCLUSIVE_STD) || match_qpath(path, &paths::RANGE_TO_INCLUSIVE)
-            {
-                Some(Range {
+                }),
+                hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range {
                     start: None,
                     end: Some(get_field("end", fields)?),
                     limits: ast::RangeLimits::Closed,
-                })
-            } else if match_qpath(path, &paths::RANGE_TO_STD) || match_qpath(path, &paths::RANGE_TO) {
-                Some(Range {
+                }),
+                hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range {
                     start: None,
                     end: Some(get_field("end", fields)?),
                     limits: ast::RangeLimits::HalfOpen,
-                })
-            } else {
-                None
+                }),
+                _ => None,
             }
         },
         _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
index 28fb6ed12a0..2eefd4a38a6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
@@ -3,9 +3,9 @@ use crate::utils::differing_macro_contexts;
 use rustc_ast::ast::InlineAsmTemplatePiece;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::{
-    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FnRetTy, GenericArg,
-    GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path, PathSegment, QPath,
-    Stmt, StmtKind, Ty, TyKind, TypeBinding,
+    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat,
+    FnRetTy, GenericArg, GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName,
+    Pat, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lint::LateContext;
 use rustc_middle::ich::StableHashingContextProvider;
@@ -185,10 +185,20 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
         left.name == right.name
     }
 
+    pub fn eq_fieldpat(&mut self, left: &FieldPat<'_>, right: &FieldPat<'_>) -> bool {
+        match (&left, &right) {
+            (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) =>
+                li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp),
+        }
+    }
+
     /// Checks whether two patterns are the same.
     pub fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
         match (&left.kind, &right.kind) {
             (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
+            (&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
+                self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_fieldpat(l, r))
+            },
             (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
             },
@@ -223,6 +233,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
             (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
                 self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
             },
+            (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) =>
+                llang_item == rlang_item,
             _ => false,
         }
     }
@@ -601,6 +613,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             QPath::TypeRelative(_, ref path) => {
                 self.hash_name(path.ident.name);
             },
+            QPath::LangItem(lang_item, ..) => {
+                lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            }
         }
         // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
     }
@@ -710,6 +725,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_ty(ty);
                     segment.ident.name.hash(&mut self.s);
                 },
+                QPath::LangItem(lang_item, ..) => {
+                    lang_item.hash(&mut self.s);
+                }
             },
             TyKind::OpaqueDef(_, arg_list) => {
                 self.hash_generic_args(arg_list);
diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs
index d8fa1fa278e..4701a3f26e6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs
@@ -266,6 +266,9 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             println!("{}Relative Path, {:?}", ind, ty);
             println!("{}seg: {:?}", ind, seg);
         },
+        hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
+            println!("{}Lang Item Path, {:?}", ind, lang_item.name());
+        },
         hir::ExprKind::AddrOf(kind, ref muta, ref e) => {
             println!("{}AddrOf", ind);
             println!("kind: {:?}", kind);
@@ -488,6 +491,9 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
             println!("{}Relative Path, {:?}", ind, ty);
             println!("{}seg: {:?}", ind, seg);
         },
+        hir::PatKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
+            println!("{}Lang Item Path, {:?}", ind, lang_item.name());
+        },
         hir::PatKind::Tuple(pats, opt_dots_position) => {
             println!("{}Tuple", ind);
             if let Some(dot_position) = opt_dots_position {
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 223628cc610..a56b8203513 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -142,6 +142,14 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb
     }
 }
 
+/// Checks if the type is equal to a lang item
+pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
+    match ty.kind {
+        ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did,
+        _ => false,
+    }
+}
+
 /// Checks if the method call given in `expr` belongs to the given trait.
 pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
     let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
@@ -163,6 +171,7 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
     match *path {
         QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
         QPath::TypeRelative(_, ref seg) => seg,
+        QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
     }
 }
 
@@ -170,6 +179,7 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment
     match *path {
         QPath::Resolved(_, ref path) => path.segments.get(0),
         QPath::TypeRelative(_, ref seg) => Some(seg),
+        QPath::LangItem(..) => None,
     }
 }
 
@@ -196,6 +206,7 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
             },
             _ => false,
         },
+        QPath::LangItem(..) => false,
     }
 }
 
@@ -277,7 +288,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<def::Res> {
 pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
     match qpath {
         hir::QPath::Resolved(_, path) => path.res,
-        hir::QPath::TypeRelative(..) => {
+        hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
             if cx.tcx.has_typeck_results(id.owner.to_def_id()) {
                 cx.tcx.typeck(id.owner.to_def_id().expect_local()).qpath_res(qpath, id)
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index 923b319d777..9c28d63d414 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -84,19 +84,7 @@ pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
 pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
-pub const RANGE: [&str; 3] = ["core", "ops", "Range"];
 pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
-pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"];
-pub const RANGE_FROM_STD: [&str; 3] = ["std", "ops", "RangeFrom"];
-pub const RANGE_FULL: [&str; 4] = ["core", "ops", "range", "RangeFull"];
-pub const RANGE_FULL_STD: [&str; 3] = ["std", "ops", "RangeFull"];
-pub const RANGE_INCLUSIVE_NEW: [&str; 4] = ["core", "ops", "RangeInclusive", "new"];
-pub const RANGE_INCLUSIVE_STD_NEW: [&str; 4] = ["std", "ops", "RangeInclusive", "new"];
-pub const RANGE_STD: [&str; 3] = ["std", "ops", "Range"];
-pub const RANGE_TO: [&str; 3] = ["core", "ops", "RangeTo"];
-pub const RANGE_TO_INCLUSIVE: [&str; 3] = ["core", "ops", "RangeToInclusive"];
-pub const RANGE_TO_INCLUSIVE_STD: [&str; 3] = ["std", "ops", "RangeToInclusive"];
-pub const RANGE_TO_STD: [&str; 3] = ["std", "ops", "RangeTo"];
 pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
 pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
 pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
@@ -130,7 +118,6 @@ pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
 pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
 pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
 pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
-pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"];
 pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
 pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
 pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
diff --git a/src/tools/clippy/clippy_lints/src/utils/sugg.rs b/src/tools/clippy/clippy_lints/src/utils/sugg.rs
index 0ac7714fbeb..2955f8d8e59 100644
--- a/src/tools/clippy/clippy_lints/src/utils/sugg.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/sugg.rs
@@ -42,7 +42,7 @@ impl<'a> Sugg<'a> {
     pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> {
         snippet_opt(cx, expr.span).map(|snippet| {
             let snippet = Cow::Owned(snippet);
-            Self::hir_from_snippet(cx, expr, snippet)
+            Self::hir_from_snippet(expr, snippet)
         })
     }
 
@@ -80,13 +80,13 @@ impl<'a> Sugg<'a> {
     pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
         let snippet = snippet_with_macro_callsite(cx, expr.span, default);
 
-        Self::hir_from_snippet(cx, expr, snippet)
+        Self::hir_from_snippet(expr, snippet)
     }
 
     /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
     /// function variants of `Sugg`, since these use different snippet functions.
-    fn hir_from_snippet(cx: &LateContext<'_>, expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
-        if let Some(range) = higher::range(cx, expr) {
+    fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
+        if let Some(range) = higher::range(expr) {
             let op = match range.limits {
                 ast::RangeLimits::HalfOpen => AssocOp::DotDot,
                 ast::RangeLimits::Closed => AssocOp::DotDotEq,
diff --git a/src/tools/clippy/tests/ui/author/for_loop.stdout b/src/tools/clippy/tests/ui/author/for_loop.stdout
index 81ede955347..3bf7607c62f 100644
--- a/src/tools/clippy/tests/ui/author/for_loop.stdout
+++ b/src/tools/clippy/tests/ui/author/for_loop.stdout
@@ -3,10 +3,10 @@ if_chain! {
     if let ExprKind::Match(ref expr1, ref arms, MatchSource::ForLoopDesugar) = expr.kind;
     if let ExprKind::Call(ref func, ref args) = expr1.kind;
     if let ExprKind::Path(ref path) = func.kind;
-    if match_qpath(path, &["{{root}}", "std", "iter", "IntoIterator", "into_iter"]);
+    if matches!(path, QPath::LangItem(LangItem::IntoIterIntoIter, _));
     if args.len() == 1;
     if let ExprKind::Struct(ref path1, ref fields, None) = args[0].kind;
-    if match_qpath(path1, &["{{root}}", "std", "ops", "Range"]);
+    if matches!(path1, QPath::LangItem(LangItem::Range, _));
     if fields.len() == 2;
     // unimplemented: field checks
     if arms.len() == 1;
@@ -20,7 +20,7 @@ if_chain! {
     if let ExprKind::Match(ref expr2, ref arms1, MatchSource::ForLoopDesugar) = e.kind;
     if let ExprKind::Call(ref func1, ref args1) = expr2.kind;
     if let ExprKind::Path(ref path2) = func1.kind;
-    if match_qpath(path2, &["{{root}}", "std", "iter", "Iterator", "next"]);
+    if matches!(path2, QPath::LangItem(LangItem::IteratorNext, _));
     if args1.len() == 1;
     if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref inner) = args1[0].kind;
     if let ExprKind::Path(ref path3) = inner.kind;
@@ -31,13 +31,15 @@ if_chain! {
     if match_qpath(path4, &["__next"]);
     if let ExprKind::Path(ref path5) = value.kind;
     if match_qpath(path5, &["val"]);
-    if let PatKind::TupleStruct(ref path6, ref fields1, None) = arms1[0].pat.kind;
-    if match_qpath(path6, &["{{root}}", "std", "option", "Option", "Some"]);
+    if let PatKind::Struct(ref path6, ref fields1, false) = arms1[0].pat.kind;
+    if matches!(path6, QPath::LangItem(LangItem::OptionSome, _));
     if fields1.len() == 1;
     // unimplemented: field checks
     if let ExprKind::Break(ref destination, None) = arms1[1].body.kind;
-    if let PatKind::Path(ref path7) = arms1[1].pat.kind;
-    if match_qpath(path7, &["{{root}}", "std", "option", "Option", "None"]);
+    if let PatKind::Struct(ref path7, ref fields2, false) = arms1[1].pat.kind;
+    if matches!(path7, QPath::LangItem(LangItem::OptionNone, _));
+    if fields2.len() == 0;
+    // unimplemented: field checks
     if let StmtKind::Local(ref local1) = body.stmts[2].kind;
     if let Some(ref init) = local1.init;
     if let ExprKind::Path(ref path8) = init.kind;