]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #96684 - tmiasko:mir-downcast, r=petrochenkov
authorYuki Okushi <jtitor@2k36.org>
Wed, 4 May 2022 08:13:15 +0000 (17:13 +0900)
committerGitHub <noreply@github.com>
Wed, 4 May 2022 08:13:15 +0000 (17:13 +0900)
Update `ProjectionElem::Downcast` documentation

`ProjectionElem:::Downcast` is used when downcasting to a variant of
an enum or a generator, regardless of the number of variants.

36 files changed:
Cargo.lock
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_builtin_macros/src/asm.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_lint/src/non_fmt_panic.rs
compiler/rustc_parse_format/Cargo.toml
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_parse_format/src/tests.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
src/bootstrap/builder.rs
src/doc/rustc/src/lints/levels.md
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/test/rustdoc-ui/block-doc-comment.rs
src/test/rustdoc-ui/block-doc-comment.stdout
src/test/rustdoc-ui/intra-doc/assoc-field.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs [new file with mode: 0644]
src/test/ui/destructuring-assignment/struct-or-enum-variant-path.rs [new file with mode: 0644]
src/test/ui/macros/macro-outer-attributes.stderr
src/test/ui/namespace/namespace-mix.stderr
src/test/ui/parser/circular_modules_main.stderr
src/test/ui/resolve/enums-are-namespaced-xc.stderr
src/test/ui/resolve/issue-50599.stderr
src/test/ui/resolve/missing-in-namespace.stderr
src/test/ui/resolve/privacy-enum-ctor.stderr
src/test/ui/resolve/resolve-primitive-fallback.stderr
src/test/ui/suggestions/issue-96223.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-96223.stderr [new file with mode: 0644]
src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed [new file with mode: 0644]
src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs [new file with mode: 0644]
src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/write.rs

index ef4800a22613682eba1362ac05a718e733424335..94832a24409874eb63af9e5e6f9802d8678c0a46 100644 (file)
@@ -4171,7 +4171,6 @@ name = "rustc_parse_format"
 version = "0.0.0"
 dependencies = [
  "rustc_lexer",
- "rustc_span",
 ]
 
 [[package]]
index 5c3e3be21167a525df9d53688938e286b7bf4cd0..a1d994c2f90db73dbfe4d89b150d5651e6775985 100644 (file)
@@ -1020,6 +1020,28 @@ fn extract_tuple_struct_path<'a>(
         None
     }
 
+    /// If the given expression is a path to a unit struct, returns that path.
+    /// It is not a complete check, but just tries to reject most paths early
+    /// if they are not unit structs.
+    /// Type checking will take care of the full validation later.
+    fn extract_unit_struct_path<'a>(
+        &mut self,
+        expr: &'a Expr,
+    ) -> Option<(&'a Option<QSelf>, &'a Path)> {
+        if let ExprKind::Path(qself, path) = &expr.kind {
+            // Does the path resolve to something disallowed in a unit struct/variant pattern?
+            if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
+                if partial_res.unresolved_segments() == 0
+                    && !partial_res.base_res().expected_in_unit_struct_pat()
+                {
+                    return None;
+                }
+            }
+            return Some((qself, path));
+        }
+        None
+    }
+
     /// Convert the LHS of a destructuring assignment to a pattern.
     /// Each sub-assignment is recorded in `assignments`.
     fn destructure_assign(
@@ -1080,6 +1102,21 @@ fn destructure_assign_mut(
                     return self.pat_without_dbm(lhs.span, tuple_struct_pat);
                 }
             }
+            // Unit structs and enum variants.
+            ExprKind::Path(..) => {
+                if let Some((qself, path)) = self.extract_unit_struct_path(lhs) {
+                    let qpath = self.lower_qpath(
+                        lhs.id,
+                        qself,
+                        path,
+                        ParamMode::Optional,
+                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                    );
+                    // Destructure like a unit struct.
+                    let unit_struct_pat = hir::PatKind::Path(qpath);
+                    return self.pat_without_dbm(lhs.span, unit_struct_pat);
+                }
+            }
             // Structs.
             ExprKind::Struct(se) => {
                 let field_pats = self.arena.alloc_from_iter(se.fields.iter().map(|f| {
index e9e3307ca95dac89f377ba83f0cb894baf27a025..c95d7147176bd111d6d3ae7a9b5fb0715a8de9b8 100644 (file)
@@ -626,7 +626,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
 
         if !parser.errors.is_empty() {
             let err = parser.errors.remove(0);
-            let err_sp = template_span.from_inner(err.span);
+            let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
             let msg = &format!("invalid asm template string: {}", err.description);
             let mut e = ecx.struct_span_err(err_sp, msg);
             e.span_label(err_sp, err.label + " in asm template string");
@@ -634,7 +634,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                 e.note(&note);
             }
             if let Some((label, span)) = err.secondary_label {
-                let err_sp = template_span.from_inner(span);
+                let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end));
                 e.span_label(err_sp, label);
             }
             e.emit();
@@ -643,7 +643,10 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
 
         curarg = parser.curarg;
 
-        let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span));
+        let mut arg_spans = parser
+            .arg_places
+            .iter()
+            .map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end)));
         for piece in unverified_pieces {
             match piece {
                 parse::Piece::String(s) => {
@@ -699,14 +702,21 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                                 Some(idx)
                             }
                         }
-                        parse::ArgumentNamed(name, span) => match args.named_args.get(&name) {
-                            Some(&idx) => Some(idx),
-                            None => {
-                                let msg = format!("there is no argument named `{}`", name);
-                                ecx.struct_span_err(template_span.from_inner(span), &msg).emit();
-                                None
+                        parse::ArgumentNamed(name, span) => {
+                            match args.named_args.get(&Symbol::intern(name)) {
+                                Some(&idx) => Some(idx),
+                                None => {
+                                    let msg = format!("there is no argument named `{}`", name);
+                                    ecx.struct_span_err(
+                                        template_span
+                                            .from_inner(InnerSpan::new(span.start, span.end)),
+                                        &msg,
+                                    )
+                                    .emit();
+                                    None
+                                }
                             }
-                        },
+                        }
                     };
 
                     let mut chars = arg.format.ty.chars();
@@ -715,7 +725,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                         let span = arg
                             .format
                             .ty_span
-                            .map(|sp| template_sp.from_inner(sp))
+                            .map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
                             .unwrap_or(template_sp);
                         ecx.struct_span_err(
                             span,
@@ -741,7 +751,12 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
             let template_num_lines = 1 + template_str.matches('\n').count();
             line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
         } else {
-            line_spans.extend(parser.line_spans.iter().map(|span| template_span.from_inner(*span)));
+            line_spans.extend(
+                parser
+                    .line_spans
+                    .iter()
+                    .map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end))),
+            );
         };
     }
 
