about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Markeffsky <@>2022-12-25 22:16:04 +0100
committerLukas Markeffsky <@>2022-12-26 16:35:21 +0100
commit1eba6c404fa3e64607fc3826214bd61ae10fa5bb (patch)
tree939b08823ed2fc38a4f1deb7e488cb251247b808
parent83e653920d694a010fad8c7d87d302c2d5b3a177 (diff)
downloadrust-1eba6c404fa3e64607fc3826214bd61ae10fa5bb.tar.gz
rust-1eba6c404fa3e64607fc3826214bd61ae10fa5bb.zip
address review comments + better tests
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs17
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs7
-rw-r--r--compiler/rustc_lint/src/builtin.rs114
-rw-r--r--src/test/ui/rust-2018/edition-lint-infer-outlives-macro.fixed137
-rw-r--r--src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs126
-rw-r--r--src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr102
6 files changed, 405 insertions, 98 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index bda914d2888..294ffec8a5e 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1316,6 +1316,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 param.id,
                 &param.kind,
                 &param.bounds,
+                param.colon_span,
+                generics.span,
                 itctx,
                 PredicateOrigin::GenericParam,
             )
@@ -1365,6 +1367,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         id: NodeId,
         kind: &GenericParamKind,
         bounds: &[GenericBound],
+        colon_span: Option<Span>,
+        parent_span: Span,
         itctx: &ImplTraitContext,
         origin: PredicateOrigin,
     ) -> Option<hir::WherePredicate<'hir>> {
@@ -1377,8 +1381,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let ident = self.lower_ident(ident);
         let param_span = ident.span;
