diff options
| author | bors <bors@rust-lang.org> | 2023-01-11 23:05:58 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-01-11 23:05:58 +0000 |
| commit | 56ee65aeb6d1fad67d903d5ee1359abcf7b94231 (patch) | |
| tree | 2ddda23b3e396ddddfa76f9f282647e3233e0898 /compiler | |
| parent | 1e4f90061cc4bc566f99ab21b1f101182b10cf0c (diff) | |
| parent | 106df9ec98012c6fbeb0ffe636f5f566333cfaa1 (diff) | |
| download | rust-56ee65aeb6d1fad67d903d5ee1359abcf7b94231.tar.gz rust-56ee65aeb6d1fad67d903d5ee1359abcf7b94231.zip | |
Auto merge of #106743 - matthiaskrgr:rollup-q5dpxms, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #106620 (Detect struct literal needing parentheses) - #106622 (Detect out of bounds range pattern value) - #106703 (Note predicate span on `ImplDerivedObligation`) - #106705 (Report fulfillment errors in new trait solver) - #106726 (Fix some typos in code comments.) - #106734 (Deny having src/test exisiting in tidy) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/write.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_error_messages/locales/en-US/mir_build.ftl | 4 | ||||
| -rw-r--r-- | compiler/rustc_error_messages/locales/en-US/parse.ftl | 4 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/errors.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/mod.rs | 68 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/errors.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 37 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/stmt.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/fulfill.rs | 36 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs | 28 |
12 files changed, 194 insertions, 45 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7aadcdd2228..25dc88c535d 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1098,7 +1098,7 @@ fn start_executing_work<B: ExtraBackendMethods>( // There are a few environmental pre-conditions that shape how the system // is set up: // - // - Error reporting only can happen on the main thread because that's the + // - Error reporting can only happen on the main thread because that's the // only place where we have access to the compiler `Session`. // - LLVM work can be done on any thread. // - Codegen can only happen on the main thread. @@ -1110,16 +1110,16 @@ fn start_executing_work<B: ExtraBackendMethods>( // Error Reporting // =============== // The error reporting restriction is handled separately from the rest: We - // set up a `SharedEmitter` the holds an open channel to the main thread. + // set up a `SharedEmitter` that holds an open channel to the main thread. // When an error occurs on any thread, the shared emitter will send the // error message to the receiver main thread (`SharedEmitterMain`). The // main thread will periodically query this error message queue and emit // any error messages it has received. It might even abort compilation if - // has received a fatal error. In this case we rely on all other threads + // it has received a fatal error. In this case we rely on all other threads // being torn down automatically with the main thread. // Since the main thread will often be busy doing codegen work, error // reporting will be somewhat delayed, since the message queue can only be - // checked in between to work packages. + // checked in between two work packages. // // Work Processing Infrastructure // ============================== @@ -1133,7 +1133,7 @@ fn start_executing_work<B: ExtraBackendMethods>( // thread about what work to do when, and it will spawn off LLVM worker // threads as open LLVM WorkItems become available. // - // The job of the main thread is to codegen CGUs into LLVM work package + // The job of the main thread is to codegen CGUs into LLVM work packages // (since the main thread is the only thread that can do this). The main // thread will block until it receives a message from the coordinator, upon // which it will codegen one CGU, send it to the coordinator and block @@ -1142,10 +1142,10 @@ fn start_executing_work<B: ExtraBackendMethods>( // // The coordinator keeps a queue of LLVM WorkItems, and when a `Token` is // available, it will spawn off a new LLVM worker thread and let it process - // that a WorkItem. When a LLVM worker thread is done with its WorkItem, + // a WorkItem. When a LLVM worker thread is done with its WorkItem, // it will just shut down, which also frees all resources associated with // the given LLVM module, and sends a message to the coordinator that the - // has been completed. + // WorkItem has been completed. // // Work Scheduling // =============== @@ -1165,7 +1165,7 @@ fn start_executing_work<B: ExtraBackendMethods>( // // Doing LLVM Work on the Main Thread // ---------------------------------- - // Since the main thread owns the compiler processes implicit `Token`, it is + // Since the main thread owns the compiler process's implicit `Token`, it is // wasteful to keep it blocked without doing any work. Therefore, what we do // in this case is: We spawn off an additional LLVM worker thread that helps // reduce the queue. The work it is doing corresponds to the implicit @@ -1216,7 +1216,7 @@ fn start_executing_work<B: ExtraBackendMethods>( // ------------------------------ // // The final job the coordinator thread is responsible for is managing LTO - // and how that works. When LTO is requested what we'll to is collect all + // and how that works. When LTO is requested what we'll do is collect all // optimized LLVM modules into a local vector on the coordinator. Once all // modules have been codegened and optimized we hand this to the `lto` // module for further optimization. The `lto` module will return back a list diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 60d3d3e69ab..aacaafeede6 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -206,6 +206,10 @@ mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = .label = lower bound larger than upper bound .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. +mir_build_literal_in_range_out_of_bounds = + literal out of range for `{$ty}` + .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}` + mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count -> diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl index 3401978caf5..f3f00fff230 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -2,6 +2,10 @@ parse_struct_literal_body_without_path = struct literal body without path .suggestion = you might have forgotten to add the struct literal inside the block +parse_struct_literal_needing_parens = + invalid struct literal + .suggestion = you might need to surround the struct literal in parentheses + parse_maybe_report_ambiguous_plus = ambiguous `+` in a type .suggestion = use parentheses to disambiguate diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 68179001b91..233eecbd5b4 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -494,6 +494,16 @@ pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper { } #[derive(Diagnostic)] +#[diag(mir_build_literal_in_range_out_of_bounds)] +pub struct LiteralOutOfRange<'tcx> { + #[primary_span] + #[label] + pub span: Span, + pub ty: Ty<'tcx>, + pub max: u128, +} + +#[derive(Diagnostic)] #[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")] pub struct LowerRangeBoundMustBeLessThanUpper { #[primary_span] diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 2c775b39718..7d4353c5292 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -129,10 +129,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hi: mir::ConstantKind<'tcx>, end: RangeEnd, span: Span, + lo_expr: Option<&hir::Expr<'tcx>>, + hi_expr: Option<&hir::Expr<'tcx>>, ) -> PatKind<'tcx> { assert_eq!(lo.ty(), ty); assert_eq!(hi.ty(), ty); let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env); + let max = || { + self.tcx + .layout_of(self.param_env.with_reveal_all_normalized(self.tcx).and(ty)) + .ok() + .unwrap() + .size + .unsigned_int_max() + }; match (end, cmp) { // `x..y` where `x < y`. // Non-empty because the range includes at least `x`. @@ -141,7 +151,27 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } // `x..y` where `x >= y`. The range is empty => error. (RangeEnd::Excluded, _) => { - self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span }); + let mut lower_overflow = false; + let mut higher_overflow = false; + if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr + && let rustc_ast::ast::LitKind::Int(val, _) = lit.node + { + if lo.eval_bits(self.tcx, self.param_env, ty) != val { + lower_overflow = true; + self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); + } + } + if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr + && let rustc_ast::ast::LitKind::Int(val, _) = lit.node + { + if hi.eval_bits(self.tcx, self.param_env, ty) != val { + higher_overflow = true; + self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); + } + } + if !lower_overflow && !higher_overflow { + self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span }); + } PatKind::Wild } // `x..=y` where `x == y`. @@ -152,10 +182,34 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } // `x..=y` where `x > y` hence the range is empty => error. (RangeEnd::Included, _) => { - self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { - span, - teach: if self.tcx.sess.teach(&error_code!(E0030)) { Some(()) } else { None }, - }); + let mut lower_overflow = false; + let mut higher_overflow = false; + if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr + && let rustc_ast::ast::LitKind::Int(val, _) = lit.node + { + if lo.eval_bits(self.tcx, self.param_env, ty) != val { + lower_overflow = true; + self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); + } + } + if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr + && let rustc_ast::ast::LitKind::Int(val, _) = lit.node + { + if hi.eval_bits(self.tcx, self.param_env, ty) != val { + higher_overflow = true; + self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); + } + } + if !lower_overflow && !higher_overflow { + self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { + span, + teach: if self.tcx.sess.teach(&error_code!(E0030)) { + Some(()) + } else { + None + }, + }); + } PatKind::Wild } } @@ -201,7 +255,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let (lp, hp) = (lo.as_ref().map(|(x, _)| x), hi.as_ref().map(|(x, _)| x)); let mut kind = match self.normalize_range_pattern_ends(ty, lp, hp) { - Some((lc, hc)) => self.lower_pattern_range(ty, lc, hc, end, lo_span), + Some((lc, hc)) => { + self.lower_pattern_range(ty, lc, hc, end, lo_span, lo_expr, hi_expr) + } None => { let msg = &format!( "found bad range pattern `{:?}` outside of error recovery", diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 574591529f3..19eeb069a25 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -971,6 +971,24 @@ pub(crate) struct StructLiteralBodyWithoutPathSugg { } #[derive(Diagnostic)] +#[diag(parse_struct_literal_needing_parens)] +pub(crate) struct StructLiteralNeedingParens { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: StructLiteralNeedingParensSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(suggestion, applicability = "machine-applicable")] +pub(crate) struct StructLiteralNeedingParensSugg { + #[suggestion_part(code = "(")] + pub before: Span, + #[suggestion_part(code = ")")] + pub after: Span, +} + +#[derive(Diagnostic)] #[diag(parse_unmatched_angle_brackets)] pub(crate) struct UnmatchedAngleBrackets { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index d9fa3e31db9..4c918c6702e 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -12,9 +12,10 @@ use crate::errors::{ IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, - StructLiteralBodyWithoutPathSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma, - UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, - UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, + StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, + SuggEscapeToUseAsIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam, + UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, + UseEqInstead, }; use crate::lexer::UnmatchedBrace; @@ -623,12 +624,15 @@ impl<'a> Parser<'a> { &mut self, lo: Span, s: BlockCheckMode, + maybe_struct_name: token::Token, + can_be_struct_literal: bool, ) -> Option<PResult<'a, P<Block>>> { if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) { // We might be having a struct literal where people forgot to include the path: // fn foo() -> Foo { // field: value, // } + info!(?maybe_struct_name, ?self.token); let mut snapshot = self.create_snapshot_for_diagnostic(); let path = Path { segments: ThinVec::new(), @@ -648,13 +652,6 @@ impl<'a> Parser<'a> { // field: value, // } } err.delay_as_bug(); - self.sess.emit_err(StructLiteralBodyWithoutPath { - span: expr.span, - sugg: StructLiteralBodyWithoutPathSugg { - before: expr.span.shrink_to_lo(), - after: expr.span.shrink_to_hi(), - }, - }); self.restore_snapshot(snapshot); let mut tail = self.mk_block( vec![self.mk_stmt_err(expr.span)], @@ -662,7 +659,25 @@ impl<'a> Parser<'a> { lo.to(self.prev_token.span), ); tail.could_be_bare_literal = true; - Ok(tail) + if maybe_struct_name.is_ident() && can_be_struct_literal { + // Account for `if Example { a: one(), }.is_pos() {}`. + Err(self.sess.create_err(StructLiteralNeedingParens { + span: maybe_struct_name.span.to(expr.span), + sugg: StructLiteralNeedingParensSugg { + before: maybe_struct_name.span.shrink_to_lo(), + after: expr.span.shrink_to_hi(), + }, + })) + } else { + self.sess.emit_err(StructLiteralBodyWithoutPath { + span: expr.span, + sugg: StructLiteralBodyWithoutPathSugg { + before: expr.span.shrink_to_lo(), + after: expr.span.shrink_to_hi(), + }, + }); + Ok(tail) + } } (Err(err), Ok(tail)) => { // We have a block tail that contains a somehow valid type ascription expr. diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9f436783ced..f5093fb02a8 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2039,7 +2039,7 @@ impl<'a> Parser<'a> { }); } - let (attrs, blk) = self.parse_block_common(lo, blk_mode)?; + let (attrs, blk) = self.parse_block_common(lo, blk_mode, true)?; Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs)) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a958c294930..a251e3ded2f 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2214,7 +2214,8 @@ impl<'a> Parser<'a> { *sig_hi = self.prev_token.span; (AttrVec::new(), None) } else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() { - self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))? + self.parse_block_common(self.token.span, BlockCheckMode::Default, false) + .map(|(attrs, body)| (attrs, Some(body)))? } else if self.token.kind == token::Eq { // Recover `fn foo() = $expr;`. self.bump(); // `=` diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 0daae457d30..1e5c2834960 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -498,7 +498,7 @@ impl<'a> Parser<'a> { /// Parses a block. Inner attributes are allowed. pub(super) fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (AttrVec, P<Block>)> { - self.parse_block_common(self.token.span, BlockCheckMode::Default) + self.parse_block_common(self.token.span, BlockCheckMode::Default, true) } /// Parses a block. Inner attributes are allowed. @@ -506,16 +506,23 @@ impl<'a> Parser<'a> { &mut self, lo: Span, blk_mode: BlockCheckMode, + can_be_struct_literal: bool, ) -> PResult<'a, (AttrVec, P<Block>)> { maybe_whole!(self, NtBlock, |x| (AttrVec::new(), x)); + let maybe_ident = self.prev_token.clone(); self.maybe_recover_unexpected_block_label(); if !self.eat(&token::OpenDelim(Delimiter::Brace)) { return self.error_block_no_opening_brace(); } let attrs = self.parse_inner_attributes()?; - let tail = match self.maybe_suggest_struct_literal(lo, blk_mode) { + let tail = match self.maybe_suggest_struct_literal( + lo, + blk_mode, + maybe_ident, + can_be_struct_literal, + ) { Some(tail) => tail?, None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?, }; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 80115d78d88..c014d682a9a 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -3,7 +3,10 @@ use std::mem; use rustc_data_structures::fx::FxHashMap; use rustc_infer::{ infer::InferCtxt, - traits::{query::NoSolution, FulfillmentError, PredicateObligation, TraitEngine}, + traits::{ + query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation, + SelectionError, TraitEngine, + }, }; use rustc_middle::ty; @@ -45,32 +48,43 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { return errors; } - if self.obligations.is_empty() { - Vec::new() - } else { - unimplemented!("ambiguous obligations") - } + self.obligations + .drain(..) + .map(|obligation| FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeSelectionError(SelectionError::Unimplemented), + root_obligation: obligation, + }) + .collect() } fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - let errors = Vec::new(); + let mut errors = Vec::new(); for i in 0.. { if !infcx.tcx.recursion_limit().value_within_limit(i) { unimplemented!("overflow") } let mut has_changed = false; - for o in mem::take(&mut self.obligations) { + for obligation in mem::take(&mut self.obligations) { let mut cx = EvalCtxt::new(infcx.tcx); - let (changed, certainty) = match cx.evaluate_goal(infcx, o.clone().into()) { + let (changed, certainty) = match cx.evaluate_goal(infcx, obligation.clone().into()) + { Ok(result) => result, - Err(NoSolution) => unimplemented!("error"), + Err(NoSolution) => { + errors.push(FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeAmbiguity, + root_obligation: obligation, + }); + continue; + } }; has_changed |= changed; match certainty { Certainty::Yes => {} - Certainty::Maybe(_) => self.obligations.push(o), + Certainty::Maybe(_) => self.obligations.push(obligation), } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 43985495827..53769742c47 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -36,7 +36,7 @@ use rustc_middle::ty::{ TypeSuperFoldable, TypeVisitable, TypeckResults, }; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP}; +use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; use rustc_target::spec::abi; use std::ops::Deref; @@ -2949,7 +2949,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // FIXME: we should do something else so that it works even on crate foreign // auto traits. is_auto_trait = matches!(is_auto, hir::IsAuto::Yes); - err.span_note(ident.span, &msg) + err.span_note(ident.span, &msg); } Some(Node::Item(hir::Item { kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }), @@ -2960,9 +2960,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { spans.push(trait_ref.path.span); } spans.push(self_ty.span); - err.span_note(spans, &msg) + let mut spans: MultiSpan = spans.into(); + if matches!( + self_ty.span.ctxt().outer_expn_data().kind, + ExpnKind::Macro(MacroKind::Derive, _) + ) || matches!( + of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind), + Some(ExpnKind::Macro(MacroKind::Derive, _)) + ) { + spans.push_span_label( + data.span, + "unsatisfied trait bound introduced in this `derive` macro", + ); + } else if !data.span.is_dummy() && !data.span.overlaps(self_ty.span) { + spans.push_span_label( + data.span, + "unsatisfied trait bound introduced here", + ); + } + err.span_note(spans, &msg); + } + _ => { + err.note(&msg); } - _ => err.note(&msg), }; if let Some(file) = file { |
