about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs17
-rw-r--r--compiler/rustc_lint/src/builtin.rs50
-rw-r--r--src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs43
-rw-r--r--src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr26
4 files changed, 98 insertions, 38 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 9d4c2900eaf..bda914d2888 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1377,21 +1377,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let ident = self.lower_ident(ident);
         let param_span = ident.span;
-        let span = bounds
-            .iter()
-            .fold(Some(param_span.shrink_to_hi()), |span: Option<Span>, bound| {
-                let bound_span = bound.span();
-                // We include bounds that come from a `#[derive(_)]` but point at the user's code,
-                // as we use this method to get a span appropriate for suggestions.
-                if !bound_span.can_be_used_for_suggestions() {
-                    None
-                } else if let Some(span) = span {
-                    Some(span.to(bound_span))
-                } else {
-                    Some(bound_span)
-                }
-            })
-            .unwrap_or(param_span.shrink_to_hi());
+        let span =
+            bounds.iter().fold(param_span.shrink_to_hi(), |span, bound| span.to(bound.span()));
         match kind {
             GenericParamKind::Const { .. } => None,
             GenericParamKind::Type { .. } => {
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index d6de6e70ead..3fc86545ed4 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};
+use rustc_span::{BytePos, InnerSpan, Span, SyntaxContext};
 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,6 +2184,7 @@ impl ExplicitOutlivesRequirements {
         tcx: TyCtxt<'tcx>,
         bounds: &hir::GenericBounds<'_>,
         inferred_outlives: &[ty::Region<'tcx>],
+        span_cx: SyntaxContext,
     ) -> Vec<(usize, Span)> {
         use rustc_middle::middle::resolve_lifetime::Region;
 
@@ -2191,23 +2192,28 @@ impl ExplicitOutlivesRequirements {
             .iter()
             .enumerate()
             .filter_map(|(i, bound)| {
-                if let hir::GenericBound::Outlives(lifetime) = bound {
-                    let is_inferred = match tcx.named_region(lifetime.hir_id) {
-                        Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
-                            if let ty::ReEarlyBound(ebr) = **r {
-                                ebr.def_id == def_id
-                            } else {
-                                false
-                            }
-                        }),
-                        _ => false,
-                    };
-                    is_inferred.then_some((i, bound.span()))
-                } else {
-                    None
+                let hir::GenericBound::Outlives(lifetime) = bound else {
+                    return None;
+                };
+
+                let is_inferred = match tcx.named_region(lifetime.hir_id) {
+                    Some(Region::EarlyBound(def_id)) => inferred_outlives
+                        .iter()
+                        .any(|r| matches!(**r, ty::ReEarlyBound(ebr) if { ebr.def_id == def_id })),
+                    _ => false,
+                };
+
+                if !is_inferred {
+                    return None;
+                }
+
+                let span = bound.span();
+                if span.ctxt() != span_cx || in_external_macro(tcx.sess, span) {
+                    return None;
                 }
+
+                Some((i, span))
             })
-            .filter(|(_, span)| !in_external_macro(tcx.sess, *span))
             .collect()
     }
 
@@ -2312,9 +2318,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                         // 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, ref path)) => {
+                            hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
                                 let Res::Def(DefKind::TyParam, def_id) = path.res else {
-                                    continue
+                                    continue;
                                 };
                                 let index = ty_generics.param_def_id_to_index[&def_id];
                                 (
@@ -2335,8 +2341,12 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                     continue;
                 }
 
-                let bound_spans =
-                    self.collect_outlives_bound_spans(cx.tcx, bounds, &relevant_lifetimes);
+                let bound_spans = self.collect_outlives_bound_spans(
+                    cx.tcx,
+                    bounds,
+                    &relevant_lifetimes,
+                    span.ctxt(),
+                );
                 bound_count += bound_spans.len();
 
                 let drop_predicate = bound_spans.len() == bounds.len();
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 d7a832831c1..d96def8173a 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
@@ -15,7 +15,11 @@ macro_rules! make_foo {
         struct Foo<$a, 'b> where 'b: $a {
             foo: &$a &'b (),
         }
-    }
+
+        struct Foo2<$a, 'b: $a> {
+            foo: &$a &'b (),
+        }
+    };
 }
 
 gimme_a! {make_foo!}
@@ -25,4 +29,41 @@ struct Bar<'a, 'b: 'a> {
     bar: &'a &'b (),
 }
 
+macro_rules! make_quux {
+    () => {
+        struct Quux<'a, 'b> where 'b: 'a {
+            //~^ ERROR: outlives requirements can be inferred
+            baz: &'a &'b (),
+        }
+
+        struct Quux2<'a, 'b: 'a> {
+            //~^ ERROR: outlives requirements can be inferred
+            baz: &'a &'b (),
+        }
+    };
+}
+
+make_quux!{}
+
+macro_rules! make_baz {
+    () => {
+        make_baz!{ 'a }
+    };
+    ($a:lifetime) => {
+        struct Baz<$a, 'b> where 'b: $a {
+            baz: &$a &'b (),
+        }
+
+        struct Baz2<$a, 'b: $a> {
+            baz: &$a &'b (),
+        }
+    };
+}
+
+make_baz!{ 'a }
+
+mod baz {
+    make_baz!{}
+}
+
 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 553b1cd976a..0dd4985244d 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
@@ -1,5 +1,5 @@
 error: outlives requirements can be inferred
-  --> $DIR/edition-lint-infer-outlives-macro.rs:23:18
+  --> $DIR/edition-lint-infer-outlives-macro.rs:27:18
    |
 LL | struct Bar<'a, 'b: 'a> {
    |                  ^^^^ help: remove this bound
@@ -10,5 +10,27 @@ note: the lint level is defined here
 LL | #![deny(explicit_outlives_requirements)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:34:28
+   |
+LL |         struct Quux<'a, 'b> where 'b: 'a {
+   |                            ^^^^^^^^^^^^^ help: remove this bound
+...
+LL | make_quux!{}
+   | ------------ in this macro invocation
+   |
+   = note: this error originates in the macro `make_quux` (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
+   |
+LL |         struct Quux2<'a, 'b: 'a> {
+   |                            ^^^^ help: remove this bound
+...
+LL | make_quux!{}
+   | ------------ in this macro invocation
+   |
+   = note: this error originates in the macro `make_quux` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors