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, "{tag_name}>").unwrap()
+ write!(self.buf, "{tag_name}>").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,
"{}