From 5fabdb8f7fd0c2c48d47ce08126d27ade5beefd9 Mon Sep 17 00:00:00 2001
From: ltdk <usr@ltdk.xyz>
Date: Sat, 28 May 2022 17:20:43 -0400
Subject: [PATCH 1/8] Add E0788 for improper #[no_coverage] usage

---
 compiler/rustc_error_codes/src/error_codes.rs |  1 +
 .../src/error_codes/E0788.md                  | 21 +++++
 compiler/rustc_passes/src/check_attr.rs       | 51 ++++++++++++
 src/test/ui/lint/no-coverage.rs               | 46 ++++++++++
 src/test/ui/lint/no-coverage.stderr           | 83 +++++++++++++++++++
 5 files changed, 202 insertions(+)
 create mode 100644 compiler/rustc_error_codes/src/error_codes/E0788.md
 create mode 100644 src/test/ui/lint/no-coverage.rs
 create mode 100644 src/test/ui/lint/no-coverage.stderr

diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 61a177f291b..0114461e388 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -491,6 +491,7 @@ E0784: include_str!("./error_codes/E0784.md"),
 E0785: include_str!("./error_codes/E0785.md"),
 E0786: include_str!("./error_codes/E0786.md"),
 E0787: include_str!("./error_codes/E0787.md"),
+E0788: include_str!("./error_codes/E0788.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/compiler/rustc_error_codes/src/error_codes/E0788.md b/compiler/rustc_error_codes/src/error_codes/E0788.md
new file mode 100644
index 00000000000..68bd53cea6f
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0788.md
@@ -0,0 +1,21 @@
+A `#[no_coverage]` attribute was incorrectly placed on something that couldn't
+be covered.
+
+Example of erroneous code:
+
+```compile_fail,E0788
+#[no_coverage]
+struct Foo;
+
+#[no_coverage]
+const FOO: Foo = Foo;
+```
+
+`#[no_coverage]` tells the compiler to not generate coverage instrumentation for
+a piece of code when the `-C instrument-coverage` flag is passed. Things like
+structs and consts are not coverable code, and thus cannot do anything with this
+attribute.
+
+If you wish to apply this attribute to all methods in an impl or module,
+manually annotate each method; it is not possible to annotate the entire impl
+with a `#[no_coverage]` attribute.
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 3d5da114ecf..f3734e1a120 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -76,6 +76,7 @@ impl CheckAttrVisitor<'_> {
         for attr in attrs {
             let attr_is_valid = match attr.name_or_empty() {
                 sym::inline => self.check_inline(hir_id, attr, span, target),
+                sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
                 sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
                 sym::marker => self.check_marker(hir_id, attr, span, target),
                 sym::rustc_must_implement_one_of => {
@@ -292,6 +293,56 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
+    /// Checks if a `#[no_coverage]` is applied directly to a function
+    fn check_no_coverage(
+        &self,
+        hir_id: HirId,
+        attr: &Attribute,
+        span: Span,
+        target: Target,
+    ) -> bool {
+        match target {
+            // no_coverage on function is fine
+            Target::Fn
+            | Target::Closure
+            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
+
+            // function prototypes can't be covered
+            Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+                    lint.build("`#[no_coverage]` is ignored on function prototypes").emit();
+                });
+                true
+            }
+
+            Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => {
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+                    lint.build("`#[no_coverage]` cannot be done recursively and must be applied to functions directly").emit();
+                });
+                true
+            }
+
+            Target::Expression | Target::Statement | Target::Arm => {
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+                    lint.build("`#[no_coverage]` can only be applied at the function level, not on code directly").emit();
+                });
+                true
+            }
+
+            _ => {
+                struct_span_err!(
+                    self.tcx.sess,
+                    attr.span,
+                    E0788,
+                    "`#[no_coverage]` must be applied to coverable code",
+                )
+                .span_label(span, "not coverable code")
+                .emit();
+                false
+            }
+        }
+    }
+
     fn check_generic_attr(
         &self,
         hir_id: HirId,
diff --git a/src/test/ui/lint/no-coverage.rs b/src/test/ui/lint/no-coverage.rs
new file mode 100644
index 00000000000..c02cd976bc9
--- /dev/null
+++ b/src/test/ui/lint/no-coverage.rs
@@ -0,0 +1,46 @@
+#![feature(extern_types)]
+#![feature(no_coverage)]
+#![feature(type_alias_impl_trait)]
+#![warn(unused_attributes)]
+
+trait Trait {
+    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    const X: u32;
+
+    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    type T;
+
+    type U;
+}
+
+impl Trait for () {
+    const X: u32 = 0;
+
+    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    type T = Self;
+
+    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    type U = impl Trait; //~ ERROR unconstrained opaque type
+}
+
+extern "C" {
+    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    static X: u32;
+
+    #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
+    type T;
+}
+
+#[no_coverage]
+fn main() {
+    #[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly
+    let _ = ();
+
+    match () {
+        #[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly
+        () => (),
+    }
+
+    #[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly
+    return ();
+}
diff --git a/src/test/ui/lint/no-coverage.stderr b/src/test/ui/lint/no-coverage.stderr
new file mode 100644
index 00000000000..8549eb699ee
--- /dev/null
+++ b/src/test/ui/lint/no-coverage.stderr
@@ -0,0 +1,83 @@
+warning: `#[no_coverage]` can only be applied at the function level, not on code directly
+  --> $DIR/no-coverage.rs:36:5
+   |
+LL |     #[no_coverage]
+   |     ^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/no-coverage.rs:4:9
+   |
+LL | #![warn(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+
+warning: `#[no_coverage]` can only be applied at the function level, not on code directly
+  --> $DIR/no-coverage.rs:40:9
+   |
+LL |         #[no_coverage]
+   |         ^^^^^^^^^^^^^^
+
+warning: `#[no_coverage]` can only be applied at the function level, not on code directly
+  --> $DIR/no-coverage.rs:44:5
+   |
+LL |     #[no_coverage]
+   |     ^^^^^^^^^^^^^^
+
+error[E0788]: `#[no_coverage]` must be applied to coverable code
+  --> $DIR/no-coverage.rs:7:5
+   |
+LL |     #[no_coverage]
+   |     ^^^^^^^^^^^^^^
+LL |     const X: u32;
+   |     ------------- not coverable code
+
+error[E0788]: `#[no_coverage]` must be applied to coverable code
+  --> $DIR/no-coverage.rs:10:5
+   |
+LL |     #[no_coverage]
+   |     ^^^^^^^^^^^^^^
+LL |     type T;
+   |     ------- not coverable code
+
+error[E0788]: `#[no_coverage]` must be applied to coverable code
+  --> $DIR/no-coverage.rs:19:5
+   |
+LL |     #[no_coverage]
+   |     ^^^^^^^^^^^^^^
+LL |     type T = Self;
+   |     -------------- not coverable code
+
+error[E0788]: `#[no_coverage]` must be applied to coverable code
+  --> $DIR/no-coverage.rs:22:5
+   |
+LL |     #[no_coverage]
+   |     ^^^^^^^^^^^^^^
+LL |     type U = impl Trait;
+   |     -------------------- not coverable code
+
+error[E0788]: `#[no_coverage]` must be applied to coverable code
+  --> $DIR/no-coverage.rs:27:5
+   |
+LL |     #[no_coverage]
+   |     ^^^^^^^^^^^^^^
+LL |     static X: u32;
+   |     -------------- not coverable code
+
+error[E0788]: `#[no_coverage]` must be applied to coverable code
+  --> $DIR/no-coverage.rs:30:5
+   |
+LL |     #[no_coverage]
+   |     ^^^^^^^^^^^^^^
+LL |     type T;
+   |     ------- not coverable code
+
+error: unconstrained opaque type
+  --> $DIR/no-coverage.rs:23:14
+   |
+LL |     type U = impl Trait;
+   |              ^^^^^^^^^^
+   |
+   = note: `U` must be used in combination with a concrete type within the same module
+
+error: aborting due to 7 previous errors; 3 warnings emitted
+
+For more information about this error, try `rustc --explain E0788`.

From a07290047e6b27638f491ee7ebb90e20fece2a79 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Sat, 7 May 2022 22:41:53 +0200
Subject: [PATCH 2/8] Compute lifetimes in scope at diagnostic time.

---
 compiler/rustc_ast_lowering/src/index.rs      |  7 ++
 compiler/rustc_hir/src/hir.rs                 |  2 +
 compiler/rustc_hir_pretty/src/lib.rs          | 35 ++++----
 compiler/rustc_middle/src/hir/map/mod.rs      |  6 +-
 .../src/middle/resolve_lifetime.rs            |  3 +-
 compiler/rustc_resolve/src/late/lifetimes.rs  | 33 +++----
 .../drop_ranges/cfg_build.rs                  |  1 +
 compiler/rustc_typeck/src/collect/type_of.rs  | 19 +---
 .../wrong_number_of_generic_args.rs           | 89 +++++++++++--------
 9 files changed, 101 insertions(+), 94 deletions(-)

diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index c506360aa8a..4da09c4ef48 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -313,6 +313,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         });
     }
 
+    fn visit_assoc_type_binding(&mut self, type_binding: &'hir TypeBinding<'hir>) {
+        self.insert(type_binding.span, type_binding.hir_id, Node::TypeBinding(type_binding));
+        self.with_parent(type_binding.hir_id, |this| {
+            intravisit::walk_assoc_type_binding(this, type_binding)
+        })
+    }
+
     fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
         // Do not visit the duplicate information in TraitItemRef. We want to
         // map the actual nodes, not the duplicate ones in the *Ref.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index cb2e66090e7..01cedccf997 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3302,6 +3302,7 @@ pub enum Node<'hir> {
     Stmt(&'hir Stmt<'hir>),
     PathSegment(&'hir PathSegment<'hir>),
     Ty(&'hir Ty<'hir>),
+    TypeBinding(&'hir TypeBinding<'hir>),
     TraitRef(&'hir TraitRef<'hir>),
     Binding(&'hir Pat<'hir>),
     Pat(&'hir Pat<'hir>),
@@ -3347,6 +3348,7 @@ impl<'hir> Node<'hir> {
             | Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
             Node::Lifetime(lt) => Some(lt.name.ident()),
             Node::GenericParam(p) => Some(p.name.ident()),
+            Node::TypeBinding(b) => Some(b.ident),
             Node::Param(..)
             | Node::AnonConst(..)
             | Node::Expr(..)
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 4558a3d10c4..fb40008d60b 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -85,6 +85,7 @@ impl<'a> State<'a> {
             Node::Stmt(a) => self.print_stmt(&a),
             Node::PathSegment(a) => self.print_path_segment(&a),
             Node::Ty(a) => self.print_type(&a),
+            Node::TypeBinding(a) => self.print_type_binding(&a),
             Node::TraitRef(a) => self.print_trait_ref(&a),
             Node::Binding(a) | Node::Pat(a) => self.print_pat(&a),
             Node::Arm(a) => self.print_arm(&a),
@@ -1703,21 +1704,7 @@ impl<'a> State<'a> {
 
             for binding in generic_args.bindings.iter() {
                 start_or_comma(self);
-                self.print_ident(binding.ident);
-                self.print_generic_args(binding.gen_args, false, false);
-                self.space();
-                match generic_args.bindings[0].kind {
-                    hir::TypeBindingKind::Equality { ref term } => {
-                        self.word_space("=");
-                        match term {
-                            Term::Ty(ref ty) => self.print_type(ty),
-                            Term::Const(ref c) => self.print_anon_const(c),
-                        }
-                    }
-                    hir::TypeBindingKind::Constraint { bounds } => {
-                        self.print_bounds(":", bounds);
-                    }
-                }
+                self.print_type_binding(binding);
             }
 
             if !empty.get() {
@@ -1726,6 +1713,24 @@ impl<'a> State<'a> {
         }
     }
 
+    pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
+        self.print_ident(binding.ident);
+        self.print_generic_args(binding.gen_args, false, false);
+        self.space();
+        match binding.kind {
+            hir::TypeBindingKind::Equality { ref term } => {
+                self.word_space("=");
+                match term {
+                    Term::Ty(ref ty) => self.print_type(ty),
+                    Term::Const(ref c) => self.print_anon_const(c),
+                }
+            }
+            hir::TypeBindingKind::Constraint { bounds } => {
+                self.print_bounds(":", bounds);
+            }
+        }
+    }
+
     pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
         self.maybe_print_comment(pat.span.lo());
         self.ann.pre(self, AnnNode::Pat(pat));
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 779af7a3827..ebda9f7588d 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -298,6 +298,7 @@ impl<'hir> Map<'hir> {
             Node::Stmt(_)
             | Node::PathSegment(_)
             | Node::Ty(_)
+            | Node::TypeBinding(_)
             | Node::Infer(_)
             | Node::TraitRef(_)
             | Node::Pat(_)
@@ -323,7 +324,8 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn get_parent_node(self, hir_id: HirId) -> HirId {
-        self.find_parent_node(hir_id).unwrap()
+        self.find_parent_node(hir_id)
+            .unwrap_or_else(|| bug!("No parent for node {:?}", self.node_to_string(hir_id)))
     }
 
     /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
@@ -973,6 +975,7 @@ impl<'hir> Map<'hir> {
                     .with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi()))
             }
             Node::Ty(ty) => ty.span,
+            Node::TypeBinding(tb) => tb.span,
             Node::TraitRef(tr) => tr.path.span,
             Node::Binding(pat) => pat.span,
             Node::Pat(pat) => pat.span,
@@ -1205,6 +1208,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         Some(Node::Stmt(_)) => node_str("stmt"),
         Some(Node::PathSegment(_)) => node_str("path segment"),
         Some(Node::Ty(_)) => node_str("type"),
+        Some(Node::TypeBinding(_)) => node_str("type binding"),
         Some(Node::TraitRef(_)) => node_str("trait ref"),
         Some(Node::Binding(_)) => node_str("local"),
         Some(Node::Pat(_)) => node_str("pat"),
diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
index cdc0d076801..7d0b751d35a 100644
--- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs
+++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
@@ -23,8 +23,7 @@ pub enum Region {
 pub enum LifetimeScopeForPath {
     /// Contains all lifetime names that are in scope and could possibly be used in generics
     /// arguments of path.
-    NonElided(Vec<LocalDefId>),
-
+    NonElided,
     /// Information that allows us to suggest args of the form `<'_>` in case
     /// no generic arguments were provided for a path.
     Elided,
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 11f80b314d7..50e067e225f 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -517,30 +517,16 @@ fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::
 
 #[tracing::instrument(level = "debug")]
 fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath {
-    let mut available_lifetimes = vec![];
     loop {
         match scope {
-            Scope::Binder { lifetimes, s, .. } => {
-                available_lifetimes.extend(lifetimes.keys());
-                scope = s;
-            }
-            Scope::Body { s, .. } => {
-                scope = s;
-            }
-            Scope::Elision { elide, s } => {
-                if let Elide::Exact(_) = elide {
-                    return LifetimeScopeForPath::Elided;
-                } else {
-                    scope = s;
-                }
-            }
-            Scope::ObjectLifetimeDefault { s, .. } => {
-                scope = s;
-            }
-            Scope::Root => {
-                return LifetimeScopeForPath::NonElided(available_lifetimes);
-            }
-            Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => {
+            Scope::Elision { elide: Elide::Exact(_), .. } => return LifetimeScopeForPath::Elided,
+            Scope::Root => return LifetimeScopeForPath::NonElided,
+            Scope::Binder { s, .. }
+            | Scope::Body { s, .. }
+            | Scope::ObjectLifetimeDefault { s, .. }
+            | Scope::Supertrait { s, .. }
+            | Scope::TraitRefBoundary { s, .. }
+            | Scope::Elision { s, .. } => {
                 scope = s;
             }
         }
@@ -2170,6 +2156,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
             // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
             Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None,
+
+            Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => None,
+
             // Everything else (only closures?) doesn't
             // actually enjoy elision in return types.
             _ => {
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
index 417778cc57d..58b63804b4a 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
@@ -249,6 +249,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
                 | hir::Node::Stmt(..)
                 | hir::Node::PathSegment(..)
                 | hir::Node::Ty(..)
+                | hir::Node::TypeBinding(..)
                 | hir::Node::TraitRef(..)
                 | hir::Node::Binding(..)
                 | hir::Node::Pat(..)
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 7e3fefe4502..2433401b7f0 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -450,21 +450,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     .discr_type()
                     .to_ty(tcx),
 
-                Node::TraitRef(trait_ref @ &TraitRef {
-                  path, ..
-                }) if let Some((binding, seg)) =
-                  path
-                      .segments
-                      .iter()
-                      .find_map(|seg| {
-                          seg.args?.bindings
-                              .iter()
-                              .find_map(|binding| if binding.opt_const()?.hir_id == hir_id {
-                                Some((binding, seg))
-                              } else {
-                                None
-                              })
-                      }) =>
+                Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, ..  })
+                    if let Node::TraitRef(trait_ref) = tcx.hir().get(
+                        tcx.hir().get_parent_node(binding_id)
+                    ) =>
                 {
                   let Some(trait_def_id) = trait_ref.trait_def_id() else {
                     return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index bc3a3db9fda..c433c5ebbd3 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -291,7 +291,52 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     }
 
     // Creates lifetime name suggestions from the lifetime parameter names
-    fn get_lifetime_args_suggestions_from_param_names(&self, num_params_to_take: usize) -> String {
+    fn get_lifetime_args_suggestions_from_param_names(
+        &self,
+        path_hir_id: Option<hir::HirId>,
+        num_params_to_take: usize,
+    ) -> String {
+        debug!(?path_hir_id);
+
+        if let Some(path_hir_id) = path_hir_id {
+            // We first try to get lifetime name suggestions from scope or elision information.
+            // If none is available we use the parameter definitions
+            if let Some(LifetimeScopeForPath::Elided) = self.tcx.lifetime_scope(path_hir_id) {
+                // Use suggestions of the form `<'_, '_>` in case lifetime can be elided
+                return ["'_"].repeat(num_params_to_take).join(",");
+            }
+
+            let mut ret = Vec::new();
+            for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
+                debug!(?id);
+                let params = if let Some(generics) = node.generics() {
+                    generics.params
+                } else if let hir::Node::Ty(ty) = node
+                    && let hir::TyKind::BareFn(bare_fn) = ty.kind
+                {
+                    bare_fn.generic_params
+                } else {
+                    &[]
+                };
+                ret.extend(params.iter().filter_map(|p| {
+                    let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
+                        = p.kind
+                    else { return None };
+                    let hir::ParamName::Plain(name) = p.name else { return None };
+                    Some(name.to_string())
+                }));
+                if ret.len() >= num_params_to_take {
+                    return ret[..num_params_to_take].join(", ");
+                }
+                // We cannot refer to lifetimes defined in an outer function.
+                if let hir::Node::Item(_) = node {
+                    break;
+                }
+            }
+        }
+
+        // We could not gather enough lifetime parameters in the scope.
+        // We use the parameter names from the target type's definition instead.
         self.gen_params
             .params
             .iter()
@@ -501,44 +546,10 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         let num_params_to_take = num_missing_args;
         let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
 
-        // we first try to get lifetime name suggestions from scope or elision information. If none is
-        // available we use the parameter definitions
-        let suggested_args = if let Some(hir_id) = self.path_segment.hir_id {
-            if let Some(lifetimes_in_scope) = self.tcx.lifetime_scope(hir_id) {
-                match lifetimes_in_scope {
-                    LifetimeScopeForPath::NonElided(param_names) => {
-                        debug!("NonElided(param_names: {:?})", param_names);
-
-                        if param_names.len() >= num_params_to_take {
-                            // use lifetime parameters in scope for suggestions
-                            param_names
-                                .iter()
-                                .take(num_params_to_take)
-                                .map(|def_id| {
-                                    self.tcx.item_name(def_id.to_def_id()).to_ident_string()
-                                })
-                                .collect::<Vec<_>>()
-                                .join(", ")
-                        } else {
-                            // Not enough lifetime arguments in scope -> create suggestions from
-                            // lifetime parameter names in definition. An error for the incorrect
-                            // lifetime scope will be output later.
-                            self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
-                        }
-                    }
-                    LifetimeScopeForPath::Elided => {
-                        debug!("Elided");
-                        // use suggestions of the form `<'_, '_>` in case lifetime can be elided
-                        ["'_"].repeat(num_params_to_take).join(",")
-                    }
-                }
-            } else {
-                self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
-            }
-        } else {
-            self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
-        };
-
+        let suggested_args = self.get_lifetime_args_suggestions_from_param_names(
+            self.path_segment.hir_id,
+            num_params_to_take,
+        );
         debug!("suggested_args: {:?}", &suggested_args);
 
         match self.angle_brackets {

From af8739b96efa97694526e478985960b4c9fc09f5 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Sat, 4 Jun 2022 15:31:04 +0200
Subject: [PATCH 3/8] Completely remove LifetimeScopeForPath.

---
 .../src/middle/resolve_lifetime.rs            | 13 ---
 compiler/rustc_middle/src/query/mod.rs        |  5 --
 compiler/rustc_middle/src/ty/context.rs       |  6 +-
 compiler/rustc_middle/src/ty/query.rs         |  4 +-
 compiler/rustc_resolve/src/late/lifetimes.rs  | 88 ++-----------------
 .../wrong_number_of_generic_args.rs           |  8 --
 6 files changed, 7 insertions(+), 117 deletions(-)

diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
index 7d0b751d35a..c71ba7b1753 100644
--- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs
+++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
@@ -16,19 +16,6 @@ pub enum Region {
     Free(DefId, /* lifetime decl */ DefId),
 }
 
-/// This is used in diagnostics to improve suggestions for missing generic arguments.
-/// It gives information on the type of lifetimes that are in scope for a particular `PathSegment`,
-/// so that we can e.g. suggest elided-lifetimes-in-paths of the form <'_, '_> e.g.
-#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
-pub enum LifetimeScopeForPath {
-    /// Contains all lifetime names that are in scope and could possibly be used in generics
-    /// arguments of path.
-    NonElided,
-    /// Information that allows us to suggest args of the form `<'_>` in case
-    /// no generic arguments were provided for a path.
-    Elided,
-}
-
 /// A set containing, at most, one known element.
 /// If two distinct values are inserted into a set, then it
 /// becomes `Many`, which can be used to detect ambiguities.
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 899d6c7e490..ef23a182bf5 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1599,11 +1599,6 @@ rustc_queries! {
         desc { "looking up late bound vars" }
     }
 
-    query lifetime_scope_map(_: LocalDefId) -> Option<FxHashMap<ItemLocalId, LifetimeScopeForPath>> {
-        storage(ArenaCacheSelector<'tcx>)
-        desc { "finds the lifetime scope for an HirId of a PathSegment" }
-    }
-
     query visibility(def_id: DefId) -> ty::Visibility {
         desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 72e2beb372d..c23b97eba1e 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -6,7 +6,7 @@ use crate::hir::place::Place as HirPlace;
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
-use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
+use crate::middle::resolve_lifetime;
 use crate::middle::stability;
 use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
 use crate::mir::{
@@ -2821,10 +2821,6 @@ impl<'tcx> TyCtxt<'tcx> {
         )
     }
 
-    pub fn lifetime_scope(self, id: HirId) -> Option<&'tcx LifetimeScopeForPath> {
-        self.lifetime_scope_map(id.owner).as_ref().and_then(|map| map.get(&id.local_id))
-    }
-
     /// Whether the `def_id` counts as const fn in the current crate, considering all active
     /// feature gates
     pub fn is_const_fn(self, def_id: DefId) -> bool {
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 65f41c5266d..db92ab0aa9a 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -6,9 +6,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
 use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use crate::middle::lib_features::LibFeatures;
 use crate::middle::privacy::AccessLevels;
-use crate::middle::resolve_lifetime::{
-    LifetimeScopeForPath, ObjectLifetimeDefault, Region, ResolveLifetimes,
-};
+use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes};
 use crate::middle::stability::{self, DeprecationEntry};
 use crate::mir;
 use crate::mir::interpret::GlobalId;
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 50e067e225f..359535951de 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -8,12 +8,11 @@
 
 use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
 use rustc_ast::walk_list;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
-use rustc_hir::hir_id::ItemLocalId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
 use rustc_hir::{GenericParamKind, HirIdMap};
@@ -141,9 +140,6 @@ struct NamedRegionMap {
     // - trait refs
     // - bound types (like `T` in `for<'a> T<'a>: Foo`)
     late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
-
-    // maps `PathSegment` `HirId`s to lifetime scopes.
-    scope_for_path: Option<FxHashMap<LocalDefId, FxHashMap<ItemLocalId, LifetimeScopeForPath>>>,
 }
 
 pub(crate) struct LifetimeContext<'a, 'tcx> {
@@ -353,10 +349,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
             _ => None,
         },
         late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
-        lifetime_scope_map: |tcx, id| {
-            let item_id = item_for(tcx, id);
-            do_resolve(tcx, item_id, false, true).scope_for_path.unwrap().remove(&id)
-        },
 
         ..*providers
     };
@@ -397,7 +389,7 @@ fn resolve_lifetimes_trait_definition(
     tcx: TyCtxt<'_>,
     local_def_id: LocalDefId,
 ) -> ResolveLifetimes {
-    convert_named_region_map(do_resolve(tcx, local_def_id, true, false))
+    convert_named_region_map(do_resolve(tcx, local_def_id, true))
 }
 
 /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
@@ -405,21 +397,17 @@ fn resolve_lifetimes_trait_definition(
 /// `named_region_map`, `is_late_bound_map`, etc.
 #[tracing::instrument(level = "debug", skip(tcx))]
 fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
-    convert_named_region_map(do_resolve(tcx, local_def_id, false, false))
+    convert_named_region_map(do_resolve(tcx, local_def_id, false))
 }
 
 fn do_resolve(
     tcx: TyCtxt<'_>,
     local_def_id: LocalDefId,
     trait_definition_only: bool,
-    with_scope_for_path: bool,
 ) -> NamedRegionMap {
     let item = tcx.hir().expect_item(local_def_id);
-    let mut named_region_map = NamedRegionMap {
-        defs: Default::default(),
-        late_bound_vars: Default::default(),
-        scope_for_path: with_scope_for_path.then(|| Default::default()),
-    };
+    let mut named_region_map =
+        NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() };
     let mut visitor = LifetimeContext {
         tcx,
         map: &mut named_region_map,
@@ -515,24 +503,6 @@ fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::
     }
 }
 
-#[tracing::instrument(level = "debug")]
-fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath {
-    loop {
-        match scope {
-            Scope::Elision { elide: Elide::Exact(_), .. } => return LifetimeScopeForPath::Elided,
-            Scope::Root => return LifetimeScopeForPath::NonElided,
-            Scope::Binder { s, .. }
-            | Scope::Body { s, .. }
-            | Scope::ObjectLifetimeDefault { s, .. }
-            | Scope::Supertrait { s, .. }
-            | Scope::TraitRefBoundary { s, .. }
-            | Scope::Elision { s, .. } => {
-                scope = s;
-            }
-        }
-    }
-}
-
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     /// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref.
     fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderScopeType) {
@@ -1172,53 +1142,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         }
     }
 
-    fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) {
-        let scope = self.scope;
-        if let Some(scope_for_path) = self.map.scope_for_path.as_mut() {
-            // We add lifetime scope information for `Ident`s in associated type bindings and use
-            // the `HirId` of the type binding as the key in `LifetimeMap`
-            let lifetime_scope = get_lifetime_scopes_for_path(scope);
-            let map = scope_for_path.entry(type_binding.hir_id.owner).or_default();
-            map.insert(type_binding.hir_id.local_id, lifetime_scope);
-        }
-        hir::intravisit::walk_assoc_type_binding(self, type_binding);
-    }
-
     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
         for (i, segment) in path.segments.iter().enumerate() {
             let depth = path.segments.len() - i - 1;
             if let Some(ref args) = segment.args {
                 self.visit_segment_args(path.res, depth, args);
             }
-
-            let scope = self.scope;
-            if let Some(scope_for_path) = self.map.scope_for_path.as_mut() {
-                // Add lifetime scope information to path segment. Note we cannot call `visit_path_segment`
-                // here because that call would yield to resolution problems due to `walk_path_segment`
-                // being called, which processes the path segments generic args, which we have already
-                // processed using `visit_segment_args`.
-                let lifetime_scope = get_lifetime_scopes_for_path(scope);
-                if let Some(hir_id) = segment.hir_id {
-                    let map = scope_for_path.entry(hir_id.owner).or_default();
-                    map.insert(hir_id.local_id, lifetime_scope);
-                }
-            }
         }
     }
 
-    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx hir::PathSegment<'tcx>) {
-        let scope = self.scope;
-        if let Some(scope_for_path) = self.map.scope_for_path.as_mut() {
-            let lifetime_scope = get_lifetime_scopes_for_path(scope);
-            if let Some(hir_id) = path_segment.hir_id {
-                let map = scope_for_path.entry(hir_id.owner).or_default();
-                map.insert(hir_id.local_id, lifetime_scope);
-            }
-        }
-
-        intravisit::walk_path_segment(self, path_span, path_segment);
-    }
-
     fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
         let output = match fd.output {
             hir::FnRetTy::DefaultReturn(_) => None,
@@ -2480,16 +2412,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
         };
 
-        // If we specifically need the `scope_for_path` map, then we're in the
-        // diagnostic pass and we don't want to emit more errors.
-        if self.map.scope_for_path.is_some() {
-            self.tcx.sess.delay_span_bug(
-                rustc_span::DUMMY_SP,
-                "Encountered unexpected errors during diagnostics related part",
-            );
-            return;
-        }
-
         let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
         spans.sort();
         let mut spans_dedup = spans.clone();
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index c433c5ebbd3..edd2aedfe87 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -5,7 +5,6 @@ use rustc_errors::{
 };
 use rustc_hir as hir;
 use rustc_middle::hir::map::fn_sig;
-use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
 use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
 use rustc_session::Session;
 use rustc_span::def_id::DefId;
@@ -299,13 +298,6 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         debug!(?path_hir_id);
 
         if let Some(path_hir_id) = path_hir_id {
-            // We first try to get lifetime name suggestions from scope or elision information.
-            // If none is available we use the parameter definitions
-            if let Some(LifetimeScopeForPath::Elided) = self.tcx.lifetime_scope(path_hir_id) {
-                // Use suggestions of the form `<'_, '_>` in case lifetime can be elided
-                return ["'_"].repeat(num_params_to_take).join(",");
-            }
-
             let mut ret = Vec::new();
             for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
                 debug!(?id);

From f71ad2f9920817b24a0253566f528bda845d9374 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Sun, 5 Jun 2022 09:59:26 +0200
Subject: [PATCH 4/8] Suggest 'static when in static/const items.

---
 .../wrong_number_of_generic_args.rs           | 24 +++++++++++++++++++
 .../elided-in-expr-position.stderr            |  4 ++--
 .../issue-81862.stderr                        |  2 +-
 .../missing-lifetime-specifier.stderr         | 16 ++++++-------
 4 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index edd2aedfe87..c440e93fe0a 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -317,6 +317,30 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
                     let hir::ParamName::Plain(name) = p.name else { return None };
                     Some(name.to_string())
                 }));
