about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-01-11 23:05:58 +0000
committerbors <bors@rust-lang.org>2023-01-11 23:05:58 +0000
commit56ee65aeb6d1fad67d903d5ee1359abcf7b94231 (patch)
tree2ddda23b3e396ddddfa76f9f282647e3233e0898 /compiler
parent1e4f90061cc4bc566f99ab21b1f101182b10cf0c (diff)
parent106df9ec98012c6fbeb0ffe636f5f566333cfaa1 (diff)
downloadrust-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.rs18
-rw-r--r--compiler/rustc_error_messages/locales/en-US/mir_build.ftl4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/parse.ftl4
-rw-r--r--compiler/rustc_mir_build/src/errors.rs10
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs68
-rw-r--r--compiler/rustc_parse/src/errors.rs18
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs37
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs2
-rw-r--r--compiler/rustc_parse/src/parser/item.rs3
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs36
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs28
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 {