diff --git a/Cargo.lock b/Cargo.lock index 04397408099ee..4d8d5111583e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2486,7 +2486,6 @@ dependencies = [ "serde_json", "smallvec", "tempfile", - "tikv-jemalloc-sys", "ui_test", ] diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 4e605ef625199..0e8cdc266f899 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -99,7 +99,7 @@ fn resolve_block<'tcx>( for (i, statement) in blk.stmts.iter().enumerate() { match statement.kind { hir::StmtKind::Let(LetStmt { els: Some(els), .. }) => { - // Let-else has a special lexical structure for variables. + // let-else has a special lexical structure for variables. // First we take a checkpoint of the current scope context here. let mut prev_cx = visitor.cx; diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 4a741169443dd..f65b99d5f99f0 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -334,7 +334,7 @@ mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count *[other] variants that aren't } matched -mir_build_suggest_let_else = you might want to use `let else` to handle the {$count -> +mir_build_suggest_let_else = you might want to use `let...else` to handle the {$count -> [one] variant that isn't *[other] variants that aren't } matched diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index c74333f5655ad..7055e60956a9c 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -732,8 +732,6 @@ parse_or_in_let_chain = `||` operators are not supported in let chain conditions parse_or_pattern_not_allowed_in_fn_parameters = function parameters require top-level or-patterns in parentheses parse_or_pattern_not_allowed_in_let_binding = `let` bindings require top-level or-patterns in parentheses -parse_out_of_range_hex_escape = out of range hex escape - .label = must be a character in the range [\x00-\x7f] parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index bde179c9438f2..62a333fbf81d7 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2455,12 +2455,6 @@ pub(crate) enum UnescapeError { is_hex: bool, ch: String, }, - #[diag(parse_out_of_range_hex_escape)] - OutOfRangeHexEscape( - #[primary_span] - #[label] - Span, - ), #[diag(parse_leading_underscore_unicode_escape)] LeadingUnderscoreUnicodeEscape { #[primary_span] diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index ec59a1a01314e..895374ab2cc4b 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -226,7 +226,24 @@ pub(crate) fn emit_unescape_error( err.emit() } EscapeError::OutOfRangeHexEscape => { - dcx.emit_err(UnescapeError::OutOfRangeHexEscape(err_span)) + let mut err = dcx.struct_span_err(err_span, "out of range hex escape"); + err.span_label(err_span, "must be a character in the range [\\x00-\\x7f]"); + + let escape_str = &lit[range]; + if lit.len() <= 4 + && escape_str.len() == 4 + && escape_str.starts_with("\\x") + && let Ok(value) = u8::from_str_radix(&escape_str[2..4], 16) + && matches!(mode, Mode::Char | Mode::Str) + { + err.help(format!("if you want to write a byte literal, use `b'{}'`", escape_str)); + err.help(format!( + "if you want to write a Unicode character, use `'\\u{{{:X}}}'`", + value + )); + } + + err.emit() } EscapeError::LeadingUnderscoreUnicodeEscape => { let (c, span) = last_char(); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 3fe8971f3d6c6..26393bf61a32e 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -867,7 +867,7 @@ impl<'a> Parser<'a> { if let_else || !if_let { err.span_suggestion_verbose( block_span.shrink_to_lo(), - format!("{alternatively}you might have meant to use `let else`"), + format!("{alternatively}you might have meant to use `let...else`"), "else ".to_string(), if let_else { Applicability::MachineApplicable diff --git a/library/std/src/env.rs b/library/std/src/env.rs index fd662e8a663a9..5c068ad2471ad 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -1097,7 +1097,7 @@ pub mod consts { /// * `"nto"` /// * `"redox"` /// * `"solaris"` - /// * `"solid_asp3` + /// * `"solid_asp3"` /// * `"vexos"` /// * `"vita"` /// * `"vxworks"` diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 0d765018d77bf..535e6a510ca68 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1567,6 +1567,11 @@ tool_rustc_extended!(Miri { tool_name: "miri", stable: false, add_bins_to_sysroot: ["miri"], + add_features: |builder, target, features| { + if builder.config.jemalloc(target) { + features.push("jemalloc".to_string()); + } + }, // Always compile also tests when building miri. Otherwise feature unification can cause rebuilds between building and testing miri. cargo_args: &["--all-targets"], }); diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index a26ae7d284443..08465ea541b80 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -197,6 +197,37 @@ themselves marked as unstable. To use any of these options, pass `-Z unstable-op the flag in question to Rustdoc on the command-line. To do this from Cargo, you can either use the `RUSTDOCFLAGS` environment variable or the `cargo rustdoc` command. +### `--merge`, `--parts-out-dir`, and `--include-parts-dir` + +These options control how rustdoc handles files that combine data from multiple crates. + +By default, they act like `--merge=shared` is set, and `--parts-out-dir` and `--include-parts-dir` +are turned off. The `--merge=shared` mode causes rustdoc to load the existing data in the out-dir, +combine the new crate data into it, and write the result. This is very easy to use in scripts that +manually invoke rustdoc, but it's also slow, because it performs O(crates) work on +every crate, meaning it performs O(crates2) work. + +```console +$ rustdoc crate1.rs --out-dir=doc +$ cat doc/search.index/crateNames/* +rd_("fcrate1") +$ rustdoc crate2.rs --out-dir=doc +$ cat doc/search.index/crateNames/* +rd_("fcrate1fcrate2") +``` + +To delay shared-data merging until the end of a build, so that you only have to perform O(crates) +work, use `--merge=none` on every crate except the last one, which will use `--merge=finalize`. + +```console +$ rustdoc +nightly crate1.rs --merge=none --parts-out-dir=crate1.d -Zunstable-options +$ cat doc/search.index/crateNames/* +cat: 'doc/search.index/crateNames/*': No such file or directory +$ rustdoc +nightly crate2.rs --merge=finalize --include-parts-dir=crate1.d -Zunstable-options +$ cat doc/search.index/crateNames/* +rd_("fcrate1fcrate2") +``` + ### `--document-hidden-items`: Show items that are `#[doc(hidden)]` diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index da19f506a3700..5d16dff24c69a 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -978,15 +978,16 @@ fn parse_extern_html_roots( Ok(externs) } -/// Path directly to crate-info file. +/// Path directly to crate-info directory. /// -/// For example, `/home/user/project/target/doc.parts//crate-info`. +/// For example, `/home/user/project/target/doc.parts`. +/// Each crate has its info stored in a file called `CRATENAME.json`. #[derive(Clone, Debug)] pub(crate) struct PathToParts(pub(crate) PathBuf); impl PathToParts { fn from_flag(path: String) -> Result { - let mut path = PathBuf::from(path); + let path = PathBuf::from(path); // check here is for diagnostics if path.exists() && !path.is_dir() { Err(format!( @@ -995,20 +996,22 @@ impl PathToParts { )) } else { // if it doesn't exist, we'll create it. worry about that in write_shared - path.push("crate-info"); Ok(PathToParts(path)) } } } -/// Reports error if --include-parts-dir / crate-info is not a file +/// Reports error if --include-parts-dir is not a directory fn parse_include_parts_dir(m: &getopts::Matches) -> Result, String> { let mut ret = Vec::new(); for p in m.opt_strs("include-parts-dir") { let p = PathToParts::from_flag(p)?; // this is just for diagnostic - if !p.0.is_file() { - return Err(format!("--include-parts-dir expected {} to be a file", p.0.display())); + if !p.0.is_dir() { + return Err(format!( + "--include-parts-dir expected {} to be a directory", + p.0.display() + )); } ret.push(p); } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index dd91cec531f59..eee13ff2b0dc0 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1252,9 +1252,9 @@ struct Indent(usize); impl Display for Indent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (0..self.0).for_each(|_| { - f.write_char(' ').unwrap(); - }); + for _ in 0..self.0 { + f.write_char(' ')?; + } Ok(()) } } diff --git a/src/librustdoc/html/length_limit.rs b/src/librustdoc/html/length_limit.rs index fdb1ddc1f5311..f786215a93be4 100644 --- a/src/librustdoc/html/length_limit.rs +++ b/src/librustdoc/html/length_limit.rs @@ -87,7 +87,7 @@ impl HtmlWithLimit { pub(super) fn close_tag(&mut self) { if let Some(tag_name) = self.unclosed_tags.pop() { // Close the most recently opened tag. - write!(self.buf, "").unwrap() + write!(self.buf, "").expect("infallible string operation"); } // There are valid cases where `close_tag()` is called without // there being any tags to close. For example, this occurs when @@ -99,7 +99,7 @@ impl HtmlWithLimit { /// Write all queued tags and add them to the `unclosed_tags` list. fn flush_queue(&mut self) { for tag_name in self.queued_tags.drain(..) { - write!(self.buf, "<{tag_name}>").unwrap(); + write!(self.buf, "<{tag_name}>").expect("infallible string operation"); self.unclosed_tags.push(tag_name); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 871ed53bd3380..9c8e599104be4 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -916,7 +916,7 @@ fn render_impls( impls: &[&Impl], containing_item: &clean::Item, toggle_open_by_default: bool, -) { +) -> fmt::Result { let mut rendered_impls = impls .iter() .map(|i| { @@ -942,7 +942,7 @@ fn render_impls( }) .collect::>(); rendered_impls.sort(); - w.write_str(&rendered_impls.join("")).unwrap(); + w.write_str(&rendered_impls.join("")) } /// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item. @@ -1037,7 +1037,7 @@ fn assoc_const( ) -> impl fmt::Display { let tcx = cx.tcx(); fmt::from_fn(move |w| { - render_attributes_in_code(w, it, &" ".repeat(indent), cx); + render_attributes_in_code(w, it, &" ".repeat(indent), cx)?; write!( w, "{indent}{vis}const {name}{generics}: {ty}", @@ -1145,10 +1145,10 @@ fn assoc_method( let (indent, indent_str, end_newline) = if parent == ItemType::Trait { header_len += 4; let indent_str = " "; - render_attributes_in_code(w, meth, indent_str, cx); + render_attributes_in_code(w, meth, indent_str, cx)?; (4, indent_str, Ending::NoNewline) } else { - render_attributes_in_code(w, meth, "", cx); + render_attributes_in_code(w, meth, "", cx)?; (0, "", Ending::Newline) }; write!( @@ -1365,10 +1365,10 @@ fn render_all_impls( concrete: &[&Impl], synthetic: &[&Impl], blanket_impl: &[&Impl], -) { +) -> fmt::Result { let impls = { let mut buf = String::new(); - render_impls(cx, &mut buf, concrete, containing_item, true); + render_impls(cx, &mut buf, concrete, containing_item, true)?; buf }; if !impls.is_empty() { @@ -1376,8 +1376,7 @@ fn render_all_impls( w, "{}
{impls}
", write_impl_section_heading("Trait Implementations", "trait-implementations") - ) - .unwrap(); + )?; } if !synthetic.is_empty() { @@ -1385,10 +1384,9 @@ fn render_all_impls( w, "{}
", write_impl_section_heading("Auto Trait Implementations", "synthetic-implementations",) - ) - .unwrap(); - render_impls(cx, &mut w, synthetic, containing_item, false); - w.write_str("
").unwrap(); + )?; + render_impls(cx, &mut w, synthetic, containing_item, false)?; + w.write_str("")?; } if !blanket_impl.is_empty() { @@ -1396,11 +1394,11 @@ fn render_all_impls( w, "{}
", write_impl_section_heading("Blanket Implementations", "blanket-implementations") - ) - .unwrap(); - render_impls(cx, &mut w, blanket_impl, containing_item, false); - w.write_str("
").unwrap(); + )?; + render_impls(cx, &mut w, blanket_impl, containing_item, false)?; + w.write_str("")?; } + Ok(()) } fn render_assoc_items( @@ -1412,8 +1410,7 @@ fn render_assoc_items( fmt::from_fn(move |f| { let mut derefs = DefIdSet::default(); derefs.insert(it); - render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs); - Ok(()) + render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs) }) } @@ -1424,10 +1421,10 @@ fn render_assoc_items_inner( it: DefId, what: AssocItemRender<'_>, derefs: &mut DefIdSet, -) { +) -> fmt::Result { info!("Documenting associated items of {:?}", containing_item.name); let cache = &cx.shared.cache; - let Some(v) = cache.impls.get(&it) else { return }; + let Some(v) = cache.impls.get(&it) else { return Ok(()) }; let (mut non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { @@ -1511,8 +1508,7 @@ fn render_assoc_items_inner( matches!(what, AssocItemRender::DerefFor { .. }) .then_some("") .maybe_display(), - ) - .unwrap(); + )?; } } @@ -1522,13 +1518,13 @@ fn render_assoc_items_inner( if let Some(impl_) = deref_impl { let has_deref_mut = traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait()); - render_deref_methods(&mut w, cx, impl_, containing_item, has_deref_mut, derefs); + render_deref_methods(&mut w, cx, impl_, containing_item, has_deref_mut, derefs)?; } // If we were already one level into rendering deref methods, we don't want to render // anything after recursing into any further deref methods above. if let AssocItemRender::DerefFor { .. } = what { - return; + return Ok(()); } let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = @@ -1536,8 +1532,9 @@ fn render_assoc_items_inner( let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket()); - render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl); + render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl)?; } + Ok(()) } /// `derefs` is the set of all deref targets that have already been handled. @@ -1548,7 +1545,7 @@ fn render_deref_methods( container_item: &clean::Item, deref_mut: bool, derefs: &mut DefIdSet, -) { +) -> fmt::Result { let cache = cx.cache(); let deref_type = impl_.inner_impl().trait_.as_ref().unwrap(); let (target, real_target) = impl_ @@ -1574,15 +1571,16 @@ fn render_deref_methods( // `impl Deref for S` if did == type_did || !derefs.insert(did) { // Avoid infinite cycles - return; + return Ok(()); } } - render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs); + render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs)?; } else if let Some(prim) = target.primitive_type() && let Some(&did) = cache.primitive_locations.get(&prim) { - render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs); + render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs)?; } + Ok(()) } fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool { @@ -1805,8 +1803,7 @@ fn render_impl( // because impls can't have a stability. if !item.doc_value().is_empty() { document_item_info(cx, it, Some(parent)) - .render_into(&mut info_buffer) - .unwrap(); + .render_into(&mut info_buffer)?; doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string(); short_documented = false; } else { @@ -1823,9 +1820,7 @@ fn render_impl( } } } else { - document_item_info(cx, item, Some(parent)) - .render_into(&mut info_buffer) - .unwrap(); + document_item_info(cx, item, Some(parent)).render_into(&mut info_buffer)?; if rendering_params.show_def_docs { doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string(); short_documented = false; @@ -2920,7 +2915,7 @@ fn render_attributes_in_code( item: &clean::Item, prefix: &str, cx: &Context<'_>, -) { +) -> fmt::Result { for attr in &item.attrs.other_attrs { let hir::Attribute::Parsed(kind) = attr else { continue }; let attr = match kind { @@ -2934,24 +2929,30 @@ fn render_attributes_in_code( AttributeKind::NonExhaustive(..) => Cow::Borrowed("#[non_exhaustive]"), _ => continue, }; - render_code_attribute(prefix, attr.as_ref(), w); + render_code_attribute(prefix, attr.as_ref(), w)?; } if let Some(def_id) = item.def_id() && let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id) { - render_code_attribute(prefix, &repr, w); + render_code_attribute(prefix, &repr, w)?; } + Ok(()) } -fn render_repr_attribute_in_code(w: &mut impl fmt::Write, cx: &Context<'_>, def_id: DefId) { +fn render_repr_attribute_in_code( + w: &mut impl fmt::Write, + cx: &Context<'_>, + def_id: DefId, +) -> fmt::Result { if let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id) { - render_code_attribute("", &repr, w); + render_code_attribute("", &repr, w)?; } + Ok(()) } -fn render_code_attribute(prefix: &str, attr: &str, w: &mut impl fmt::Write) { - write!(w, "
{prefix}{attr}
").unwrap(); +fn render_code_attribute(prefix: &str, attr: &str, w: &mut impl fmt::Write) -> fmt::Result { + write!(w, "
{prefix}{attr}
") } /// Compute the *public* `#[repr]` of the item given by `DefId`. diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index fa7c9e75fdac4..0c511738d7c8a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -457,7 +457,7 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i "\ " )?; - render_attributes_in_code(w, myitem, "", cx); + render_attributes_in_code(w, myitem, "", cx)?; write!( w, "{vis}{imp}{stab_tags}\ @@ -625,7 +625,7 @@ fn item_function(cx: &Context<'_>, it: &clean::Item, f: &clean::Function) -> imp let notable_traits = notable_traits_button(&f.decl.output, cx).maybe_display(); wrap_item(w, |w| { - render_attributes_in_code(w, it, "", cx); + render_attributes_in_code(w, it, "", cx)?; write!( w, "{vis}{constness}{asyncness}{safety}{abi}fn \ @@ -666,7 +666,7 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt: // Output the trait definition wrap_item(w, |mut w| { - render_attributes_in_code(&mut w, it, "", cx); + render_attributes_in_code(&mut w, it, "", cx)?; write!( w, "{vis}{safety}{is_auto}trait {name}{generics}{bounds}", @@ -1240,7 +1240,7 @@ fn item_trait_alias( ) -> impl fmt::Display { fmt::from_fn(|w| { wrap_item(w, |w| { - render_attributes_in_code(w, it, "", cx); + render_attributes_in_code(w, it, "", cx)?; write!( w, "trait {name}{generics} = {bounds}{where_clause};", @@ -1268,7 +1268,7 @@ fn item_trait_alias( fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> impl fmt::Display { fmt::from_fn(|w| { wrap_item(w, |w| { - render_attributes_in_code(w, it, "", cx); + render_attributes_in_code(w, it, "", cx)?; write!( w, "{vis}type {name}{generics}{where_clause} = {type_};", @@ -1464,7 +1464,7 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { fn print_field_attrs(&self, field: &'a clean::Item) -> impl Display { fmt::from_fn(move |w| { - render_attributes_in_code(w, field, "", self.cx); + render_attributes_in_code(w, field, "", self.cx)?; Ok(()) }) } @@ -1554,9 +1554,9 @@ impl<'clean> DisplayEnum<'clean> { wrap_item(w, |w| { if is_type_alias { // For now the only attributes we render for type aliases are `repr` attributes. - render_repr_attribute_in_code(w, cx, self.def_id); + render_repr_attribute_in_code(w, cx, self.def_id)?; } else { - render_attributes_in_code(w, it, "", cx); + render_attributes_in_code(w, it, "", cx)?; } write!( w, @@ -1695,7 +1695,7 @@ fn render_enum_fields( if v.is_stripped() { continue; } - render_attributes_in_code(w, v, TAB, cx); + render_attributes_in_code(w, v, TAB, cx)?; w.write_str(TAB)?; match v.kind { clean::VariantItem(ref var) => match var.kind { @@ -1779,7 +1779,7 @@ fn item_variants( ) .maybe_display() )?; - render_attributes_in_code(w, variant, "", cx); + render_attributes_in_code(w, variant, "", cx)?; if let clean::VariantItem(ref var) = variant.kind && let clean::VariantKind::CLike = var.kind { @@ -1855,7 +1855,7 @@ fn item_variants( ยง\ " )?; - render_attributes_in_code(w, field, "", cx); + render_attributes_in_code(w, field, "", cx)?; write!( w, "{f}: {t}\ @@ -1881,7 +1881,7 @@ fn item_macro(cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) -> impl fmt: fmt::from_fn(|w| { wrap_item(w, |w| { // FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`. - render_attributes_in_code(w, it, "", cx); + render_attributes_in_code(w, it, "", cx)?; if !t.macro_rules { write!(w, "{}", visibility_print_with_space(it, cx))?; } @@ -1927,16 +1927,15 @@ fn item_primitive(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display { let def_id = it.item_id.expect_def_id(); write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) { - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All))?; + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)) } else { // We handle the "reference" primitive type on its own because we only want to list // implementations on generic types. let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&cx.shared, it); - render_all_impls(w, cx, it, &concrete, &synthetic, &blanket_impl); + render_all_impls(w, cx, it, &concrete, &synthetic, &blanket_impl) } - Ok(()) }) } @@ -1950,7 +1949,7 @@ fn item_constant( fmt::from_fn(|w| { wrap_item(w, |w| { let tcx = cx.tcx(); - render_attributes_in_code(w, it, "", cx); + render_attributes_in_code(w, it, "", cx)?; write!( w, @@ -2016,9 +2015,9 @@ impl<'a> DisplayStruct<'a> { wrap_item(w, |w| { if is_type_alias { // For now the only attributes we render for type aliases are `repr` attributes. - render_repr_attribute_in_code(w, cx, self.def_id); + render_repr_attribute_in_code(w, cx, self.def_id)?; } else { - render_attributes_in_code(w, it, "", cx); + render_attributes_in_code(w, it, "", cx)?; } write!( w, @@ -2097,7 +2096,7 @@ fn item_fields( ", item_type = ItemType::StructField, )?; - render_attributes_in_code(w, field, "", cx); + render_attributes_in_code(w, field, "", cx)?; write!( w, "{field_name}: {ty}\ @@ -2120,7 +2119,7 @@ fn item_static( ) -> impl fmt::Display { fmt::from_fn(move |w| { wrap_item(w, |w| { - render_attributes_in_code(w, it, "", cx); + render_attributes_in_code(w, it, "", cx)?; write!( w, "{vis}{safe}static {mutability}{name}: {typ}", @@ -2140,8 +2139,8 @@ fn item_foreign_type(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display { fmt::from_fn(|w| { wrap_item(w, |w| { w.write_str("extern {\n")?; - render_attributes_in_code(w, it, "", cx); - write!(w, " {}type {};\n}}", visibility_print_with_space(it, cx), it.name.unwrap(),) + render_attributes_in_code(w, it, "", cx)?; + write!(w, " {}type {};\n}}", visibility_print_with_space(it, cx), it.name.unwrap()) })?; write!( @@ -2292,15 +2291,14 @@ fn print_bounds( .maybe_display() } -fn wrap_item(w: &mut W, f: F) -> T +fn wrap_item(w: &mut W, f: F) -> fmt::Result where W: fmt::Write, - F: FnOnce(&mut W) -> T, + F: FnOnce(&mut W) -> fmt::Result, { - write!(w, r#"
"#).unwrap();
-    let res = f(w);
-    write!(w, "
").unwrap(); - res + w.write_str(r#"
"#)?;
+    f(w)?;
+    w.write_str("
") } #[derive(PartialEq, Eq)] @@ -2370,9 +2368,9 @@ fn render_union( fmt::from_fn(move |mut f| { if is_type_alias { // For now the only attributes we render for type aliases are `repr` attributes. - render_repr_attribute_in_code(f, cx, def_id); + render_repr_attribute_in_code(f, cx, def_id)?; } else { - render_attributes_in_code(f, it, "", cx); + render_attributes_in_code(f, it, "", cx)?; } write!(f, "{}union {}", visibility_print_with_space(it, cx), it.name.unwrap(),)?; @@ -2403,7 +2401,7 @@ fn render_union( for field in fields { if let clean::StructFieldItem(ref ty) = field.kind { - render_attributes_in_code(&mut f, field, " ", cx); + render_attributes_in_code(&mut f, field, " ", cx)?; writeln!( f, " {}{}: {},", @@ -2500,7 +2498,7 @@ fn render_struct_fields( } for field in fields { if let clean::StructFieldItem(ref ty) = field.kind { - render_attributes_in_code(w, field, &format!("{tab} "), cx); + render_attributes_in_code(w, field, &format!("{tab} "), cx)?; writeln!( w, "{tab} {vis}{name}: {ty},", diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 6045b9a77ecae..8b6776ffa4b8c 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -14,7 +14,7 @@ //! or contains "invocation-specific". use std::cell::RefCell; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fs::File; use std::io::{self, Write as _}; use std::iter::once; @@ -84,9 +84,11 @@ pub(crate) fn write_shared( }; if let Some(parts_out_dir) = &opt.parts_out_dir { - create_parents(&parts_out_dir.0)?; + let mut parts_out_file = parts_out_dir.0.clone(); + parts_out_file.push(&format!("{crate_name}.json")); + create_parents(&parts_out_file)?; try_err!( - fs::write(&parts_out_dir.0, serde_json::to_string(&info).unwrap()), + fs::write(&parts_out_file, serde_json::to_string(&info).unwrap()), &parts_out_dir.0 ); } @@ -238,13 +240,25 @@ impl CrateInfo { pub(crate) fn read_many(parts_paths: &[PathToParts]) -> Result, Error> { parts_paths .iter() - .map(|parts_path| { - let path = &parts_path.0; - let parts = try_err!(fs::read(path), &path); - let parts: CrateInfo = try_err!(serde_json::from_slice(&parts), &path); - Ok::<_, Error>(parts) + .fold(Ok(Vec::new()), |acc, parts_path| { + let mut acc = acc?; + let dir = &parts_path.0; + acc.append(&mut try_err!(std::fs::read_dir(dir), dir.as_path()) + .filter_map(|file| { + let to_crate_info = |file: Result| -> Result, Error> { + let file = try_err!(file, dir.as_path()); + if file.path().extension() != Some(OsStr::new("json")) { + return Ok(None); + } + let parts = try_err!(fs::read(file.path()), file.path()); + let parts: CrateInfo = try_err!(serde_json::from_slice(&parts), file.path()); + Ok(Some(parts)) + }; + to_crate_info(file).transpose() + }) + .collect::, Error>>()?); + Ok(acc) }) - .collect::, Error>>() } } diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 611e549930a9e..2235203e2d791 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -29,13 +29,6 @@ directories = "6" bitflags = "2.6" serde_json = { version = "1.0", optional = true } -# Copied from `compiler/rustc/Cargo.toml`. -# But only for some targets, it fails for others. Rustc configures this in its CI, but we can't -# easily use that since we support of-tree builds. -[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies.tikv-jemalloc-sys] -version = "0.6.1" -features = ['override_allocator_on_supported_platforms'] - [target.'cfg(unix)'.dependencies] libc = "0.2" # native-lib dependencies @@ -75,6 +68,7 @@ stack-cache = [] expensive-consistency-checks = ["stack-cache"] tracing = ["serde_json"] native-lib = ["dep:libffi", "dep:libloading", "dep:capstone", "dep:ipc-channel", "dep:nix", "dep:serde"] +jemalloc = [] [lints.rust.unexpected_cfgs] level = "warn" diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index d7c5cb68e4f08..9f1ff238359a1 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -21,9 +21,13 @@ extern crate rustc_session; extern crate rustc_span; /// See docs in https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc/src/main.rs -/// and https://github.com/rust-lang/rust/pull/146627 for why we need this `use` statement. -#[cfg(any(target_os = "linux", target_os = "macos"))] -use tikv_jemalloc_sys as _; +/// and https://github.com/rust-lang/rust/pull/146627 for why we need this. +/// +/// FIXME(madsmtm): This is loaded from the sysroot that was built with the other `rustc` crates +/// above, instead of via Cargo as you'd normally do. This is currently needed for LTO due to +/// https://github.com/rust-lang/cc-rs/issues/1613. +#[cfg(feature = "jemalloc")] +extern crate tikv_jemalloc_sys as _; mod log; diff --git a/tests/run-make/rustdoc-merge-directory/dep1.rs b/tests/run-make/rustdoc-merge-directory/dep1.rs new file mode 100644 index 0000000000000..5a1238adec0eb --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory/dep1.rs @@ -0,0 +1,4 @@ +//@ hasraw crates.js 'dep1' +//@ hasraw search.index/name/*.js 'Dep1' +//@ has dep1/index.html +pub struct Dep1; diff --git a/tests/run-make/rustdoc-merge-directory/dep2.rs b/tests/run-make/rustdoc-merge-directory/dep2.rs new file mode 100644 index 0000000000000..238ff2e4f9b70 --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory/dep2.rs @@ -0,0 +1,4 @@ +//@ hasraw crates.js 'dep1' +//@ hasraw search.index/name/*.js 'Dep1' +//@ has dep2/index.html +pub struct Dep2; diff --git a/tests/run-make/rustdoc-merge-directory/dep_missing.rs b/tests/run-make/rustdoc-merge-directory/dep_missing.rs new file mode 100644 index 0000000000000..74236aef47ea5 --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory/dep_missing.rs @@ -0,0 +1,4 @@ +//@ !hasraw crates.js 'dep_missing' +//@ !hasraw search.index/name/*.js 'DepMissing' +//@ has dep_missing/index.html +pub struct DepMissing; diff --git a/tests/run-make/rustdoc-merge-directory/rmake.rs b/tests/run-make/rustdoc-merge-directory/rmake.rs new file mode 100644 index 0000000000000..e4695ddad0b48 --- /dev/null +++ b/tests/run-make/rustdoc-merge-directory/rmake.rs @@ -0,0 +1,46 @@ +// Running --merge=finalize without an input crate root should not trigger ICE. +// Issue: https://github.com/rust-lang/rust/issues/146646 + +//@ needs-target-std + +use run_make_support::{htmldocck, path, rustdoc}; + +fn main() { + let out_dir = path("out"); + let merged_dir = path("merged"); + let parts_out_dir = path("parts"); + + rustdoc() + .input("dep1.rs") + .out_dir(&out_dir) + .arg("-Zunstable-options") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) + .arg("--merge=none") + .run(); + assert!(parts_out_dir.join("dep1.json").exists()); + + rustdoc() + .input("dep2.rs") + .out_dir(&out_dir) + .arg("-Zunstable-options") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) + .arg("--merge=none") + .run(); + assert!(parts_out_dir.join("dep2.json").exists()); + + // dep_missing is different, because --parts-out-dir is not supplied + rustdoc().input("dep_missing.rs").out_dir(&out_dir).run(); + assert!(parts_out_dir.join("dep2.json").exists()); + + let output = rustdoc() + .arg("-Zunstable-options") + .out_dir(&out_dir) + .arg(format!("--include-parts-dir={}", parts_out_dir.display())) + .arg("--merge=finalize") + .run(); + output.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); + + htmldocck().arg(&out_dir).arg("dep1.rs").run(); + htmldocck().arg(&out_dir).arg("dep2.rs").run(); + htmldocck().arg(out_dir).arg("dep_missing.rs").run(); +} diff --git a/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs b/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs index d750a36f44534..4dad01f341fef 100644 --- a/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs +++ b/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs @@ -16,7 +16,7 @@ fn main() { .arg(format!("--parts-out-dir={}", parts_out_dir.display())) .arg("--merge=none") .run(); - assert!(parts_out_dir.join("crate-info").exists()); + assert!(parts_out_dir.join("sierra.json").exists()); let output = rustdoc() .arg("-Zunstable-options") diff --git a/tests/ui/empty/empty-never-array.stderr b/tests/ui/empty/empty-never-array.stderr index ee04ff162a4cb..cd8a80e3d49d7 100644 --- a/tests/ui/empty/empty-never-array.stderr +++ b/tests/ui/empty/empty-never-array.stderr @@ -14,7 +14,7 @@ LL | enum Helper { LL | T(T, [!; 0]), | - not covered = note: the matched value is of type `Helper` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Helper::U(u) = Helper::T(t, []) else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/error-codes/E0005.stderr b/tests/ui/error-codes/E0005.stderr index c643ee07a3739..004812cad9f18 100644 --- a/tests/ui/error-codes/E0005.stderr +++ b/tests/ui/error-codes/E0005.stderr @@ -7,7 +7,7 @@ LL | let Some(y) = x; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `Option` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Some(y) = x else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr index b596da8463f21..614f382d67327 100644 --- a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr +++ b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr @@ -7,7 +7,7 @@ LL | let Ok(_x) = &foo(); = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `&Result` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Ok(_x) = &foo() else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.stderr b/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.stderr index 65903dbe12e57..9e13cf510e838 100644 --- a/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.stderr +++ b/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.stderr @@ -17,7 +17,7 @@ LL | let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `[i32; 8]` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr index 17b65c1dae548..dec0fe1fe0d79 100644 --- a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr +++ b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr @@ -17,7 +17,7 @@ LL | let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `[i32; 8]` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/parser/ascii-only-character-escape.stderr b/tests/ui/parser/ascii-only-character-escape.stderr index b599b35f4b324..78844ae385e47 100644 --- a/tests/ui/parser/ascii-only-character-escape.stderr +++ b/tests/ui/parser/ascii-only-character-escape.stderr @@ -3,18 +3,27 @@ error: out of range hex escape | LL | let x = "\x80"; | ^^^^ must be a character in the range [\x00-\x7f] + | + = help: if you want to write a byte literal, use `b'\x80'` + = help: if you want to write a Unicode character, use `'\u{80}'` error: out of range hex escape --> $DIR/ascii-only-character-escape.rs:3:14 | LL | let y = "\xff"; | ^^^^ must be a character in the range [\x00-\x7f] + | + = help: if you want to write a byte literal, use `b'\xff'` + = help: if you want to write a Unicode character, use `'\u{FF}'` error: out of range hex escape --> $DIR/ascii-only-character-escape.rs:4:14 | LL | let z = "\xe2"; | ^^^^ must be a character in the range [\x00-\x7f] + | + = help: if you want to write a byte literal, use `b'\xe2'` + = help: if you want to write a Unicode character, use `'\u{E2}'` error: aborting due to 3 previous errors diff --git a/tests/ui/parser/out-of-range-hex-escape-suggestions-148917.rs b/tests/ui/parser/out-of-range-hex-escape-suggestions-148917.rs new file mode 100644 index 0000000000000..ee8489fef8004 --- /dev/null +++ b/tests/ui/parser/out-of-range-hex-escape-suggestions-148917.rs @@ -0,0 +1,21 @@ +fn main() { + let _c = '\xFF'; //~ ERROR out of range hex escape + let _s = "\xFF"; //~ ERROR out of range hex escape + + let _c2 = '\xff'; //~ ERROR out of range hex escape + let _s2 = "\xff"; //~ ERROR out of range hex escape + + let _c3 = '\x80'; //~ ERROR out of range hex escape + let _s3 = "\x80"; //~ ERROR out of range hex escape + + // Byte literals should not get suggestions (they're already valid) + let _b = b'\xFF'; // OK + let _bs = b"\xFF"; // OK + + dbg!('\xFF'); //~ ERROR out of range hex escape + + // do not suggest for out of range escapes that are too long + dbg!("\xFFFFF"); //~ ERROR out of range hex escape + + dbg!("this is some kind of string \xa7"); //~ ERROR out of range hex escape +} diff --git a/tests/ui/parser/out-of-range-hex-escape-suggestions-148917.stderr b/tests/ui/parser/out-of-range-hex-escape-suggestions-148917.stderr new file mode 100644 index 0000000000000..e0485bfe50ea5 --- /dev/null +++ b/tests/ui/parser/out-of-range-hex-escape-suggestions-148917.stderr @@ -0,0 +1,77 @@ +error: out of range hex escape + --> $DIR/out-of-range-hex-escape-suggestions-148917.rs:2:15 + | +LL | let _c = '\xFF'; + | ^^^^ must be a character in the range [\x00-\x7f] + | + = help: if you want to write a byte literal, use `b'\xFF'` + = help: if you want to write a Unicode character, use `'\u{FF}'` + +error: out of range hex escape + --> $DIR/out-of-range-hex-escape-suggestions-148917.rs:3:15 + | +LL | let _s = "\xFF"; + | ^^^^ must be a character in the range [\x00-\x7f] + | + = help: if you want to write a byte literal, use `b'\xFF'` + = help: if you want to write a Unicode character, use `'\u{FF}'` + +error: out of range hex escape + --> $DIR/out-of-range-hex-escape-suggestions-148917.rs:5:16 + | +LL | let _c2 = '\xff'; + | ^^^^ must be a character in the range [\x00-\x7f] + | + = help: if you want to write a byte literal, use `b'\xff'` + = help: if you want to write a Unicode character, use `'\u{FF}'` + +error: out of range hex escape + --> $DIR/out-of-range-hex-escape-suggestions-148917.rs:6:16 + | +LL | let _s2 = "\xff"; + | ^^^^ must be a character in the range [\x00-\x7f] + | + = help: if you want to write a byte literal, use `b'\xff'` + = help: if you want to write a Unicode character, use `'\u{FF}'` + +error: out of range hex escape + --> $DIR/out-of-range-hex-escape-suggestions-148917.rs:8:16 + | +LL | let _c3 = '\x80'; + | ^^^^ must be a character in the range [\x00-\x7f] + | + = help: if you want to write a byte literal, use `b'\x80'` + = help: if you want to write a Unicode character, use `'\u{80}'` + +error: out of range hex escape + --> $DIR/out-of-range-hex-escape-suggestions-148917.rs:9:16 + | +LL | let _s3 = "\x80"; + | ^^^^ must be a character in the range [\x00-\x7f] + | + = help: if you want to write a byte literal, use `b'\x80'` + = help: if you want to write a Unicode character, use `'\u{80}'` + +error: out of range hex escape + --> $DIR/out-of-range-hex-escape-suggestions-148917.rs:15:11 + | +LL | dbg!('\xFF'); + | ^^^^ must be a character in the range [\x00-\x7f] + | + = help: if you want to write a byte literal, use `b'\xFF'` + = help: if you want to write a Unicode character, use `'\u{FF}'` + +error: out of range hex escape + --> $DIR/out-of-range-hex-escape-suggestions-148917.rs:18:11 + | +LL | dbg!("\xFFFFF"); + | ^^^^ must be a character in the range [\x00-\x7f] + +error: out of range hex escape + --> $DIR/out-of-range-hex-escape-suggestions-148917.rs:20:39 + | +LL | dbg!("this is some kind of string \xa7"); + | ^^^^ must be a character in the range [\x00-\x7f] + +error: aborting due to 9 previous errors + diff --git a/tests/ui/pattern/issue-106552.stderr b/tests/ui/pattern/issue-106552.stderr index 6d9a989f182ea..06f33ecf10667 100644 --- a/tests/ui/pattern/issue-106552.stderr +++ b/tests/ui/pattern/issue-106552.stderr @@ -25,7 +25,7 @@ LL | let x @ 5 = 6; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `i32` -help: you might want to use `let else` to handle the variants that aren't matched +help: you might want to use `let...else` to handle the variants that aren't matched | LL | let x @ 5 = 6 else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr index d241f417553fc..a234ad435c970 100644 --- a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr @@ -152,7 +152,7 @@ LL | let Ok(_x) = res_u32_never.as_ref(); = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `Result<&u32, &!>` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr index ea63d7ba1afd1..3fff1a3805c82 100644 --- a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr +++ b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr @@ -106,7 +106,7 @@ LL | let Ok(_x) = res_u32_never.as_ref(); = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `Result<&u32, &!>` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; | ++++++++++++++++ @@ -120,7 +120,7 @@ LL | let Ok(_x) = &res_u32_never; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `&Result` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Ok(_x) = &res_u32_never else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr index a1a44e7774428..28f9650557efc 100644 --- a/tests/ui/pattern/usefulness/empty-types.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr @@ -97,7 +97,7 @@ LL | let Ok(_x) = res_u32_never.as_ref(); = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `Result<&u32, &!>` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; | ++++++++++++++++ @@ -111,7 +111,7 @@ LL | let Ok(_x) = &res_u32_never; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `&Result` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Ok(_x) = &res_u32_never else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/pattern/usefulness/issue-31561.stderr b/tests/ui/pattern/usefulness/issue-31561.stderr index 382b2337ffaba..389c1126b9848 100644 --- a/tests/ui/pattern/usefulness/issue-31561.stderr +++ b/tests/ui/pattern/usefulness/issue-31561.stderr @@ -17,7 +17,7 @@ LL | Bar, LL | Baz | --- not covered = note: the matched value is of type `Thing` -help: you might want to use `let else` to handle the variants that aren't matched +help: you might want to use `let...else` to handle the variants that aren't matched | LL | let Thing::Foo(y) = Thing::Foo(1) else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr index 48d7a636055dc..d31510d66e0c9 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr @@ -183,7 +183,7 @@ LL | enum Opt { LL | None, | ---- not covered = note: the matched value is of type `Opt` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Opt::Some(ref _x) = e else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr b/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr index 35d436a1413ed..cd78c0f0bb45c 100644 --- a/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr +++ b/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr @@ -7,7 +7,7 @@ LL | let Ok(x) = res; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `Result>` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Ok(x) = res else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr index c2c9ac15ab220..f8bf6f8cb28bc 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr @@ -138,7 +138,7 @@ LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html = note: the matched value is of type `NonExhaustiveEnum` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/uninhabited/missing-if-let-or-let-else.rs b/tests/ui/uninhabited/missing-if-let-or-let-else.rs index 51fedb797562c..c8cc672a82aa4 100644 --- a/tests/ui/uninhabited/missing-if-let-or-let-else.rs +++ b/tests/ui/uninhabited/missing-if-let-or-let-else.rs @@ -6,14 +6,14 @@ fn a() { } fn b() { let Some(x) = foo() { //~ ERROR expected one of - //~^ HELP you might have meant to use `let else` + //~^ HELP you might have meant to use `let...else` return; } } fn c() { let Some(x) = foo() { //~ ERROR expected one of //~^ HELP you might have meant to use `if let` - //~| HELP alternatively, you might have meant to use `let else` + //~| HELP alternatively, you might have meant to use `let...else` // The parser check happens pre-macro-expansion, so we don't know for sure. println!("{x}"); } diff --git a/tests/ui/uninhabited/missing-if-let-or-let-else.stderr b/tests/ui/uninhabited/missing-if-let-or-let-else.stderr index 4b78a0fa16e8d..f13147dd7fc50 100644 --- a/tests/ui/uninhabited/missing-if-let-or-let-else.stderr +++ b/tests/ui/uninhabited/missing-if-let-or-let-else.stderr @@ -15,7 +15,7 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `{` LL | let Some(x) = foo() { | ^ expected one of `.`, `;`, `?`, `else`, or an operator | -help: you might have meant to use `let else` +help: you might have meant to use `let...else` | LL | let Some(x) = foo() else { | ++++ @@ -30,7 +30,7 @@ help: you might have meant to use `if let` | LL | if let Some(x) = foo() { | ++ -help: alternatively, you might have meant to use `let else` +help: alternatively, you might have meant to use `let...else` | LL | let Some(x) = foo() else { | ++++ diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr b/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr index 0e87f14aa14ae..a4270c29ff35b 100644 --- a/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr +++ b/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr @@ -16,7 +16,7 @@ LL | A(foo::SecretlyEmpty), | - not covered = note: pattern `Foo::A(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future = note: the matched value is of type `Foo` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Foo::D(_y, _z) = x else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr b/tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr index 0e87f14aa14ae..a4270c29ff35b 100644 --- a/tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr +++ b/tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr @@ -16,7 +16,7 @@ LL | A(foo::SecretlyEmpty), | - not covered = note: pattern `Foo::A(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future = note: the matched value is of type `Foo` -help: you might want to use `let else` to handle the variant that isn't matched +help: you might want to use `let...else` to handle the variant that isn't matched | LL | let Foo::D(_y, _z) = x else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.rs b/tests/ui/uninhabited/uninhabited-irrefutable.rs index 3f7414e596bf1..9f4731e6e71a2 100644 --- a/tests/ui/uninhabited/uninhabited-irrefutable.rs +++ b/tests/ui/uninhabited/uninhabited-irrefutable.rs @@ -34,5 +34,5 @@ fn main() { //~| NOTE for more information //~| NOTE pattern `Foo::A(_)` is currently uninhabited //~| NOTE the matched value is of type `Foo` - //~| HELP you might want to use `let else` + //~| HELP you might want to use `let...else` }