diff options
| -rw-r--r-- | compiler/rustc_ast_lowering/src/item.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/builtin.rs | 50 | ||||
| -rw-r--r-- | src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs | 43 | ||||
| -rw-r--r-- | src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr | 26 |
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 |