+                // Suggest `'static` when in const/static item-like.
+                if let hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
+                    ..
+                })
+                | hir::Node::TraitItem(hir::TraitItem {
+                    kind: hir::TraitItemKind::Const { .. },
+                    ..
+                })
+                | hir::Node::ImplItem(hir::ImplItem {
+                    kind: hir::ImplItemKind::Const { .. },
+                    ..
+                })
+                | hir::Node::ForeignItem(hir::ForeignItem {
+                    kind: hir::ForeignItemKind::Static { .. },
+                    ..
+                })
+                | hir::Node::AnonConst(..) = node
+                {
+                    ret.extend(
+                        std::iter::repeat("'static".to_owned())
+                            .take(num_params_to_take.saturating_sub(ret.len())),
+                    );
+                }
                 if ret.len() >= num_params_to_take {
                     return ret[..num_params_to_take].join(", ");
                 }
diff --git a/src/test/ui/generic-associated-types/elided-in-expr-position.stderr b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr
index 9263f3d67e3..b395a1cfd8a 100644
--- a/src/test/ui/generic-associated-types/elided-in-expr-position.stderr
+++ b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr
@@ -11,7 +11,7 @@ LL |     type Assoc<'a> where Self: 'a;
    |          ^^^^^ --
 help: add missing lifetime argument
    |
-LL |     fn g(&self) -> Self::Assoc<'_>;
+LL |     fn g(&self) -> Self::Assoc<'a>;
    |                          ~~~~~~~~~
 
 error[E0107]: missing generics for associated type `Trait::Assoc`
@@ -27,7 +27,7 @@ LL |     type Assoc<'a> where Self: 'a;
    |          ^^^^^ --
 help: add missing lifetime argument
    |
-LL |     fn g(&self) -> Self::Assoc<'_> {
+LL |     fn g(&self) -> Self::Assoc<'a> {
    |                          ~~~~~~~~~
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/generic-associated-types/issue-81862.stderr b/src/test/ui/generic-associated-types/issue-81862.stderr
index 024f8ad89f7..c664b3ee668 100644
--- a/src/test/ui/generic-associated-types/issue-81862.stderr
+++ b/src/test/ui/generic-associated-types/issue-81862.stderr
@@ -11,7 +11,7 @@ LL |     type Item<'a>;
    |          ^^^^ --
 help: add missing lifetime argument
    |
-LL |     fn next(&mut self) -> Option<Self::Item<'_>>;
+LL |     fn next(&mut self) -> Option<Self::Item<'a>>;
    |                                        ~~~~~~~~
 
 error: aborting due to previous error
diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.stderr b/src/test/ui/suggestions/missing-lifetime-specifier.stderr
index b04ea1c9158..1498337549d 100644
--- a/src/test/ui/suggestions/missing-lifetime-specifier.stderr
+++ b/src/test/ui/suggestions/missing-lifetime-specifier.stderr
@@ -171,8 +171,8 @@ LL | pub union Qux<'t, 'k, I> {
    |           ^^^ --  --
 help: add missing lifetime argument
    |
-LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
-   |                                                       ++++
+LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                                       +++++++++
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:43:44
@@ -243,8 +243,8 @@ LL | pub union Qux<'t, 'k, I> {
    |           ^^^ --  --
 help: add missing lifetime argument
    |
-LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
-   |                                                       ++++
+LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                                       +++++++++
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:51:45
@@ -261,8 +261,8 @@ LL | trait Tar<'t, 'k, I> {}
    |       ^^^ --  --
 help: add missing lifetime argument
    |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
-   |                                                        ++++
+LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                                        +++++++++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/missing-lifetime-specifier.rs:51:44
@@ -360,8 +360,8 @@ LL | trait Tar<'t, 'k, I> {}
    |       ^^^ --  --
 help: add missing lifetime argument
    |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
-   |                                                        ++++
+LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                                        +++++++++
 
 error: aborting due to 24 previous errors
 

From a6207ec975abeb6132aeeede0d3895dbe1d877a8 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 5 Jun 2022 13:24:10 -0400
Subject: [PATCH 5/8] interpret: do not claim UB until we looked more into
 variadic functions

---
 compiler/rustc_const_eval/src/interpret/terminator.rs | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 10da2f803af..57d06b48ca4 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -353,12 +353,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // FIXME: for variadic support, do we have to somehow determine callee's extra_args?
                 let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
 
-                if callee_fn_abi.c_variadic != caller_fn_abi.c_variadic {
-                    throw_ub_format!(
-                        "calling a c-variadic function via a non-variadic call site, or vice versa"
-                    );
-                }
-                if callee_fn_abi.c_variadic {
+                if callee_fn_abi.c_variadic || caller_fn_abi.c_variadic {
                     throw_unsup_format!("calling a c-variadic function is not supported");
                 }
 

From 9473e2195518d64074e8e3f85d64c82fe285915c Mon Sep 17 00:00:00 2001
From: ltdk <usr@ltdk.xyz>
Date: Sun, 5 Jun 2022 22:24:14 -0400
Subject: [PATCH 6/8] Changes from code review

---
 .../src/error_codes/E0788.md                  |  9 +++-
 compiler/rustc_passes/src/check_attr.rs       |  5 +-
 src/test/ui/lint/no-coverage.rs               | 15 ++++--
 src/test/ui/lint/no-coverage.stderr           | 50 +++++++++++++------
 4 files changed, 56 insertions(+), 23 deletions(-)

diff --git a/compiler/rustc_error_codes/src/error_codes/E0788.md b/compiler/rustc_error_codes/src/error_codes/E0788.md
index 68bd53cea6f..d26f9b59455 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0788.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0788.md
@@ -1,5 +1,10 @@
-A `#[no_coverage]` attribute was incorrectly placed on something that couldn't
-be covered.
+A `#[no_coverage]` attribute was applied to something which does not show up
+in code coverage, or is too granular to be excluded from the coverage report.
+
+For now, this attribute can only be applied to function, method, and closure
+definitions. In the future, it may be added to statements, blocks, and
+expressions, and for the time being, using this attribute in those places
+will just emit an `unused_attributes` lint instead of this error.
 
 Example of erroneous code:
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index f3734e1a120..67144d03d98 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -317,14 +317,15 @@ impl CheckAttrVisitor<'_> {
 
             Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => {
                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    lint.build("`#[no_coverage]` cannot be done recursively and must be applied to functions directly").emit();
+                    lint.build("`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly").emit();
                 });
                 true
             }
 
             Target::Expression | Target::Statement | Target::Arm => {
                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    lint.build("`#[no_coverage]` can only be applied at the function level, not on code directly").emit();
+                    lint.build("`#[no_coverage]` may only be applied to function definitions")
+                        .emit();
                 });
                 true
             }