-        let span =
-            bounds.iter().fold(param_span.shrink_to_hi(), |span, bound| span.to(bound.span()));
+
+        // Reconstruct the span of the entire predicate from the individual generic bounds.
+        let span_start = colon_span.unwrap_or_else(|| param_span.shrink_to_hi());
+        let span = bounds.iter().fold(span_start, |span_accum, bound| {
+            match bound.span().find_ancestor_inside(parent_span) {
+                Some(bound_span) => span_accum.to(bound_span),
+                None => span_accum,
+            }
+        });
+        let span = self.lower_span(span);
+
         match kind {
             GenericParamKind::Const { .. } => None,
             GenericParamKind::Type { .. } => {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 0ef784a4453..a2b0f112e3b 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2247,6 +2247,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     ) -> (hir::GenericParam<'hir>, Option<hir::WherePredicate<'hir>>, hir::TyKind<'hir>) {
         // Add a definition for the in-band `Param`.
         let def_id = self.local_def_id(node_id);
+        let span = self.lower_span(span);
 
         // Set the name to `impl Bound1 + Bound2`.
         let param = hir::GenericParam {
@@ -2254,7 +2255,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             def_id,
             name: ParamName::Plain(self.lower_ident(ident)),
             pure_wrt_drop: false,
-            span: self.lower_span(span),
+            span,
             kind: hir::GenericParamKind::Type { default: None, synthetic: true },
             colon_span: None,
         };
@@ -2264,6 +2265,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             node_id,
             &GenericParamKind::Type { default: None },
             bounds,
+            /* colon_span */ None,
+            span,
             &ImplTraitContext::Universal,
             hir::PredicateOrigin::ImplTrait,
         );
@@ -2273,7 +2276,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let ty = hir::TyKind::Path(hir::QPath::Resolved(
             None,
             self.arena.alloc(hir::Path {
-                span: self.lower_span(span),
+                span,
                 res,
                 segments:
                     arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 3fc86545ed4..cdb901b7f86 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -55,7 +55,7 @@ use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, InnerSpan, Span, SyntaxContext};
+use rustc_span::{BytePos, InnerSpan, Span};
 use rustc_target::abi::{Abi, VariantIdx};
 use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
 use rustc_trait_selection::traits::{self, misc::can_type_implement_copy, EvaluationResult};
@@ -2184,7 +2184,7 @@ impl ExplicitOutlivesRequirements {
         tcx: TyCtxt<'tcx>,
         bounds: &hir::GenericBounds<'_>,
         inferred_outlives: &[ty::Region<'tcx>],
-        span_cx: SyntaxContext,
+        predicate_span: Span,
     ) -> Vec<(usize, Span)> {
         use rustc_middle::middle::resolve_lifetime::Region;
 
@@ -2207,8 +2207,8 @@ impl ExplicitOutlivesRequirements {
                     return None;
                 }
 
-                let span = bound.span();
-                if span.ctxt() != span_cx || in_external_macro(tcx.sess, span) {
+                let span = bound.span().find_ancestor_inside(predicate_span)?;
+                if in_external_macro(tcx.sess, span) {
                     return None;
                 }
 
@@ -2279,9 +2279,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
         use rustc_middle::middle::resolve_lifetime::Region;
 
         let def_id = item.owner_id.def_id;
-        if let hir::ItemKind::Struct(_, ref hir_generics)
-        | hir::ItemKind::Enum(_, ref hir_generics)
-        | hir::ItemKind::Union(_, ref hir_generics) = item.kind
+        if let hir::ItemKind::Struct(_, hir_generics)
+        | hir::ItemKind::Enum(_, hir_generics)
+        | hir::ItemKind::Union(_, hir_generics) = item.kind
         {
             let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
             if inferred_outlives.is_empty() {
@@ -2296,47 +2296,48 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
             let mut dropped_predicate_count = 0;
             let num_predicates = hir_generics.predicates.len();
             for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
-                let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
-                    hir::WherePredicate::RegionPredicate(predicate) => {
-                        if let Some(Region::EarlyBound(region_def_id)) =
-                            cx.tcx.named_region(predicate.lifetime.hir_id)
-                        {
-                            (
-                                Self::lifetimes_outliving_lifetime(
-                                    inferred_outlives,
-                                    region_def_id,
-                                ),
-                                &predicate.bounds,
-                                predicate.span,
-                                predicate.in_where_clause,
-                            )
-                        } else {
-                            continue;
-                        }
-                    }
-                    hir::WherePredicate::BoundPredicate(predicate) => {
-                        // FIXME we can also infer bounds on associated types,
-                        // and should check for them here.
-                        match predicate.bounded_ty.kind {
-                            hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
-                                let Res::Def(DefKind::TyParam, def_id) = path.res else {
-                                    continue;
-                                };
-                                let index = ty_generics.param_def_id_to_index[&def_id];
+                let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
+                    match where_predicate {
+                        hir::WherePredicate::RegionPredicate(predicate) => {
+                            if let Some(Region::EarlyBound(region_def_id)) =
+                                cx.tcx.named_region(predicate.lifetime.hir_id)
+                            {
                                 (
-                                    Self::lifetimes_outliving_type(inferred_outlives, index),
+                                    Self::lifetimes_outliving_lifetime(
+                                        inferred_outlives,
+                                        region_def_id,
+                                    ),
                                     &predicate.bounds,
                                     predicate.span,
-                                    predicate.origin == PredicateOrigin::WhereClause,
+                                    predicate.in_where_clause,
                                 )
-                            }
-                            _ => {
+                            } else {
                                 continue;
                             }
                         }
-                    }
-                    _ => continue,
-                };
+                        hir::WherePredicate::BoundPredicate(predicate) => {
+                            // FIXME we can also infer bounds on associated types,
+                            // and should check for them here.
+                            match predicate.bounded_ty.kind {
+                                hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
+                                    let Res::Def(DefKind::TyParam, def_id) = path.res else {
+                                    continue;
+                                };
+                                    let index = ty_generics.param_def_id_to_index[&def_id];
+                                    (
+                                        Self::lifetimes_outliving_type(inferred_outlives, index),
+                                        &predicate.bounds,
+                                        predicate.span,
+                                        predicate.origin == PredicateOrigin::WhereClause,
+                                    )
+                                }
+                                _ => {
+                                    continue;
+                                }
+                            }
+                        }
+                        _ => continue,
+                    };
                 if relevant_lifetimes.is_empty() {
                     continue;
                 }
@@ -2345,7 +2346,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                     cx.tcx,
                     bounds,
                     &relevant_lifetimes,
-                    span.ctxt(),
+                    predicate_span,
                 );
                 bound_count += bound_spans.len();
 
@@ -2355,15 +2356,15 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                 }
 
                 if drop_predicate && !in_where_clause {
-                    lint_spans.push(span);
+                    lint_spans.push(predicate_span);
                 } else if drop_predicate && i + 1 < num_predicates {
                     // If all the bounds on a predicate were inferable and there are
                     // further predicates, we want to eat the trailing comma.
                     let next_predicate_span = hir_generics.predicates[i + 1].span();
-                    where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
+                    where_lint_spans.push(predicate_span.to(next_predicate_span.shrink_to_lo()));
                 } else {
                     where_lint_spans.extend(self.consolidate_outlives_bound_spans(
-                        span.shrink_to_lo(),
+                        predicate_span.shrink_to_lo(),
                         bounds,
                         bound_spans,
                     ));
@@ -2384,12 +2385,26 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                     } else {
                         hir_generics.span.shrink_to_hi().to(where_span)
                     };
-                lint_spans.push(full_where_span);
+
+                // Due to macro expansions, the `full_where_span` might not actually contain all predicates.
+                if where_lint_spans.iter().all(|&sp| full_where_span.contains(sp)) {
+                    lint_spans.push(full_where_span);
+                } else {
+                    lint_spans.extend(where_lint_spans);
+                }
             } else {
                 lint_spans.extend(where_lint_spans);
             }
 
             if !lint_spans.is_empty() {
+                // Do not automatically delete outlives requirements from macros.
+                let applicability = if lint_spans.iter().all(|sp| sp.can_be_used_for_suggestions())
+                {
+                    Applicability::MachineApplicable
+                } else {
+                    Applicability::MaybeIncorrect
+                };
+
                 cx.struct_span_lint(
                     EXPLICIT_OUTLIVES_REQUIREMENTS,
                     lint_spans.clone(),
@@ -2397,11 +2412,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                     |lint| {
                         lint.set_arg("count", bound_count).multipart_suggestion(
                             fluent::suggestion,
-                            lint_spans
-                                .into_iter()
-                                .map(|span| (span, String::new()))
-                                .collect::<Vec<_>>(),
-                            Applicability::MachineApplicable,
+                            lint_spans.into_iter().map(|span| (span, String::new())).collect(),
+                            applicability,
                         )
                     },
                 );
diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.fixed b/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.fixed
new file mode 100644
index 00000000000..8cdb08e81b9
--- /dev/null
+++ b/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.fixed
@@ -0,0 +1,137 @@
+// edition:2018
+// aux-build:edition-lint-infer-outlives-macro.rs
+// run-rustfix
+
+#![deny(explicit_outlives_requirements)]
+#![allow(dead_code)]
+
+#[macro_use]
+extern crate edition_lint_infer_outlives_macro;
+
+// Test that the lint does not fire if the predicate is from the local crate,
+// but all the bounds are from an external macro.
+macro_rules! make_foo {
+    ($a:tt) => {
+        struct Foo<$a, 'b: $a> {
+            foo: &$a &'b (),
+        }
+
+        struct FooWhere<$a, 'b> where 'b: $a {
+            foo: &$a &'b (),
+        }
+    }
+}
+
+gimme_a! {make_foo!}
+
+struct Bar<'a, 'b> {
+    //~^ ERROR: outlives requirements can be inferred
+    bar: &'a &'b (),
+}
+
+struct BarWhere<'a, 'b> {
+    //~^ ERROR: outlives requirements can be inferred
+    bar: &'a &'b (),
+}
+
+// Test that the lint *does* fire if the predicate is contained in a local macro.
+mod everything_inside {
+    macro_rules! m {
+        ('b: 'a) => {
+            struct Foo<'a, 'b>(&'a &'b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<'a, 'b>(&'a &'b ()) ;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<'a, 'b>(&'a &'b ()) where (): Sized, ;
+            //~^ ERROR: outlives requirements can be inferred
+        };
+    }
+    m!('b: 'a);
+}
+
+mod inner_lifetime_outside_colon_inside {
+    macro_rules! m {
+        ($b:lifetime: 'a) => {
+            struct Foo<'a, $b>(&'a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<'a, $b>(&'a &$b ()) ;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<'a, $b>(&'a &$b ()) where (): Sized, ;
+            //~^ ERROR: outlives requirements can be inferred
+        }
+    }
+    m!('b: 'a);
+}
+
+mod outer_lifetime_outside_colon_inside {
+    macro_rules! m {
+        ('b: $a:lifetime) => {
+            struct Foo<$a, 'b: $a>(&$a &'b ());
+            struct Bar<$a, 'b>(&$a &'b ()) where 'b: $a;
+            struct Baz<$a, 'b>(&$a &'b ()) where (): Sized, 'b: $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod both_lifetimes_outside_colon_inside {
+    macro_rules! m {
+        ($b:lifetime: $a:lifetime) => {
+            struct Foo<$a, $b: $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b: $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b: $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod everything_outside {
+    macro_rules! m {
+        ($b:lifetime $colon:tt $a:lifetime) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod everything_outside_with_tt_inner {
+    macro_rules! m {
+        ($b:tt $colon:tt $a:lifetime) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+// FIXME: These should be consistent.
+mod everything_outside_with_tt_outer {
+    macro_rules! m {
+        ($b:lifetime $colon:tt $a:tt) => {
+            struct Foo<$a, $b >(&$a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod everything_outside_with_tt_both {
+    macro_rules! m {
+        ($b:tt $colon:tt $a:tt) => {
+            struct Foo<$a, $b >(&$a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<$a, $b>(&$a &$b ()) where ;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, ;
+            //~^ ERROR: outlives requirements can be inferred
+        }
+    }
+    m!('b: 'a);
+}
+
+fn main() {}
diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs b/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs
index d96def8173a..647906c2dc2 100644
--- a/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs
+++ b/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs
@@ -1,25 +1,25 @@
 // edition:2018
 // aux-build:edition-lint-infer-outlives-macro.rs
-
-// Test that the lint does not fire if the where predicate
-// is from the local crate, but all the bounds are from an
-// external macro.
+// run-rustfix
 
 #![deny(explicit_outlives_requirements)]
+#![allow(dead_code)]
 
 #[macro_use]
 extern crate edition_lint_infer_outlives_macro;
 
+// Test that the lint does not fire if the predicate is from the local crate,
+// but all the bounds are from an external macro.
 macro_rules! make_foo {
     ($a:tt) => {
-        struct Foo<$a, 'b> where 'b: $a {
+        struct Foo<$a, 'b: $a> {
             foo: &$a &'b (),
         }
 
-        struct Foo2<$a, 'b: $a> {
+        struct FooWhere<$a, 'b> where 'b: $a {
             foo: &$a &'b (),
         }
-    };
+    }
 }
 
 gimme_a! {make_foo!}
@@ -29,41 +29,109 @@ struct Bar<'a, 'b: 'a> {
     bar: &'a &'b (),
 }
 
-macro_rules! make_quux {
-    () => {
-        struct Quux<'a, 'b> where 'b: 'a {
+struct BarWhere<'a, 'b> where 'b: 'a {
+    //~^ ERROR: outlives requirements can be inferred
+    bar: &'a &'b (),
+}
+
+// Test that the lint *does* fire if the predicate is contained in a local macro.
+mod everything_inside {
+    macro_rules! m {
+        ('b: 'a) => {
+            struct Foo<'a, 'b: 'a>(&'a &'b ());
             //~^ ERROR: outlives requirements can be inferred
-            baz: &'a &'b (),
-        }
+            struct Bar<'a, 'b>(&'a &'b ()) where 'b: 'a;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<'a, 'b>(&'a &'b ()) where (): Sized, 'b: 'a;
+            //~^ ERROR: outlives requirements can be inferred
+        };
+    }
+    m!('b: 'a);
+}
 
-        struct Quux2<'a, 'b: 'a> {
+mod inner_lifetime_outside_colon_inside {
+    macro_rules! m {
+        ($b:lifetime: 'a) => {
+            struct Foo<'a, $b: 'a>(&'a &$b ());
             //~^ ERROR: outlives requirements can be inferred
-            baz: &'a &'b (),
+            struct Bar<'a, $b>(&'a &$b ()) where $b: 'a;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<'a, $b>(&'a &$b ()) where (): Sized, $b: 'a;
+            //~^ ERROR: outlives requirements can be inferred
+        }
+    }
+    m!('b: 'a);
+}
+
+mod outer_lifetime_outside_colon_inside {
+    macro_rules! m {
+        ('b: $a:lifetime) => {
+            struct Foo<$a, 'b: $a>(&$a &'b ());
+            struct Bar<$a, 'b>(&$a &'b ()) where 'b: $a;
+            struct Baz<$a, 'b>(&$a &'b ()) where (): Sized, 'b: $a;
         }
-    };
+    }
+    m!('b: 'a);
 }
 
-make_quux!{}
+mod both_lifetimes_outside_colon_inside {
+    macro_rules! m {
+        ($b:lifetime: $a:lifetime) => {
+            struct Foo<$a, $b: $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b: $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b: $a;
+        }
+    }
+    m!('b: 'a);
+}
 
-macro_rules! make_baz {
-    () => {
-        make_baz!{ 'a }
-    };
-    ($a:lifetime) => {
-        struct Baz<$a, 'b> where 'b: $a {
-            baz: &$a &'b (),
+mod everything_outside {
+    macro_rules! m {
+        ($b:lifetime $colon:tt $a:lifetime) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
         }
+    }
+    m!('b: 'a);
+}
 
-        struct Baz2<$a, 'b: $a> {
-            baz: &$a &'b (),
+mod everything_outside_with_tt_inner {
+    macro_rules! m {
+        ($b:tt $colon:tt $a:lifetime) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
         }
-    };
+    }
+    m!('b: 'a);
 }
 
-make_baz!{ 'a }
+// FIXME: These should be consistent.
+mod everything_outside_with_tt_outer {
+    macro_rules! m {
+        ($b:lifetime $colon:tt $a:tt) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+        }
+    }
+    m!('b: 'a);
+}
 
-mod baz {
-    make_baz!{}
+mod everything_outside_with_tt_both {
+    macro_rules! m {
+        ($b:tt $colon:tt $a:tt) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+            //~^ ERROR: outlives requirements can be inferred
+        }
+    }
+    m!('b: 'a);
 }
 
 fn main() {}
diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr b/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr
index 0dd4985244d..734ae687978 100644
--- a/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr
+++ b/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr
@@ -5,32 +5,106 @@ LL | struct Bar<'a, 'b: 'a> {
    |                  ^^^^ help: remove this bound
    |
 note: the lint level is defined here
-  --> $DIR/edition-lint-infer-outlives-macro.rs:8:9
+  --> $DIR/edition-lint-infer-outlives-macro.rs:5:9
    |
 LL | #![deny(explicit_outlives_requirements)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: outlives requirements can be inferred
-  --> $DIR/edition-lint-infer-outlives-macro.rs:34:28
+  --> $DIR/edition-lint-infer-outlives-macro.rs:32:24
    |
-LL |         struct Quux<'a, 'b> where 'b: 'a {
-   |                            ^^^^^^^^^^^^^ help: remove this bound
+LL | struct BarWhere<'a, 'b> where 'b: 'a {
+   |                        ^^^^^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:41:30
+   |
+LL |             struct Foo<'a, 'b: 'a>(&'a &'b ());
+   |                              ^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:43:44
+   |
+LL |             struct Bar<'a, 'b>(&'a &'b ()) where 'b: 'a;
+   |                                            ^^^^^^^^^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:45:61
+   |
+LL |             struct Baz<'a, 'b>(&'a &'b ()) where (): Sized, 'b: 'a;
+   |                                                             ^^^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:55:30
+   |
+LL |             struct Foo<'a, $b: 'a>(&'a &$b ());
+   |                              ^^^^ help: remove this bound
 ...
-LL | make_quux!{}
-   | ------------ in this macro invocation
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
    |
-   = note: this error originates in the macro `make_quux` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: outlives requirements can be inferred
-  --> $DIR/edition-lint-infer-outlives-macro.rs:39:28
+  --> $DIR/edition-lint-infer-outlives-macro.rs:57:44
    |
-LL |         struct Quux2<'a, 'b: 'a> {
-   |                            ^^^^ help: remove this bound
+LL |             struct Bar<'a, $b>(&'a &$b ()) where $b: 'a;
+   |                                            ^^^^^^^^^^^^ help: remove this bound
 ...
-LL | make_quux!{}
-   | ------------ in this macro invocation
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:59:61
+   |
+LL |             struct Baz<'a, $b>(&'a &$b ()) where (): Sized, $b: 'a;
+   |                                                             ^^^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:114:31
+   |
+LL |             struct Foo<$a, $b $colon $a>(&$a &$b ());
+   |                               ^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:126:31
+   |
+LL |             struct Foo<$a, $b $colon $a>(&$a &$b ());
+   |                               ^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:128:50
+   |
+LL |             struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+   |                                                  ^^^^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:130:61
    |
-   = note: this error originates in the macro `make_quux` (in Nightly builds, run with -Z macro-backtrace for more info)
+LL |             struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+   |                                                             ^^^^^^^^^^^^ help: remove this bound
 
-error: aborting due to 3 previous errors
+error: aborting due to 12 previous errors