index 138e1fa0176033ed2b121f76b46565c7968c9a10..60b96399b5e7ec7a159c1b8d7bd84d3036950f04 100644 (file)
@@ -242,7 +242,7 @@ fn num_args(&self) -> usize {
     fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
         // NOTE: the `unwrap_or` branch is needed in case of invalid format
         // arguments, e.g., `format_args!("{foo}")`.
-        let lookup = |s: Symbol| *self.names.get(&s).unwrap_or(&0);
+        let lookup = |s: &str| *self.names.get(&Symbol::intern(s)).unwrap_or(&0);
 
         match *p {
             parse::String(_) => {}
@@ -276,7 +276,9 @@ fn verify_piece(&mut self, p: &parse::Piece<'_>) {
                 // it's written second, so it should come after width/precision.
                 let pos = match arg.position {
                     parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
-                    parse::ArgumentNamed(s, span) => Named(s, span),
+                    parse::ArgumentNamed(s, span) => {
+                        Named(Symbol::intern(s), InnerSpan::new(span.start, span.end))
+                    }
                 };
 
                 let ty = Placeholder(match arg.format.ty {
@@ -291,7 +293,10 @@ fn verify_piece(&mut self, p: &parse::Piece<'_>) {
                     "X" => "UpperHex",
                     _ => {
                         let fmtsp = self.fmtsp;
-                        let sp = arg.format.ty_span.map(|sp| fmtsp.from_inner(sp));
+                        let sp = arg
+                            .format
+                            .ty_span
+                            .map(|sp| fmtsp.from_inner(InnerSpan::new(sp.start, sp.end)));
                         let mut err = self.ecx.struct_span_err(
                             sp.unwrap_or(fmtsp),
                             &format!("unknown format trait `{}`", arg.format.ty),
@@ -340,14 +345,17 @@ fn verify_piece(&mut self, p: &parse::Piece<'_>) {
         }
     }
 
-    fn verify_count(&mut self, c: parse::Count) {
+    fn verify_count(&mut self, c: parse::Count<'_>) {
         match c {
             parse::CountImplied | parse::CountIs(..) => {}
             parse::CountIsParam(i) => {
                 self.verify_arg_type(Exact(i), Count);
             }
             parse::CountIsName(s, span) => {
-                self.verify_arg_type(Named(s, span), Count);
+                self.verify_arg_type(
+                    Named(Symbol::intern(s), InnerSpan::new(span.start, span.end)),
+                    Count,
+                );
             }
         }
     }
@@ -425,7 +433,7 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
 
         for fmt in &self.arg_with_formatting {
             if let Some(span) = fmt.precision_span {
-                let span = self.fmtsp.from_inner(span);
+                let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
                 match fmt.precision {
                     parse::CountIsParam(pos) if pos > self.num_args() => {
                         e.span_label(
@@ -471,7 +479,7 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
                 }
             }
             if let Some(span) = fmt.width_span {
-                let span = self.fmtsp.from_inner(span);
+                let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
                 match fmt.width {
                     parse::CountIsParam(pos) if pos > self.num_args() => {
                         e.span_label(
@@ -610,7 +618,7 @@ fn rtpath(ecx: &ExtCtxt<'_>, s: Symbol) -> Vec<Ident> {
         ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s])
     }
 
-    fn build_count(&self, c: parse::Count) -> P<ast::Expr> {
+    fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
         let sp = self.macsp;
         let count = |c, arg| {
             let mut path = Context::rtpath(self.ecx, sym::Count);
@@ -1033,7 +1041,7 @@ pub fn expand_preparsed_format_args(
     if !parser.errors.is_empty() {
         let err = parser.errors.remove(0);
         let sp = if efmt_kind_is_lit {
-            fmt_span.from_inner(err.span)
+            fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
         } else {
             // The format string could be another macro invocation, e.g.:
             //     format!(concat!("abc", "{}"), 4);
@@ -1052,14 +1060,18 @@ pub fn expand_preparsed_format_args(
         }
         if let Some((label, span)) = err.secondary_label {
             if efmt_kind_is_lit {
-                e.span_label(fmt_span.from_inner(span), label);
+                e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
             }
         }
         e.emit();
         return DummyResult::raw_expr(sp, true);
     }
 
-    let arg_spans = parser.arg_places.iter().map(|span| fmt_span.from_inner(*span)).collect();
+    let arg_spans = parser
+        .arg_places
+        .iter()
+        .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
+        .collect();
 
     let named_pos: FxHashSet<usize> = names.values().cloned().collect();
 
index 324e110005717ac6517f4f357e4b4dc7c08cc1a2..7416ad79aefd0075a960cb9d36caa14b0d1f0b2f 100644 (file)
@@ -663,4 +663,9 @@ pub fn matches_ns(&self, ns: Namespace) -> bool {
     pub fn expected_in_tuple_struct_pat(&self) -> bool {
         matches!(self, Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..))
     }
+
+    /// Returns whether such a resolved path can occur in a unit struct/variant pattern
+    pub fn expected_in_unit_struct_pat(&self) -> bool {
+        matches!(self, Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..))
+    }
 }
index 71769fceec1f2994c98bc6d9a478fc2e6cbc1b4c..4e7aeca9ce1d5c881baa52d404d08b349c4d4c01 100644 (file)
@@ -254,7 +254,10 @@ fn check_panic_str<'tcx>(
     if n_arguments > 0 && fmt_parser.errors.is_empty() {
         let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
             [] => vec![fmt_span],
-            v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
+            v => v
+                .iter()
+                .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
+                .collect(),
         };
         cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
             let mut l = lint.build(match n_arguments {
index aa1714e820f4862a035ce10a11946245267d060c..fcc68b3a219cc93bea57983cbe980b31a8b220c8 100644 (file)
@@ -4,5 +4,4 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
-rustc_span = { path = "../rustc_span" }
 rustc_lexer = { path = "../rustc_lexer" }
index 00bac26a16a98bd3fa17cfc86e1d1b14fab0c690..f6fa19030acb9ff08bd76bb03f26739d4537cc7e 100644 (file)
@@ -9,8 +9,8 @@
     html_playground_url = "https://play.rust-lang.org/",
     test(attr(deny(warnings)))
 )]
-#![feature(nll)]
-#![feature(bool_to_option)]
+// We want to be able to build this crate with a stable compiler, so no
+// `#![feature]` attributes should be added.
 
 pub use Alignment::*;
 pub use Count::*;
 use std::str;
 use std::string;
 
-use rustc_span::{InnerSpan, Symbol};
+// Note: copied from rustc_span
+/// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct InnerSpan {
+    pub start: usize,
+    pub end: usize,
+}
+
+impl InnerSpan {
+    pub fn new(start: usize, end: usize) -> InnerSpan {
+        InnerSpan { start, end }
+    }
+}
 
 /// The type of format string that we are parsing.
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -57,7 +69,7 @@ pub enum Piece<'a> {
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub struct Argument<'a> {
     /// Where to find this argument
-    pub position: Position,
+    pub position: Position<'a>,
     /// How to format the argument
     pub format: FormatSpec<'a>,
 }
@@ -72,11 +84,11 @@ pub struct FormatSpec<'a> {
     /// Packed version of various flags provided.
     pub flags: u32,
     /// The integer precision to use.
-    pub precision: Count,
+    pub precision: Count<'a>,
     /// The span of the precision formatting flag (for diagnostics).
     pub precision_span: Option<InnerSpan>,
     /// The string width requested for the resulting format.
-    pub width: Count,
+    pub width: Count<'a>,
     /// The span of the width formatting flag (for diagnostics).
     pub width_span: Option<InnerSpan>,
     /// The descriptor string representing the name of the format desired for
@@ -89,16 +101,16 @@ pub struct FormatSpec<'a> {
 
 /// Enum describing where an argument for a format can be located.
 #[derive(Copy, Clone, Debug, PartialEq)]
-pub enum Position {
+pub enum Position<'a> {
     /// The argument is implied to be located at an index
     ArgumentImplicitlyIs(usize),
     /// The argument is located at a specific index given in the format
     ArgumentIs(usize),
     /// The argument has a name.
-    ArgumentNamed(Symbol, InnerSpan),
+    ArgumentNamed(&'a str, InnerSpan),
 }
 
-impl Position {
+impl Position<'_> {
     pub fn index(&self) -> Option<usize> {
         match self {
             ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
@@ -143,11 +155,11 @@ pub enum Flag {
 /// A count is used for the precision and width parameters of an integer, and
 /// can reference either an argument or a literal integer.
 #[derive(Copy, Clone, Debug, PartialEq)]
-pub enum Count {
+pub enum Count<'a> {
     /// The count is specified explicitly.
     CountIs(usize),
     /// The count is specified by the argument with the given name.
-    CountIsName(Symbol, InnerSpan),
+    CountIsName(&'a str, InnerSpan),
     /// The count is specified by the argument at the given index.
     CountIsParam(usize),
     /// The count is implied and cannot be explicitly specified.
@@ -489,7 +501,7 @@ fn argument(&mut self) -> Argument<'a> {
     /// integer index of an argument, a named argument, or a blank string.
     /// Returns `Some(parsed_position)` if the position is not implicitly
     /// consuming a macro argument, `None` if it's the case.
-    fn position(&mut self) -> Option<Position> {
+    fn position(&mut self) -> Option<Position<'a>> {
         if let Some(i) = self.integer() {
             Some(ArgumentIs(i))
         } else {
@@ -498,7 +510,7 @@ fn position(&mut self) -> Option<Position> {
                     let word = self.word();
                     let end = start + word.len();
                     let span = self.to_span_index(start).to(self.to_span_index(end));
-                    Some(ArgumentNamed(Symbol::intern(word), span))
+                    Some(ArgumentNamed(word, span))
                 }
 
                 // This is an `ArgumentNext`.
@@ -651,7 +663,7 @@ fn inline_asm(&mut self) -> FormatSpec<'a> {
     /// Parses a `Count` parameter at the current position. This does not check
     /// for 'CountIsNextParam' because that is only used in precision, not
     /// width.
-    fn count(&mut self, start: usize) -> (Count, Option<InnerSpan>) {
+    fn count(&mut self, start: usize) -> (Count<'a>, Option<InnerSpan>) {
         if let Some(i) = self.integer() {
             if let Some(end) = self.consume_pos('$') {
                 let span = self.to_span_index(start).to(self.to_span_index(end + 1));
@@ -667,7 +679,7 @@ fn count(&mut self, start: usize) -> (Count, Option<InnerSpan>) {
                 (CountImplied, None)
             } else if let Some(end) = self.consume_pos('$') {
                 let span = self.to_span_index(start + 1).to(self.to_span_index(end));
-                (CountIsName(Symbol::intern(word), span), None)
+                (CountIsName(word, span), None)
             } else {
                 self.cur = tmp;
                 (CountImplied, None)
@@ -723,7 +735,7 @@ fn integer(&mut self) -> Option<usize> {
                 break;
             }
         }
-        found.then_some(cur)
+        if found { Some(cur) } else { None }
     }
 }
 
index 6c960fdc72bfd583ab0ffd243829ef8da57103b3..c9667922ee7c3649b7a00d7cb202ebe915004b0d 100644 (file)
@@ -144,93 +144,91 @@ fn format_align_fill() {
 }
 #[test]
 fn format_counts() {
-    rustc_span::create_default_session_globals_then(|| {
-        same(
-            "{:10x}",
-            &[NextArgument(Argument {
-                position: ArgumentImplicitlyIs(0),
-                format: FormatSpec {
-                    fill: None,
-                    align: AlignUnknown,
-                    flags: 0,
-                    precision: CountImplied,
-                    width: CountIs(10),
-                    precision_span: None,
-                    width_span: None,
-                    ty: "x",
-                    ty_span: None,
-                },
-            })],
-        );
-        same(
-            "{:10$.10x}",
-            &[NextArgument(Argument {
-                position: ArgumentImplicitlyIs(0),
-                format: FormatSpec {
-                    fill: None,
-                    align: AlignUnknown,
-                    flags: 0,
-                    precision: CountIs(10),
-                    width: CountIsParam(10),
-                    precision_span: None,
-                    width_span: Some(InnerSpan::new(3, 6)),
-                    ty: "x",
-                    ty_span: None,
-                },
-            })],
-        );
-        same(
-            "{:.*x}",
-            &[NextArgument(Argument {
-                position: ArgumentImplicitlyIs(1),
-                format: FormatSpec {
-                    fill: None,
-                    align: AlignUnknown,
-                    flags: 0,
-                    precision: CountIsParam(0),
-                    width: CountImplied,
-                    precision_span: Some(InnerSpan::new(3, 5)),
-                    width_span: None,
-                    ty: "x",
-                    ty_span: None,
-                },
-            })],
-        );
-        same(
-            "{:.10$x}",
-            &[NextArgument(Argument {
-                position: ArgumentImplicitlyIs(0),
-                format: FormatSpec {
-                    fill: None,
-                    align: AlignUnknown,
-                    flags: 0,
-                    precision: CountIsParam(10),
-                    width: CountImplied,
-                    precision_span: Some(InnerSpan::new(3, 7)),
-                    width_span: None,
-                    ty: "x",
-                    ty_span: None,
-                },
-            })],
-        );
-        same(
-            "{:a$.b$?}",
-            &[NextArgument(Argument {
-                position: ArgumentImplicitlyIs(0),
-                format: FormatSpec {
-                    fill: None,
-                    align: AlignUnknown,
-                    flags: 0,
-                    precision: CountIsName(Symbol::intern("b"), InnerSpan::new(6, 7)),
-                    width: CountIsName(Symbol::intern("a"), InnerSpan::new(4, 4)),
-                    precision_span: None,
-                    width_span: None,
-                    ty: "?",
-                    ty_span: None,
-                },
-            })],
-        );
-    });
+    same(
+        "{:10x}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountImplied,
+                width: CountIs(10),
+                precision_span: None,
+                width_span: None,
+                ty: "x",
+                ty_span: None,
+            },
+        })],
+    );
+    same(
+        "{:10$.10x}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIs(10),
+                width: CountIsParam(10),
+                precision_span: None,
+                width_span: Some(InnerSpan::new(3, 6)),
+                ty: "x",
+                ty_span: None,
+            },
+        })],
+    );
+    same(
+        "{:.*x}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(1),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIsParam(0),
+                width: CountImplied,
+                precision_span: Some(InnerSpan::new(3, 5)),
+                width_span: None,
+                ty: "x",
+                ty_span: None,
+            },
+        })],
+    );
+    same(
+        "{:.10$x}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIsParam(10),
+                width: CountImplied,
+                precision_span: Some(InnerSpan::new(3, 7)),
+                width_span: None,
+                ty: "x",
+                ty_span: None,
+            },
+        })],
+    );
+    same(
+        "{:a$.b$?}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIsName("b", InnerSpan::new(6, 7)),
+                width: CountIsName("a", InnerSpan::new(4, 4)),
+                precision_span: None,
+                width_span: None,
+                ty: "?",
+                ty_span: None,
+            },
+        })],
+    );
 }
 #[test]
 fn format_flags() {
index aef9fb57a6a7c5a08ddbdf7b9e7f08ac19810ee9..5d80f49626a0476ad92a4daa2bb8b8aeec32fea1 100644 (file)
@@ -117,7 +117,7 @@ impl<'a> Resolver<'a> {
     }
 
     fn report_with_use_injections(&mut self, krate: &Crate) {
-        for UseError { mut err, candidates, def_id, instead, suggestion } in
+        for UseError { mut err, candidates, def_id, instead, suggestion, path } in
             self.use_injections.drain(..)
         {
             let (span, found_use) = if let Some(def_id) = def_id.as_local() {
@@ -135,6 +135,7 @@ fn report_with_use_injections(&mut self, krate: &Crate) {
                     if instead { Instead::Yes } else { Instead::No },
                     found_use,
                     IsPattern::No,
+                    path,
                 );
             } else if let Some((span, msg, sugg, appl)) = suggestion {
                 err.span_suggestion(span, msg, sugg, appl);
@@ -702,6 +703,7 @@ fn add_suggestion_for_duplicate_nested_use(
                         Instead::No,
                         FoundUse::Yes,
                         IsPattern::Yes,
+                        vec![],
                     );
                 }
                 err
@@ -1482,6 +1484,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
             Instead::No,
             FoundUse::Yes,
             IsPattern::No,
+            vec![],
         );
 
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
@@ -2448,6 +2451,7 @@ fn show_candidates(
     instead: Instead,
     found_use: FoundUse,
     is_pattern: IsPattern,
+    path: Vec<Segment>,
 ) {
     if candidates.is_empty() {
         return;
@@ -2515,6 +2519,14 @@ fn show_candidates(
                 accessible_path_strings.into_iter().map(|a| a.0),
                 Applicability::MaybeIncorrect,
             );
+            if let [first, .., last] = &path[..] {
+                err.span_suggestion_verbose(
+                    first.ident.span.until(last.ident.span),
+                    &format!("if you import `{}`, refer to it directly", last.ident),
+                    String::new(),
+                    Applicability::Unspecified,
+                );
+            }
         } else {
             msg.push(':');
 
index ab353128cbcced62dc7b0071de6a11845b58b3ac..1bdf53cf84fedc41a6b3194b9fc3fd9a55f2fd6a 100644 (file)
@@ -396,13 +396,10 @@ fn is_call(self) -> bool {
                 ) | Res::Local(..)
                     | Res::SelfCtor(..)
             ),
-            PathSource::Pat => matches!(
-                res,
-                Res::Def(
-                    DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::AssocConst,
-                    _,
-                ) | Res::SelfCtor(..)
-            ),
+            PathSource::Pat => {
+                res.expected_in_unit_struct_pat()
+                    || matches!(res, Res::Def(DefKind::Const | DefKind::AssocConst, _))
+            }
             PathSource::TupleStruct(..) => res.expected_in_tuple_struct_pat(),
             PathSource::Struct => matches!(
                 res,
@@ -2696,6 +2693,7 @@ fn smart_resolve_path_fragment(
                     def_id,
                     instead,
                     suggestion,
+                    path: path.into(),
                 });
             }
 
@@ -2759,6 +2757,7 @@ fn smart_resolve_path_fragment(
                     def_id,
                     instead: false,
                     suggestion: None,
+                    path: path.into(),
                 });
             } else {
                 err.cancel();
index f6109b1dc1a1af17f89ea10afcbda9e707d20976..ff11aba49d83613d7e92fed5ee48ff828ec067d6 100644 (file)
@@ -696,6 +696,9 @@ struct UseError<'a> {
     instead: bool,
     /// Extra free-form suggestion.
     suggestion: Option<(Span, &'static str, String, Applicability)>,
+    /// Path `Segment`s at the place of use that failed. Used for accurate suggestion after telling
+    /// the user to import the item directly.
+    path: Vec<Segment>,
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
index a3d3c7c0cf3aa9f445141f9068826bfcd10caf98..bfb8ce6f1051c03b3573fbf39e2c5591c36da235 100644 (file)
@@ -866,7 +866,13 @@ fn suggest_add_reference_to_arg(
                 return false;
             }
 
-            let orig_ty = old_pred.self_ty().skip_binder();
+            // This is a quick fix to resolve an ICE (#96223).
+            // This change should probably be deeper.
+            // As suggested by @jackh726, `mk_trait_obligation_with_new_self_ty` could take a `Binder<(TraitRef, Ty)>
+            // instead of `Binder<Ty>` leading to some changes to its call places.
+            let Some(orig_ty) = old_pred.self_ty().no_bound_vars() else {
+                return false;
+            };
             let mk_result = |new_ty| {
                 let obligation =
                     self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);
index ce0e0a21ff516f0adaab581cfa80bf828836af39..c266eec25aa6b9a68eb914b43978f417b65cb308 100644 (file)
@@ -304,42 +304,40 @@ fn verify(
             match token {
                 Piece::String(_) => (), // Normal string, no need to check it
                 Piece::NextArgument(a) => match a.position {
-                    // `{Self}` is allowed
-                    Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (),
-                    // `{ThisTraitsName}` is allowed
-                    Position::ArgumentNamed(s, _) if s == trait_name => (),
-                    // `{from_method}` is allowed
-                    Position::ArgumentNamed(s, _) if s == sym::from_method => (),
-                    // `{from_desugaring}` is allowed
-                    Position::ArgumentNamed(s, _) if s == sym::from_desugaring => (),
-                    // `{ItemContext}` is allowed
-                    Position::ArgumentNamed(s, _) if s == sym::ItemContext => (),
-                    // `{integral}` and `{integer}` and `{float}` are allowed
-                    Position::ArgumentNamed(s, _)
-                        if s == sym::integral || s == sym::integer_ || s == sym::float =>
-                    {
-                        ()
-                    }
-                    // So is `{A}` if A is a type parameter
                     Position::ArgumentNamed(s, _) => {
-                        match generics.params.iter().find(|param| param.name == s) {
-                            Some(_) => (),
-                            None => {
-                                let reported = struct_span_err!(
-                                    tcx.sess,
-                                    span,
-                                    E0230,
-                                    "there is no parameter `{}` on {}",
-                                    s,
-                                    if trait_def_id == item_def_id {
-                                        format!("trait `{}`", trait_name)
-                                    } else {
-                                        "impl".to_string()
-                                    }
-                                )
-                                .emit();
-                                result = Err(reported);
-                            }
+                        match Symbol::intern(s) {
+                            // `{Self}` is allowed
+                            kw::SelfUpper => (),
+                            // `{ThisTraitsName}` is allowed
+                            s if s == trait_name => (),
+                            // `{from_method}` is allowed
+                            sym::from_method => (),
+                            // `{from_desugaring}` is allowed
+                            sym::from_desugaring => (),
+                            // `{ItemContext}` is allowed
+                            sym::ItemContext => (),
+                            // `{integral}` and `{integer}` and `{float}` are allowed
+                            sym::integral | sym::integer_ | sym::float => (),
+                            // So is `{A}` if A is a type parameter
+                            s => match generics.params.iter().find(|param| param.name == s) {
+                                Some(_) => (),
+                                None => {
+                                    let reported = struct_span_err!(
+                                        tcx.sess,
+                                        span,
+                                        E0230,
+                                        "there is no parameter `{}` on {}",
+                                        s,
+                                        if trait_def_id == item_def_id {
+                                            format!("trait `{}`", trait_name)
+                                        } else {
+                                            "impl".to_string()
+                                        }
+                                    )
+                                    .emit();
+                                    result = Err(reported);
+                                }
+                            },
                         }
                     }
                     // `{:1}` and `{}` are not to be used
@@ -392,34 +390,37 @@ pub fn format(
             .map(|p| match p {
                 Piece::String(s) => s,
                 Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s, _) => match generic_map.get(&s) {
-                        Some(val) => val,
-                        None if s == name => &trait_str,
-                        None => {
-                            if let Some(val) = options.get(&s) {
-                                val
-                            } else if s == sym::from_desugaring || s == sym::from_method {
-                                // don't break messages using these two arguments incorrectly
-                                &empty_string
-                            } else if s == sym::ItemContext {
-                                &item_context
-                            } else if s == sym::integral {
-                                "{integral}"
-                            } else if s == sym::integer_ {
-                                "{integer}"
-                            } else if s == sym::float {
-                                "{float}"
-                            } else {
-                                bug!(
-                                    "broken on_unimplemented {:?} for {:?}: \
+                    Position::ArgumentNamed(s, _) => {
+                        let s = Symbol::intern(s);
+                        match generic_map.get(&s) {
+                            Some(val) => val,
+                            None if s == name => &trait_str,
+                            None => {
+                                if let Some(val) = options.get(&s) {
+                                    val
+                                } else if s == sym::from_desugaring || s == sym::from_method {
+                                    // don't break messages using these two arguments incorrectly
+                                    &empty_string
+                                } else if s == sym::ItemContext {
+                                    &item_context
+                                } else if s == sym::integral {
+                                    "{integral}"
+                                } else if s == sym::integer_ {
+                                    "{integer}"
+                                } else if s == sym::float {
+                                    "{float}"
+                                } else {
+                                    bug!(
+                                        "broken on_unimplemented {:?} for {:?}: \
                                       no argument matching {:?}",
-                                    self.0,
-                                    trait_ref,
-                                    s
-                                )
+                                        self.0,
+                                        trait_ref,
+                                        s
+                                    )
+                                }
                             }
                         }
-                    },
+                    }
                     _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
                 },
             })
index edfe31319e8d0ab10735d109b45fc5f0c6a31048..2224bf5f66e90103c4f2542583f0e849b4779797 100644 (file)
@@ -1405,7 +1405,8 @@ pub fn cargo(
         // FIXME(davidtwco): #[cfg(not(bootstrap))] - #95612 needs to be in the bootstrap compiler
         // for this conditional to be removed.
         if !target.contains("windows") || compiler.stage >= 1 {
-            if target.contains("linux") || target.contains("windows") {
+            if target.contains("linux") || target.contains("windows") || target.contains("openbsd")
+            {
                 rustflags.arg("-Zunstable-options");
             }
             match self.config.rust_split_debuginfo {
index 7bd46fafadf8344fe432971136857780cb639df4..fbec3cd9baf5033d5227e37f8da2538f48bed9d5 100644 (file)
@@ -100,9 +100,8 @@ This lint level gives you that.
 'force-warn' does for 'warn'. It's the same as 'deny' in that a lint at this
 level will produce an error, but unlike the 'deny' level, the 'forbid' level
 can not be overridden to be anything lower than an error.  However, lint
-levels may still be capped with `--cap-lints` (see below) so `rustc --cap-
-lints warn` will make lints set to 'forbid' just
-warn.
+levels may still be capped with `--cap-lints` (see below) so `rustc --cap-lints warn`
+will make lints set to 'forbid' just warn.
 
 ## Configuring warning levels
 
index 1d2ef832db77be99662a9d2339740b0080d65ab0..07d05cab1d1d7bbfa719c3cca89ca7a8bb0ccde3 100644 (file)
@@ -293,10 +293,22 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
                     if let Res::Def(DefKind::Mod, ..) = child.res {
                         self.resolve_doc_links_extern_inner(def_id); // Inner attribute scope
                     }
-                    // Traits are processed in `add_extern_traits_in_scope`.
+                    // `DefKind::Trait`s are processed in `process_extern_impls`.
                     if let Res::Def(DefKind::Mod | DefKind::Enum, ..) = child.res {
                         self.process_module_children_or_reexports(def_id);
                     }
+                    if let Res::Def(DefKind::Struct | DefKind::Union | DefKind::Variant, _) =
+                        child.res
+                    {
+                        let field_def_ids = Vec::from_iter(
+                            self.resolver
+                                .cstore()
+                                .associated_item_def_ids_untracked(def_id, self.sess),
+                        );
+                        for field_def_id in field_def_ids {
+                            self.resolve_doc_links_extern_outer(field_def_id, scope_id);
+                        }
+                    }
                 }
             }
         }
index c60dfa3f9518e0998a3a3016af866fedc4645b37..ce529916e5edebbd7e2846ebe4a157158bd4e1c0 100644 (file)
@@ -1,5 +1,6 @@
 // check-pass
 // compile-flags:--test
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 // This test ensures that no code block is detected in the doc comments.
 
index e5c27bebbdb23760134f4ddd98b349116b3c04e6..7326c0a25a069340ea659b1382b6271d853bcc72 100644 (file)
@@ -1,5 +1,5 @@
 
 running 0 tests
 
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/intra-doc/assoc-field.rs b/src/test/rustdoc-ui/intra-doc/assoc-field.rs
new file mode 100644 (file)
index 0000000..e18404e
--- /dev/null
@@ -0,0 +1,26 @@
+// Traits in scope are collected for doc links in field attributes.
+
+// check-pass
+// aux-build: assoc-field-dep.rs
+
+extern crate assoc_field_dep;
+pub use assoc_field_dep::*;
+
+#[derive(Clone)]
+pub struct Struct;
+
+pub mod mod1 {
+    pub struct Fields {
+        /// [crate::Struct::clone]
+        pub field: u8,
+    }
+}
+
+pub mod mod2 {
+    pub enum Fields {
+        V {
+            /// [crate::Struct::clone]
+            field: u8,
+        },
+    }
+}
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs
new file mode 100644 (file)
index 0000000..cfb24fc
--- /dev/null
@@ -0,0 +1,18 @@
+#[derive(Clone)]
+pub struct Struct;
+
+pub mod dep_mod1 {
+    pub struct Fields {
+        /// [crate::Struct::clone]
+        pub field: u8,
+    }
+}
+
+pub mod dep_mod2 {
+    pub enum Fields {
+        V {
+            /// [crate::Struct::clone]
+            field: u8,
+        },
+    }
+}
diff --git a/src/test/ui/destructuring-assignment/struct-or-enum-variant-path.rs b/src/test/ui/destructuring-assignment/struct-or-enum-variant-path.rs
new file mode 100644 (file)
index 0000000..8da7f90
--- /dev/null
@@ -0,0 +1,34 @@
+// check-pass
+
+struct S;
+
+enum E {
+    V,
+}
+
+type A = E;
+
+fn main() {
+    let mut a;
+
+    (S, a) = (S, ());
+
+    (E::V, a) = (E::V, ());
+
+    (<E>::V, a) = (E::V, ());
+    (A::V, a) = (E::V, ());
+}
+
+impl S {
+    fn check() {
+        let a;
+        (Self, a) = (S, ());
+    }
+}
+
+impl E {
+    fn check() {
+        let a;
+        (Self::V, a) = (E::V, ());
+    }
+}
index 8e064d980afabc9be0ee2284753099299eedfe39..91073d3698d911887442f5f9425cbc4cda640e88 100644 (file)
@@ -8,6 +8,11 @@ help: consider importing this function
    |
 LL | use b::bar;
    |
+help: if you import `bar`, refer to it directly
+   |
+LL -     a::bar();
+LL +     bar();
+   | 
 
 error: aborting due to previous error
 
index b610857229201a156a3c5967e7cf11625dfd2f7d..037a858d7e1012fdc56b94613bcc61121c87995a 100644 (file)
@@ -18,6 +18,11 @@ LL | use m2::S;
    |
 LL | use xm2::S;
    |
+help: if you import `S`, refer to it directly
+   |
+LL -     check(m1::S);
+LL +     check(S);
+   | 
 
 error[E0423]: expected value, found type alias `xm1::S`
   --> $DIR/namespace-mix.rs:40:11
@@ -41,6 +46,11 @@ LL | use m2::S;
    |
 LL | use xm2::S;
    |
+help: if you import `S`, refer to it directly
+   |
+LL -     check(xm1::S);
+LL +     check(S);
+   | 
 
 error[E0423]: expected value, found struct variant `m7::V`
   --> $DIR/namespace-mix.rs:100:11
@@ -67,6 +77,11 @@ LL | use m8::V;
    |
 LL | use xm8::V;
    |
+help: if you import `V`, refer to it directly
+   |
+LL -     check(m7::V);
+LL +     check(V);
+   | 
 
 error[E0423]: expected value, found struct variant `xm7::V`
   --> $DIR/namespace-mix.rs:106:11
@@ -95,6 +110,11 @@ LL | use m8::V;
    |
 LL | use xm8::V;
    |
+help: if you import `V`, refer to it directly
+   |
+LL -     check(xm7::V);
+LL +     check(V);
+   | 
 
 error[E0277]: the trait bound `c::Item: Impossible` is not satisfied
   --> $DIR/namespace-mix.rs:33:11
index ee45f65a3bd5ad1b079e3161e5f843b64f76cef3..c5434c72b382b6a3c289874e115555c6506af22d 100644 (file)
@@ -14,6 +14,11 @@ help: consider importing this function
    |
 LL | use hi_str;
    |
+help: if you import `hi_str`, refer to it directly
+   |
+LL -     println!("{}", circular_modules_main::hi_str());
+LL +     println!("{}", hi_str());
+   | 
 
 error: aborting due to 2 previous errors
 
index 621686dd292d64b53023ae6850e1ad3af21c8c1e..1d26a2c005872524a875f4441063b510a4165e42 100644 (file)
@@ -8,6 +8,11 @@ help: consider importing this unit variant
    |
 LL | use namespaced_enums::Foo::A;
    |
+help: if you import `A`, refer to it directly
+   |
+LL -     let _ = namespaced_enums::A;
+LL +     let _ = A;
+   | 
 
 error[E0425]: cannot find function, tuple struct or tuple variant `B` in crate `namespaced_enums`
   --> $DIR/enums-are-namespaced-xc.rs:7:31
@@ -19,6 +24,11 @@ help: consider importing this tuple variant
    |
 LL | use namespaced_enums::Foo::B;
    |
+help: if you import `B`, refer to it directly
+   |
+LL -     let _ = namespaced_enums::B(10);
+LL +     let _ = B(10);
+   | 
 
 error[E0422]: cannot find struct, variant or union type `C` in crate `namespaced_enums`
   --> $DIR/enums-are-namespaced-xc.rs:9:31
@@ -30,6 +40,11 @@ help: consider importing this variant
    |
 LL | use namespaced_enums::Foo::C;
    |
+help: if you import `C`, refer to it directly
+   |
+LL -     let _ = namespaced_enums::C { a: 10 };
+LL +     let _ = C { a: 10 };
+   | 
 
 error: aborting due to 3 previous errors
 
index 7ec567a06f09dcf3694ddffca05188b708db21fe..4cc035cb11e2034e9e0d178b1ac23d3e721c595b 100644 (file)
@@ -10,6 +10,11 @@ LL | use std::f32::consts::LOG10_2;
    |
 LL | use std::f64::consts::LOG10_2;
    |
+help: if you import `LOG10_2`, refer to it directly
+   |
+LL -     const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize;
+LL +     const M: usize = (f64::from(N) * LOG10_2) as usize;
+   | 
 
 error: aborting due to previous error
 
index 8b292aeda50745fa45553d744c64feb3e103027c..338a5423aa472a58d602f924aace44b62d4f13fd 100644 (file)
@@ -8,6 +8,11 @@ help: consider importing this struct
    |
 LL | use std::collections::HashMap;
    |
+help: if you import `HashMap`, refer to it directly
+   |
+LL -     let _map = std::hahmap::HashMap::new();
+LL +     let _map = HashMap::new();
+   | 
 
 error: aborting due to previous error
 
index c93ba915efb2f36fd919fff93466f6fdd41ba55c..ed89170fd8a75519ea4c3117ecbff87ae0bec5ff 100644 (file)
@@ -105,6 +105,11 @@ LL | use std::f32::consts::E;
    |
 LL | use std::f64::consts::E;
    |
+help: if you import `E`, refer to it directly
+   |
+LL -     let _: E = m::E;
+LL +     let _: E = E;
+   | 
 
 error[E0423]: expected value, found struct variant `m::E::Struct`
   --> $DIR/privacy-enum-ctor.rs:45:16
index 44631f954df33c9ad295651fd35d031f7a93d64d..fcbc28475f99880799cbfaafa5f04174374886f9 100644 (file)
@@ -14,6 +14,11 @@ help: consider importing this builtin type
    |
 LL | use std::primitive::u8;
    |
+help: if you import `u8`, refer to it directly
+   |
+LL -     let _: ::u8;
+LL +     let _: u8;
+   | 
 
 error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/resolve-primitive-fallback.rs:3:5
diff --git a/src/test/ui/suggestions/issue-96223.rs b/src/test/ui/suggestions/issue-96223.rs
new file mode 100644 (file)
index 0000000..85667bb
--- /dev/null
@@ -0,0 +1,52 @@
+// Previously ICEd because we didn't properly track binders in suggestions
+// check-fail
+
+pub trait Foo<'de>: Sized {}
+
+pub trait Bar<'a>: 'static {
+    type Inner: 'a;
+}
+
+pub trait Fubar {
+    type Bar: for<'a> Bar<'a>;
+}
+
+pub struct Baz<T>(pub T);
+
+impl<'de, T> Foo<'de> for Baz<T> where T: Foo<'de> {}
+
+struct Empty;
+
+impl<M> Dummy<M> for Empty
+where
+    M: Fubar,
+    for<'de> Baz<<M::Bar as Bar<'de>>::Inner>: Foo<'de>,
+{
+}
+
+pub trait Dummy<M>
+where
+    M: Fubar,
+{
+}
+
+pub struct EmptyBis<'a>(&'a [u8]);
+
+impl<'a> Bar<'a> for EmptyBis<'static> {
+    type Inner = EmptyBis<'a>;
+}
+
+pub struct EmptyMarker;
+
+impl Fubar for EmptyMarker {
+    type Bar = EmptyBis<'static>;
+}
+
+fn icey_bounds<D: Dummy<EmptyMarker>>(p: &D) {}
+
+fn trigger_ice() {
+    let p = Empty;
+    icey_bounds(&p); //~ERROR the trait bound
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-96223.stderr b/src/test/ui/suggestions/issue-96223.stderr
new file mode 100644 (file)
index 0000000..513725d
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0277]: the trait bound `for<'de> EmptyBis<'de>: Foo<'_>` is not satisfied
+  --> $DIR/issue-96223.rs:49:17
+   |
+LL |     icey_bounds(&p);
+   |     ----------- ^^ the trait `for<'de> Foo<'_>` is not implemented for `EmptyBis<'de>`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Foo<'de>` is implemented for `Baz<T>`
+note: required because of the requirements on the impl of `for<'de> Foo<'de>` for `Baz<EmptyBis<'de>>`
+  --> $DIR/issue-96223.rs:16:14
+   |
+LL | impl<'de, T> Foo<'de> for Baz<T> where T: Foo<'de> {}
+   |              ^^^^^^^^     ^^^^^^
+note: required because of the requirements on the impl of `Dummy<EmptyMarker>` for `Empty`
+  --> $DIR/issue-96223.rs:20:9
+   |
+LL | impl<M> Dummy<M> for Empty
+   |         ^^^^^^^^     ^^^^^
+note: required by a bound in `icey_bounds`
+  --> $DIR/issue-96223.rs:45:19
+   |
+LL | fn icey_bounds<D: Dummy<EmptyMarker>>(p: &D) {}
+   |                   ^^^^^^^^^^^^^^^^^^ required by this bound in `icey_bounds`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed
new file mode 100644 (file)
index 0000000..39e90d7
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+#![allow(non_snake_case)]
+mod A {
+    pub trait Trait {}
+    impl Trait for i32 {}
+}
+
+mod B {
+    use A::Trait;
+
+pub struct A<H: Trait>(pub H); //~ ERROR cannot find trait
+}
+
+fn main() {
+    let _ = B::A(42);
+}
diff --git a/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs
new file mode 100644 (file)
index 0000000..ee6ed0c
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+#![allow(non_snake_case)]
+mod A {
+    pub trait Trait {}
+    impl Trait for i32 {}
+}
+
+mod B {
+    pub struct A<H: A::Trait>(pub H); //~ ERROR cannot find trait
+}
+
+fn main() {
+    let _ = B::A(42);
+}
diff --git a/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr
new file mode 100644 (file)
index 0000000..a8b275f
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0405]: cannot find trait `Trait` in `A`
+  --> $DIR/shadowed-path-in-trait-bound-suggestion.rs:9:24
+   |
+LL |     pub struct A<H: A::Trait>(pub H);
+   |                        ^^^^^ not found in `A`
+   |
+help: consider importing this trait
+   |
+LL |     use A::Trait;
+   |
+help: if you import `Trait`, refer to it directly
+   |
+LL -     pub struct A<H: A::Trait>(pub H);
+LL +     pub struct A<H: Trait>(pub H);
+   | 
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0405`.
index f3d818cc3485dd0c617da2a3591418a2b39b032a..54b93a20a057d9b0fc8171f93afe5b2a7934e404 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_parse::parser;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{kw, Symbol};
-use rustc_span::{sym, BytePos, Span, DUMMY_SP};
+use rustc_span::{sym, BytePos, InnerSpan, Span, DUMMY_SP};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -454,6 +454,7 @@ fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) {
                 }
             },
             ArgumentNamed(n, _) => {
+                let n = Symbol::intern(n);
                 if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
                     match x.1.as_slice() {
                         // A non-empty format string has been seen already.
@@ -495,7 +496,7 @@ fn parse_fmt_string(&self, cx: &EarlyContext<'_>, str_lit: &StrLit) -> Option<Si
             let span = parser
                 .arg_places
                 .last()
-                .map_or(DUMMY_SP, |&x| str_lit.span.from_inner(x));
+                .map_or(DUMMY_SP, |&x| str_lit.span.from_inner(InnerSpan::new(x.start, x.end)));
 
             if !self.in_debug_impl && arg.format.ty == "?" {
                 // FIXME: modify rustc's fmt string parser to give us the current span