diff --git a/src/test/ui/lint/no-coverage.rs b/src/test/ui/lint/no-coverage.rs
index c02cd976bc9..ff24c12b2bc 100644
--- a/src/test/ui/lint/no-coverage.rs
+++ b/src/test/ui/lint/no-coverage.rs
@@ -2,7 +2,11 @@
 #![feature(no_coverage)]
 #![feature(type_alias_impl_trait)]
 #![warn(unused_attributes)]
+#![no_coverage]
+//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
 
+#[no_coverage]
+//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
 trait Trait {
     #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
     const X: u32;
@@ -13,6 +17,8 @@ trait Trait {
     type U;
 }
 
+#[no_coverage]
+//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
 impl Trait for () {
     const X: u32 = 0;
 
@@ -33,14 +39,17 @@ extern "C" {
 
 #[no_coverage]
 fn main() {
-    #[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly
+    #[no_coverage]
+    //~^ WARN `#[no_coverage]` may only be applied to function definitions
     let _ = ();
 
     match () {
-        #[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly
+        #[no_coverage]
+        //~^ WARN `#[no_coverage]` may only be applied to function definitions
         () => (),
     }
 
-    #[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly
+    #[no_coverage]
+    //~^ WARN `#[no_coverage]` may only be applied to function definitions
     return ();
 }
diff --git a/src/test/ui/lint/no-coverage.stderr b/src/test/ui/lint/no-coverage.stderr
index 8549eb699ee..8452ccc7a03 100644
--- a/src/test/ui/lint/no-coverage.stderr
+++ b/src/test/ui/lint/no-coverage.stderr
@@ -1,8 +1,8 @@
-warning: `#[no_coverage]` can only be applied at the function level, not on code directly
-  --> $DIR/no-coverage.rs:36:5
+warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+  --> $DIR/no-coverage.rs:8:1
    |
-LL |     #[no_coverage]
-   |     ^^^^^^^^^^^^^^
+LL | #[no_coverage]
+   | ^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/no-coverage.rs:4:9
@@ -10,20 +10,32 @@ note: the lint level is defined here
 LL | #![warn(unused_attributes)]
    |         ^^^^^^^^^^^^^^^^^
 
-warning: `#[no_coverage]` can only be applied at the function level, not on code directly
-  --> $DIR/no-coverage.rs:40:9
+warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+  --> $DIR/no-coverage.rs:20:1
+   |
+LL | #[no_coverage]
+   | ^^^^^^^^^^^^^^
+
+warning: `#[no_coverage]` may only be applied to function definitions
+  --> $DIR/no-coverage.rs:42:5
+   |
+LL |     #[no_coverage]
+   |     ^^^^^^^^^^^^^^
+
+warning: `#[no_coverage]` may only be applied to function definitions
+  --> $DIR/no-coverage.rs:47:9
    |
 LL |         #[no_coverage]
    |         ^^^^^^^^^^^^^^
 
-warning: `#[no_coverage]` can only be applied at the function level, not on code directly
-  --> $DIR/no-coverage.rs:44:5
+warning: `#[no_coverage]` may only be applied to function definitions
+  --> $DIR/no-coverage.rs:52:5
    |
 LL |     #[no_coverage]
    |     ^^^^^^^^^^^^^^
 
 error[E0788]: `#[no_coverage]` must be applied to coverable code
-  --> $DIR/no-coverage.rs:7:5
+  --> $DIR/no-coverage.rs:11:5
    |
 LL |     #[no_coverage]
    |     ^^^^^^^^^^^^^^
@@ -31,7 +43,7 @@ LL |     const X: u32;
    |     ------------- not coverable code
 
 error[E0788]: `#[no_coverage]` must be applied to coverable code
-  --> $DIR/no-coverage.rs:10:5
+  --> $DIR/no-coverage.rs:14:5
    |
 LL |     #[no_coverage]
    |     ^^^^^^^^^^^^^^
@@ -39,7 +51,7 @@ LL |     type T;
    |     ------- not coverable code
 
 error[E0788]: `#[no_coverage]` must be applied to coverable code
-  --> $DIR/no-coverage.rs:19:5
+  --> $DIR/no-coverage.rs:25:5
    |
 LL |     #[no_coverage]
    |     ^^^^^^^^^^^^^^
@@ -47,7 +59,7 @@ LL |     type T = Self;
    |     -------------- not coverable code
 
 error[E0788]: `#[no_coverage]` must be applied to coverable code
-  --> $DIR/no-coverage.rs:22:5
+  --> $DIR/no-coverage.rs:28:5
    |
 LL |     #[no_coverage]
    |     ^^^^^^^^^^^^^^
@@ -55,7 +67,7 @@ LL |     type U = impl Trait;
    |     -------------------- not coverable code
 
 error[E0788]: `#[no_coverage]` must be applied to coverable code
-  --> $DIR/no-coverage.rs:27:5
+  --> $DIR/no-coverage.rs:33:5
    |
 LL |     #[no_coverage]
    |     ^^^^^^^^^^^^^^
@@ -63,21 +75,27 @@ LL |     static X: u32;
    |     -------------- not coverable code
 
 error[E0788]: `#[no_coverage]` must be applied to coverable code
-  --> $DIR/no-coverage.rs:30:5
+  --> $DIR/no-coverage.rs:36:5
    |
 LL |     #[no_coverage]
    |     ^^^^^^^^^^^^^^
 LL |     type T;
    |     ------- not coverable code
 
+warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+  --> $DIR/no-coverage.rs:5:1
+   |
+LL | #![no_coverage]
+   | ^^^^^^^^^^^^^^^
+
 error: unconstrained opaque type
-  --> $DIR/no-coverage.rs:23:14
+  --> $DIR/no-coverage.rs:29:14
    |
 LL |     type U = impl Trait;
    |              ^^^^^^^^^^
    |
    = note: `U` must be used in combination with a concrete type within the same module
 
-error: aborting due to 7 previous errors; 3 warnings emitted
+error: aborting due to 7 previous errors; 6 warnings emitted
 
 For more information about this error, try `rustc --explain E0788`.

From 343c135e0cfa28c07a68ada80c829fec91c47e26 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= <matthias.krueger@famsik.de>
Date: Mon, 6 Jun 2022 11:39:54 +0200
Subject: [PATCH 7/8] E0432: rust 2018 -> rust 2018 or later    in --explain
 message

---
 compiler/rustc_error_codes/src/error_codes/E0432.md | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_error_codes/src/error_codes/E0432.md b/compiler/rustc_error_codes/src/error_codes/E0432.md
index a6e2acac5d2..2920e2623fb 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0432.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0432.md
@@ -10,10 +10,10 @@ In Rust 2015, paths in `use` statements are relative to the crate root. To
 import items relative to the current and parent modules, use the `self::` and
 `super::` prefixes, respectively.
 
-In Rust 2018, paths in `use` statements are relative to the current module
-unless they begin with the name of a crate or a literal `crate::`, in which
-case they start from the crate root. As in Rust 2015 code, the `self::` and
-`super::` prefixes refer to the current and parent modules respectively.
+In Rust 2018 or later, paths in `use` statements are relative to the current
+module unless they begin with the name of a crate or a literal `crate::`, in
+which case they start from the crate root. As in Rust 2015 code, the `self::`
+and `super::` prefixes refer to the current and parent modules respectively.
 
 Also verify that you didn't misspell the import name and that the import exists
 in the module from where you tried to import it. Example:
@@ -38,8 +38,8 @@ use core::any;
 # fn main() {}
 ```
 
-In Rust 2018 the `extern crate` declaration is not required and you can instead
-just `use` it:
+Since Rust 2018 the `extern crate` declaration is not required and
+you can instead just `use` it:
 
 ```edition2018
 use core::any; // No extern crate required in Rust 2018.

From b3cd892ae153fb8eb10a6b386518ffca16834d8e Mon Sep 17 00:00:00 2001
From: SparrowLii <liyuan179@huawei.com>
Date: Mon, 6 Jun 2022 18:05:07 +0800
Subject: [PATCH 8/8] Avoid creating `SmallVec`s in `global_llvm_features`

---
 compiler/rustc_codegen_llvm/src/llvm_util.rs | 70 +++++++++++---------
 1 file changed, 37 insertions(+), 33 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 7b407c94e7b..ce6c6e3215c 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -218,15 +218,17 @@ pub fn check_tied_features(
     sess: &Session,
     features: &FxHashMap<&str, bool>,
 ) -> Option<&'static [&'static str]> {
-    for tied in tied_target_features(sess) {
-        // Tied features must be set to the same value, or not set at all
-        let mut tied_iter = tied.iter();
-        let enabled = features.get(tied_iter.next().unwrap());
-        if tied_iter.any(|f| enabled != features.get(f)) {
-            return Some(tied);
+    if !features.is_empty() {
+        for tied in tied_target_features(sess) {
+            // Tied features must be set to the same value, or not set at all
+            let mut tied_iter = tied.iter();
+            let enabled = features.get(tied_iter.next().unwrap());
+            if tied_iter.any(|f| enabled != features.get(f)) {
+                return Some(tied);
+            }
         }
     }
-    None
+    return None;
 }
 
 // Used to generate cfg variables and apply features
@@ -440,6 +442,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
 
     // -Ctarget-features
     let supported_features = supported_target_features(sess);
+    let mut featsmap = FxHashMap::default();
     let feats = sess
         .opts
         .cg
@@ -485,35 +488,36 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
                 }
                 diag.emit();
             }
-            Some((enable_disable, feature))
-        })
-        .collect::<SmallVec<[(char, &str); 8]>>();
 
