about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_attr/src/builtin.rs26
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs94
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0539.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0542.md8
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0543.md10
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0549.md12
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0550.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0734.md1
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs7
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs11
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs5
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs48
-rw-r--r--compiler/rustc_passes/src/check_attr.rs76
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs10
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs31
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs9
-rw-r--r--compiler/rustc_typeck/src/check/method/confirm.rs16
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs14
19 files changed, 221 insertions, 167 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 8e748aaa58b..5a79cf68f11 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -679,12 +679,12 @@ where
             continue;
         }
 
-        if let Some((_, span)) = &depr {
-            struct_span_err!(diagnostic, attr.span, E0550, "multiple deprecated attributes")
-                .span_label(attr.span, "repeated deprecation attribute")
-                .span_label(*span, "first deprecation attribute")
+        // FIXME(jhpratt) remove this eventually
+        if attr.has_name(sym::rustc_deprecated) {
+            diagnostic
+                .struct_span_err(attr.span, "`#[rustc_deprecated]` has been removed")
+                .help("use `#[deprecated]` instead")
                 .emit();
-            break;
         }
 
         let Some(meta) = attr.meta() else {
@@ -742,12 +742,24 @@ where
                                     continue 'outer;
                                 }
                             }
-                            // FIXME(jhpratt) remove this after a bootstrap occurs. Emitting an
-                            // error specific to the renaming would be a good idea as well.
+                            // FIXME(jhpratt) remove this eventually
                             sym::reason if attr.has_name(sym::rustc_deprecated) => {
                                 if !get(mi, &mut note) {
                                     continue 'outer;
                                 }
+
+                                let mut diag = diagnostic
+                                    .struct_span_err(mi.span, "`reason` has been renamed");
+                                match note {
+                                    Some(note) => diag.span_suggestion(
+                                        mi.span,
+                                        "use `note` instead",
+                                        format!("note = \"{note}\""),
+                                        Applicability::MachineApplicable,
+                                    ),
+                                    None => diag.span_help(mi.span, "use `note` instead"),
+                                };
+                                diag.emit();
                             }
                             sym::suggestion => {
                                 if !sess.features_untracked().deprecated_suggestion {
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 1052d588fad..f88538f61ec 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -60,9 +60,9 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
 
         let mut rpo = traversal::reverse_postorder(body);
         let ccx = ConstCx::new(tcx, body);
-        let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
+        let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
 
-        let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates);
+        let promotable_candidates = validate_candidates(&ccx, &mut temps, &all_candidates);
 
         let promoted = promote_candidates(body, tcx, temps, promotable_candidates);
         self.promoted_fragments.set(promoted);
@@ -77,7 +77,7 @@ pub enum TempState {
     /// One direct assignment and any number of direct uses.
     /// A borrow of this temp is promotable if the assigned
     /// value is qualified as constant.
-    Defined { location: Location, uses: usize },
+    Defined { location: Location, uses: usize, valid: Result<(), ()> },
     /// Any other combination of assignments/uses.
     Unpromotable,
     /// This temp was part of an rvalue which got extracted
@@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
             match context {
                 PlaceContext::MutatingUse(MutatingUseContext::Store)
                 | PlaceContext::MutatingUse(MutatingUseContext::Call) => {
-                    *temp = TempState::Defined { location, uses: 0 };
+                    *temp = TempState::Defined { location, uses: 0, valid: Err(()) };
                     return;
                 }
                 _ => { /* mark as unpromotable below */ }
@@ -188,7 +188,7 @@ pub fn collect_temps_and_candidates<'tcx>(
 /// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion.
 struct Validator<'a, 'tcx> {
     ccx: &'a ConstCx<'a, 'tcx>,
-    temps: &'a IndexVec<Local, TempState>,
+    temps: &'a mut IndexVec<Local, TempState>,
 }
 
 impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
@@ -202,7 +202,7 @@ impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
 struct Unpromotable;
 
 impl<'tcx> Validator<'_, 'tcx> {
-    fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
+    fn validate_candidate(&mut self, candidate: Candidate) -> Result<(), Unpromotable> {
         let loc = candidate.location;
         let statement = &self.body[loc.block].statements[loc.statement_index];
         match &statement.kind {
@@ -234,7 +234,7 @@ impl<'tcx> Validator<'_, 'tcx> {
     }
 
     // FIXME(eddyb) maybe cache this?
-    fn qualif_local<Q: qualifs::Qualif>(&self, local: Local) -> bool {
+    fn qualif_local<Q: qualifs::Qualif>(&mut self, local: Local) -> bool {
         if let TempState::Defined { location: loc, .. } = self.temps[local] {
             let num_stmts = self.body[loc.block].statements.len();
 
@@ -272,40 +272,50 @@ impl<'tcx> Validator<'_, 'tcx> {
         }
     }
 
-    // FIXME(eddyb) maybe cache this?
-    fn validate_local(&self, local: Local) -> Result<(), Unpromotable> {
-        if let TempState::Defined { location: loc, .. } = self.temps[local] {
-            let block = &self.body[loc.block];
-            let num_stmts = block.statements.len();
-
-            if loc.statement_index < num_stmts {
-                let statement = &block.statements[loc.statement_index];
-                match &statement.kind {
-                    StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
-                    _ => {
-                        span_bug!(
-                            statement.source_info.span,
-                            "{:?} is not an assignment",
-                            statement
-                        );
-                    }
-                }
-            } else {
-                let terminator = block.terminator();
-                match &terminator.kind {
-                    TerminatorKind::Call { func, args, .. } => self.validate_call(func, args),
-                    TerminatorKind::Yield { .. } => Err(Unpromotable),
-                    kind => {
-                        span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
+    fn validate_local(&mut self, local: Local) -> Result<(), Unpromotable> {
+        if let TempState::Defined { location: loc, uses, valid } = self.temps[local] {
+            valid.or_else(|_| {
+                let ok = {
+                    let block = &self.body[loc.block];
+                    let num_stmts = block.statements.len();
+
+                    if loc.statement_index < num_stmts {
+                        let statement = &block.statements[loc.statement_index];
+                        match &statement.kind {
+                            StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
+                            _ => {
+                                span_bug!(
+                                    statement.source_info.span,
+                                    "{:?} is not an assignment",
+                                    statement
+                                );
+                            }
+                        }
+                    } else {
+                        let terminator = block.terminator();
+                        match &terminator.kind {
+                            TerminatorKind::Call { func, args, .. } => {
+                                self.validate_call(func, args)
+                            }
+                            TerminatorKind::Yield { .. } => Err(Unpromotable),
+                            kind => {
+                                span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
+                            }
+                        }
                     }
-                }
-            }
+                };
+                self.temps[local] = match ok {
+                    Ok(()) => TempState::Defined { location: loc, uses, valid: Ok(()) },
+                    Err(_) => TempState::Unpromotable,
+                };
+                ok
+            })
         } else {
             Err(Unpromotable)
         }
     }
 
-    fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
+    fn validate_place(&mut self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
         match place.last_projection() {
             None => self.validate_local(place.local),
             Some((place_base, elem)) => {
@@ -417,7 +427,7 @@ impl<'tcx> Validator<'_, 'tcx> {
         }
     }
 
-    fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> {
+    fn validate_operand(&mut self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> {
         match operand {
             Operand::Copy(place) | Operand::Move(place) => self.validate_place(place.as_ref()),
 
@@ -447,7 +457,7 @@ impl<'tcx> Validator<'_, 'tcx> {
         }
     }
 
-    fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
+    fn validate_ref(&mut self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
         match kind {
             // Reject these borrow types just to be safe.
             // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
@@ -480,7 +490,7 @@ impl<'tcx> Validator<'_, 'tcx> {
         Ok(())
     }
 
-    fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
+    fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
         match rvalue {
             Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
                 self.validate_operand(operand)?;
@@ -623,7 +633,7 @@ impl<'tcx> Validator<'_, 'tcx> {
     }
 
     fn validate_call(
-        &self,
+        &mut self,
         callee: &Operand<'tcx>,
         args: &[Operand<'tcx>],
     ) -> Result<(), Unpromotable> {
@@ -665,10 +675,10 @@ impl<'tcx> Validator<'_, 'tcx> {
 // FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
 pub fn validate_candidates(
     ccx: &ConstCx<'_, '_>,
-    temps: &IndexVec<Local, TempState>,
+    temps: &mut IndexVec<Local, TempState>,
     candidates: &[Candidate],
 ) -> Vec<Candidate> {
-    let validator = Validator { ccx, temps };
+    let mut validator = Validator { ccx, temps };
 
     candidates
         .iter()
@@ -720,7 +730,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
     fn promote_temp(&mut self, temp: Local) -> Local {
         let old_keep_original = self.keep_original;
         let loc = match self.temps[temp] {
-            TempState::Defined { location, uses } if uses > 0 => {
+            TempState::Defined { location, uses, .. } if uses > 0 => {
                 if uses > 1 {
                     self.keep_original = true;
                 }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md
index df2d7d910bb..c53d60a5f47 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0539.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0539.md
@@ -6,7 +6,7 @@ Erroneous code example:
 #![feature(staged_api)]
 #![stable(since = "1.0.0", feature = "test")]
 
-#[rustc_deprecated(reason)] // error!
+#[deprecated(note)] // error!
 #[unstable(feature = "deprecated_fn", issue = "123")]
 fn deprecated() {}
 
@@ -30,7 +30,7 @@ To fix these issues you need to give required key-value pairs.
 #![feature(staged_api)]
 #![stable(since = "1.0.0", feature = "test")]
 
-#[rustc_deprecated(since = "1.39.0", reason = "reason")] // ok!
+#[deprecated(since = "1.39.0", note = "reason")] // ok!
 #[unstable(feature = "deprecated_fn", issue = "123")]
 fn deprecated() {}
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0542.md b/compiler/rustc_error_codes/src/error_codes/E0542.md
index 7fecfeaa57c..c69e574179b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0542.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0542.md
@@ -13,8 +13,8 @@ fn _stable_fn() {}
 const fn _stable_const_fn() {}
 
 #[stable(feature = "_deprecated_fn", since = "0.1.0")]
-#[rustc_deprecated(
-    reason = "explanation for deprecation"
+#[deprecated(
+    note = "explanation for deprecation"
 )] // invalid
 fn _deprecated_fn() {}
 ```
@@ -32,9 +32,9 @@ fn _stable_fn() {}
 const fn _stable_const_fn() {}
 
 #[stable(feature = "_deprecated_fn", since = "0.1.0")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.0.0",
-    reason = "explanation for deprecation"
+    note = "explanation for deprecation"
 )] // ok!
 fn _deprecated_fn() {}
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0543.md b/compiler/rustc_error_codes/src/error_codes/E0543.md
index ba26f92e89f..d0b2e2f7a7d 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0543.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0543.md
@@ -1,4 +1,4 @@
-The `reason` value is missing in a stability attribute.
+The `note` value is missing in a stability attribute.
 
 Erroneous code example:
 
@@ -7,22 +7,22 @@ Erroneous code example:
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(since = "0.1.0", feature = "_deprecated_fn")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.0.0"
 )] // invalid
 fn _deprecated_fn() {}
 ```
 
-To fix this issue, you need to provide the `reason` field. Example:
+To fix this issue, you need to provide the `note` field. Example:
 
 ```
 #![feature(staged_api)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(since = "0.1.0", feature = "_deprecated_fn")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.0.0",
-    reason = "explanation for deprecation"
+    note = "explanation for deprecation"
 )] // ok!
 fn _deprecated_fn() {}
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md
index d4b78e7e0d6..70e458a9867 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0549.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0549.md
@@ -1,5 +1,5 @@
-A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable`
-attribute.
+A `deprecated` attribute wasn't paired with a `stable`/`unstable` attribute with
+`#![feature(staged_api)]` enabled.
 
 Erroneous code example:
 
@@ -7,9 +7,9 @@ Erroneous code example:
 #![feature(staged_api)]
 #![stable(since = "1.0.0", feature = "test")]
 
-#[rustc_deprecated(
+#[deprecated(
     since = "1.0.1",
-    reason = "explanation for deprecation"
+    note = "explanation for deprecation"
 )] // invalid
 fn _deprecated_fn() {}
 ```
@@ -22,9 +22,9 @@ Example:
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(since = "1.0.0", feature = "test")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.0.1",
-    reason = "explanation for deprecation"
+    note = "explanation for deprecation"
 )] // ok!
 fn _deprecated_fn() {}
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0550.md b/compiler/rustc_error_codes/src/error_codes/E0550.md
index 1487d701847..6aac5c969d2 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0550.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0550.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler
+
 More than one `deprecated` attribute has been put on an item.
 
 Erroneous code example:
 
-```compile_fail,E0550
+```compile_fail
 #[deprecated(note = "because why not?")]
 #[deprecated(note = "right?")] // error!
 fn the_banished() {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0734.md b/compiler/rustc_error_codes/src/error_codes/E0734.md
index 4b8e89a7060..b912061ec42 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0734.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0734.md
@@ -3,7 +3,6 @@ A stability attribute has been used outside of the standard library.
 Erroneous code example:
 
 ```compile_fail,E0734
-#[rustc_deprecated(since = "b", reason = "text")] // invalid
 #[stable(feature = "a", since = "b")] // invalid
 #[unstable(feature = "b", issue = "none")] // invalid
 fn foo(){}
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 33d2e82b24a..c5f42aa7af7 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -304,8 +304,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
             List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
             NameValueStr: "reason"
         ),
-        // This has special duplicate handling in E0550 to handle duplicates with rustc_deprecated
-        DuplicatesOk
+        ErrorFollowing
     ),
 
     // Crate properties:
@@ -469,10 +468,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // ==========================================================================
 
     ungated!(feature, CrateLevel, template!(List: "name1, name2, ..."), DuplicatesOk),
-    // DuplicatesOk since it has its own validation
+    // FIXME(jhpratt) remove this eventually
     ungated!(
         rustc_deprecated, Normal,
-        template!(List: r#"since = "version", note = "...""#), DuplicatesOk // See E0550
+        template!(List: r#"since = "version", note = "...""#), ErrorFollowing
     ),
     // DuplicatesOk since it has its own validation
     ungated!(
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index b8ba65adaa8..565ec4e5ab9 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2201,13 +2201,12 @@ declare_lint! {
     /// used by user code.
     ///
     /// This lint is only enabled in the standard library. It works with the
-    /// use of `#[rustc_deprecated]` with a `since` field of a version in the
-    /// future. This allows something to be marked as deprecated in a future
-    /// version, and then this lint will ensure that the item is no longer
-    /// used in the standard library. See the [stability documentation] for
-    /// more details.
+    /// use of `#[deprecated]` with a `since` field of a version in the future.
+    /// This allows something to be marked as deprecated in a future version,
+    /// and then this lint will ensure that the item is no longer used in the
+    /// standard library. See the [stability documentation] for more details.
     ///
-    /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#rustc_deprecated
+    /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#deprecated
     pub DEPRECATED_IN_FUTURE,
     Allow,
     "detects use of items that will be deprecated in a future version",
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 32041143240..6918046390e 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -118,8 +118,7 @@ pub fn deprecation_in_effect(depr: &Deprecation) -> bool {
     }
 
     if !is_since_rustc_version {
-        // The `since` field doesn't have semantic purpose in the stable `deprecated`
-        // attribute, only in `rustc_deprecated`.
+        // The `since` field doesn't have semantic purpose without `#![staged_api]`.
         return true;
     }
 
@@ -336,7 +335,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 // topmost deprecation. For example, if a struct is deprecated,
                 // the use of a field won't be linted.
                 //
-                // #[rustc_deprecated] however wants to emit down the whole
+                // With #![staged_api], we want to emit down the whole
                 // hierarchy.
                 let depr_attr = &depr_entry.attr;
                 if !skip || depr_attr.is_since_rustc_version {
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 5063420e975..5b1fb708729 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -10,7 +10,7 @@ use rustc_data_structures::intern::{Interned, WithStableHash};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
 use rustc_serialize::{self, Decodable, Encodable};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::DUMMY_SP;
 use smallvec::SmallVec;
 
 use core::intrinsics;
@@ -498,34 +498,14 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
-// Public trait `Subst`
-//
-// Just call `foo.subst(tcx, substs)` to perform a substitution across
-// `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
-// there is more information available (for better errors).
-
+// Just call `foo.subst(tcx, substs)` to perform a substitution across `foo`.
 pub trait Subst<'tcx>: Sized {
-    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self {
-        self.subst_spanned(tcx, substs, None)
-    }
-
-    fn subst_spanned(
-        self,
-        tcx: TyCtxt<'tcx>,
-        substs: &[GenericArg<'tcx>],
-        span: Option<Span>,
-    ) -> Self;
+    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self;
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T {
-    fn subst_spanned(
-        self,
-        tcx: TyCtxt<'tcx>,
-        substs: &[GenericArg<'tcx>],
-        span: Option<Span>,
-    ) -> T {
-        let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 };
+    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T {
+        let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
         self.fold_with(&mut folder)
     }
 }
@@ -537,9 +517,6 @@ struct SubstFolder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     substs: &'a [GenericArg<'tcx>],
 
-    /// The location for which the substitution is performed, if available.
-    span: Option<Span>,
-
     /// Number of region binders we have passed through while doing the substitution
     binders_passed: u32,
 }
@@ -571,13 +548,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
                 match rk {
                     Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
                     _ => {
-                        let span = self.span.unwrap_or(DUMMY_SP);
                         let msg = format!(
                             "Region parameter out of range \
                              when substituting in region {} (index={})",
                             data.name, data.index
                         );
-                        span_bug!(span, "{}", msg);
+                        span_bug!(DUMMY_SP, "{}", msg);
                     }
                 }
             }
@@ -617,9 +593,8 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
         let ty = match opt_ty {
             Some(GenericArgKind::Type(ty)) => ty,
             Some(kind) => {
-                let span = self.span.unwrap_or(DUMMY_SP);
                 span_bug!(
-                    span,
+                    DUMMY_SP,
                     "expected type for `{:?}` ({:?}/{}) but found {:?} \
                      when substituting, substs={:?}",
                     p,
@@ -630,9 +605,8 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
                 );
             }
             None => {
-                let span = self.span.unwrap_or(DUMMY_SP);
                 span_bug!(
-                    span,
+                    DUMMY_SP,
                     "type parameter `{:?}` ({:?}/{}) out of range \
                      when substituting, substs={:?}",
                     p,
@@ -652,9 +626,8 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
         let ct = match opt_ct {
             Some(GenericArgKind::Const(ct)) => ct,
             Some(kind) => {
-                let span = self.span.unwrap_or(DUMMY_SP);
                 span_bug!(
-                    span,
+                    DUMMY_SP,
                     "expected const for `{:?}` ({:?}/{}) but found {:?} \
                      when substituting substs={:?}",
                     p,
@@ -665,9 +638,8 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
                 );
             }
             None => {
-                let span = self.span.unwrap_or(DUMMY_SP);
                 span_bug!(
-                    span,
+                    DUMMY_SP,
                     "const parameter `{:?}` ({:?}/{}) out of range \
                      when substituting substs={:?}",
                     p,
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index b297012f19f..2b0fa57cba8 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -4,7 +4,8 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
+use rustc_ast::tokenstream::DelimSpan;
+use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MacArgs, MetaItemKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@@ -810,6 +811,68 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
+    /// Checks `#[doc(hidden)]` attributes. Returns `true` if valid.
+    fn check_doc_hidden(
+        &self,
+        attr: &Attribute,
+        meta_index: usize,
+        meta: &NestedMetaItem,
+        hir_id: HirId,
+        target: Target,
+    ) -> bool {
+        if let Target::AssocConst
+        | Target::AssocTy
+        | Target::Method(MethodKind::Trait { body: true }) = target
+        {
+            let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+            let containing_item = self.tcx.hir().expect_item(parent_hir_id);
+
+            if Target::from_item(containing_item) == Target::Impl {
+                let meta_items = attr.meta_item_list().unwrap();
+
+                let (span, replacement_span) = if meta_items.len() == 1 {
+                    (attr.span, attr.span)
+                } else {
+                    let meta_span = meta.span();
+                    (
+                        meta_span,
+                        meta_span.until(match meta_items.get(meta_index + 1) {
+                            Some(next_item) => next_item.span(),
+                            None => match attr.get_normal_item().args {
+                                MacArgs::Delimited(DelimSpan { close, .. }, ..) => close,
+                                _ => unreachable!(),
+                            },
+                        }),
+                    )
+                };
+
+                // FIXME: #[doc(hidden)] was previously erroneously allowed on trait impl items,
+                // so for backward compatibility only emit a warning and do not mark it as invalid.
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| {
+                    lint.build("`#[doc(hidden)]` is ignored on trait impl items")
+                        .warn(
+                            "this was previously accepted by the compiler but is \
+                             being phased out; it will become a hard error in \
+                             a future release!",
+                        )
+                        .note(
+                            "whether the impl item is `doc(hidden)` or not \
+                             entirely depends on the corresponding trait item",
+                        )
+                        .span_suggestion(
+                            replacement_span,
+                            "remove this attribute",
+                            String::new(),
+                            Applicability::MachineApplicable,
+                        )
+                        .emit();
+                });
+            }
+        }
+
+        true
+    }
+
     /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
     fn check_attr_not_crate_level(
         &self,
@@ -928,7 +991,7 @@ impl CheckAttrVisitor<'_> {
         let mut is_valid = true;
 
         if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() {
-            for meta in list {
+            for (meta_index, meta) in list.into_iter().enumerate() {
                 if let Some(i_meta) = meta.meta_item() {
                     match i_meta.name_or_empty() {
                         sym::alias
@@ -969,6 +1032,15 @@ impl CheckAttrVisitor<'_> {
                             is_valid = false;
                         }
 
+                        sym::hidden if !self.check_doc_hidden(attr,
+                            meta_index,
+                            meta,
+                            hir_id,
+                            target,
+                            ) => {
+                            is_valid = false;
+                        }
+
                         // no_default_passes: deprecated
                         // passes: deprecated
                         // plugins: removed, but rustdoc warns about it itself
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 93f6b4a6b5a..3c1676b1aac 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -523,11 +523,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                 self.astconv
                                     .normalize_ty(
                                         self.span,
-                                        tcx.at(self.span).type_of(param.def_id).subst_spanned(
-                                            tcx,
-                                            substs,
-                                            Some(self.span),
-                                        ),
+                                        tcx.at(self.span).type_of(param.def_id).subst(tcx, substs),
                                     )
                                     .into()
                             }
@@ -547,9 +543,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     GenericParamDefKind::Const { has_default } => {
                         let ty = tcx.at(self.span).type_of(param.def_id);
                         if !infer_args && has_default {
-                            tcx.const_param_default(param.def_id)
-                                .subst_spanned(tcx, substs.unwrap(), Some(self.span))
-                                .into()
+                            tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
                         } else {
                             if infer_args {
                                 self.astconv.ct_infer(ty, Some(param), self.span).into()
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index a1e8d2040dd..f3a5b9f13dd 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -44,7 +44,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
+use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeFoldable};
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -2034,17 +2034,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         base: &'tcx hir::Expr<'tcx>,
         def_id: DefId,
     ) {
-        let local_id = def_id.expect_local();
-        let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
-        let node = self.tcx.hir().get(hir_id);
-
-        if let Some(fields) = node.tuple_fields() {
-            let kind = match self.tcx.opt_def_kind(local_id) {
-                Some(DefKind::Ctor(of, _)) => of,
-                _ => return,
-            };
+        if let Some(local_id) = def_id.as_local() {
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
+            let node = self.tcx.hir().get(hir_id);
+
+            if let Some(fields) = node.tuple_fields() {
+                let kind = match self.tcx.opt_def_kind(local_id) {
+                    Some(DefKind::Ctor(of, _)) => of,
+                    _ => return,
+                };
 
-            suggest_call_constructor(base.span, kind, fields.len(), err);
+                suggest_call_constructor(base.span, kind, fields.len(), err);
+            }
+        } else {
+            // The logic here isn't smart but `associated_item_def_ids`
+            // doesn't work nicely on local.
+            if let DefKind::Ctor(of, _) = self.tcx.def_kind(def_id) {
+                let parent_def_id = self.tcx.parent(def_id);
+                let fields = self.tcx.associated_item_def_ids(parent_def_id);
+                suggest_call_constructor(base.span, of, fields.len(), err);
+            }
         }
     }
 
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 93b0edb84c0..d824c1d7cf2 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1403,10 +1403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // is missing.
                             let default = tcx.type_of(param.def_id);
                             self.fcx
-                                .normalize_ty(
-                                    self.span,
-                                    default.subst_spanned(tcx, substs.unwrap(), Some(self.span)),
-                                )
+                                .normalize_ty(self.span, default.subst(tcx, substs.unwrap()))
                                 .into()
                         } else {
                             // If no type arguments were provided, we have to infer them.
@@ -1418,9 +1415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                     GenericParamDefKind::Const { has_default } => {
                         if !infer_args && has_default {
-                            tcx.const_param_default(param.def_id)
-                                .subst_spanned(tcx, substs.unwrap(), Some(self.span))
-                                .into()
+                            tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
                         } else {
                             self.fcx.var_for_def(self.span, param)
                         }
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index bc0fa916556..1b619776b85 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -462,19 +462,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
 
         let sig = self.tcx.fn_sig(def_id);
 
-        // Instantiate late-bound regions and substitute the trait
-        // parameters into the method type to get the actual method type.
-        //
-        // N.B., instantiate late-bound regions first so that
-        // `instantiate_type_scheme` can normalize associated types that
-        // may reference those regions.
-        let method_sig = self.replace_bound_vars_with_fresh_vars(sig);
-        debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig);
+        let sig = sig.subst(self.tcx, all_substs);
+        debug!("type scheme substituted, sig={:?}", sig);
 
-        let method_sig = method_sig.subst(self.tcx, all_substs);
-        debug!("type scheme substituted, method_sig={:?}", method_sig);
+        let sig = self.replace_bound_vars_with_fresh_vars(sig);
+        debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
 
-        (method_sig, method_predicates)
+        (sig, method_predicates)
     }
 
     fn add_obligations(
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 8137d702921..1dd5e45fdc1 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -461,8 +461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
         let fn_sig = tcx.fn_sig(def_id);
-        let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
         let fn_sig = fn_sig.subst(self.tcx, substs);
+        let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
 
         let InferOk { value, obligations: o } = if is_op {
             self.normalize_op_associated_types_in_as_infer_ok(span, fn_sig, opt_input_expr)
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index c7d0f61c601..c28ab9fa1ee 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -1784,12 +1784,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         let generics = self.tcx.generics_of(method);
         assert_eq!(substs.len(), generics.parent_count as usize);
 
-        // Erase any late-bound regions from the method and substitute
-        // in the values from the substitution.
-        let xform_fn_sig = self.erase_late_bound_regions(fn_sig);
-
-        if generics.params.is_empty() {
-            xform_fn_sig.subst(self.tcx, substs)
+        let xform_fn_sig = if generics.params.is_empty() {
+            fn_sig.subst(self.tcx, substs)
         } else {
             let substs = InternalSubsts::for_item(self.tcx, method, |param, _| {
                 let i = param.index as usize;
@@ -1807,8 +1803,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     }
                 }
             });
-            xform_fn_sig.subst(self.tcx, substs)
-        }
+            fn_sig.subst(self.tcx, substs)
+        };
+
+        self.erase_late_bound_regions(xform_fn_sig)
     }
 
     /// Gets the type of an impl and generate substitutions with placeholders.