-    if diagnostics {
-        // FIXME(nagisa): figure out how to not allocate a full hashset here.
-        let featmap = feats.iter().map(|&(flag, feat)| (feat, flag == '+')).collect();
-        if let Some(f) = check_tied_features(sess, &featmap) {
-            sess.err(&format!(
-                "target features {} must all be enabled or disabled together",
-                f.join(", ")
-            ));
-        }
+            if diagnostics {
+                // FIXME(nagisa): figure out how to not allocate a full hashset here.
+                featsmap.insert(feature, enable_disable == '+');
+            }
+
+            // rustc-specific features do not get passed down to LLVM…
+            if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
+                return None;
+            }
+            // ... otherwise though we run through `to_llvm_features` when
+            // passing requests down to LLVM. This means that all in-language
+            // features also work on the command line instead of having two
+            // different names when the LLVM name and the Rust name differ.
+            Some(
+                to_llvm_features(sess, feature)
+                    .into_iter()
+                    .map(move |f| format!("{}{}", enable_disable, f)),
+            )
+        })
+        .flatten();
+    features.extend(feats);
+
+    if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
+        sess.err(&format!(
+            "target features {} must all be enabled or disabled together",
+            f.join(", ")
+        ));
     }
 
-    features.extend(feats.into_iter().flat_map(|(enable_disable, feature)| {
-        // rustc-specific features do not get passed down to LLVM…
-        if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
-            return SmallVec::<[_; 2]>::new();
-        }
-        // ... otherwise though we run through `to_llvm_features` when
-        // passing requests down to LLVM. This means that all in-language
-        // features also work on the command line instead of having two
-        // different names when the LLVM name and the Rust name differ.
-        to_llvm_features(sess, feature)
-            .into_iter()
-            .map(|f| format!("{}{}", enable_disable, f))
-            .collect()
-    }));
     features
 }