Auto merge of #150912 - matthiaskrgr:rollup-SHXgjYS, r=matthiaskrgr

Rollup of 11 pull requests

Successful merges:

 - rust-lang/rust#150269 (Remove inactive nvptx maintainer)
 - rust-lang/rust#150713 (mgca: Type-check fields of struct expr const args)
 - rust-lang/rust#150765 (rustc_parse_format: improve error for missing `:` before `?` in format args)
 - rust-lang/rust#150847 (Fix broken documentation links to SipHash)
 - rust-lang/rust#150867 (rustdoc_json: Remove one call to `std::mem::take` in `after_krate`)
 - rust-lang/rust#150872 (Fix some loop block coercion diagnostics)
 - rust-lang/rust#150874 (Ignore `rustc-src-gpl` in fast try builds)
 - rust-lang/rust#150875 (Refactor artifact keep mode in bootstrap)
 - rust-lang/rust#150876 (Mention that `rustc_codegen_gcc` is a subtree in `rustc-dev-guide`)
 - rust-lang/rust#150882 (Supress unused_parens lint for guard patterns)
 - rust-lang/rust#150884 (Update bors email in CI postprocessing step)

Failed merges:

 - rust-lang/rust#150869 (Emit error instead of delayed bug when meeting mismatch type for const tuple)

r? @ghost
This commit is contained in:
rust-bors[bot] 2026-01-10 22:52:39 +00:00 committed by GitHub
commit ad04f76d84
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 495 additions and 123 deletions

View file

@ -289,7 +289,7 @@ jobs:
fi
# Get closest bors merge commit
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
PARENT_COMMIT=`git rev-list --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1`
./build/citool/debug/citool postprocess-metrics \
--job-name ${CI_JOB_NAME} \

View file

@ -182,6 +182,8 @@ builtin_macros_expected_other = expected operand, {$is_inline_asm ->
builtin_macros_export_macro_rules = cannot export macro_rules! macros from a `proc-macro` crate type currently
builtin_macros_format_add_missing_colon = add a colon before the format specifier
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
.label1 = previously here
.label2 = duplicate argument

View file

@ -643,6 +643,15 @@ pub(crate) enum InvalidFormatStringSuggestion {
span: Span,
replacement: String,
},
#[suggestion(
builtin_macros_format_add_missing_colon,
code = ":?",
applicability = "machine-applicable"
)]
AddMissingColon {
#[primary_span]
span: Span,
},
}
#[derive(Diagnostic)]

View file

@ -329,6 +329,10 @@ fn make_format_args(
replacement,
});
}
parse::Suggestion::AddMissingColon(span) => {
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span });
}
}
let guar = ecx.dcx().emit_err(e);
return ExpandResult::Ready(Err(guar));

View file

@ -54,7 +54,7 @@ use rustc_middle::ty::adjustment::{
};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span};
use rustc_span::{BytePos, DUMMY_SP, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor};
use rustc_trait_selection::solve::{Certainty, Goal, NoSolution};
@ -1828,10 +1828,9 @@ impl<'tcx> CoerceMany<'tcx> {
// If the block is from an external macro or try (`?`) desugaring, then
// do not suggest adding a semicolon, because there's nowhere to put it.
// See issues #81943 and #87051.
&& matches!(
cond_expr.span.desugaring_kind(),
None | Some(DesugaringKind::WhileLoop)
)
// Similarly, if the block is from a loop desugaring, then also do not
// suggest adding a semicolon. See issue #150850.
&& cond_expr.span.desugaring_kind().is_none()
&& !cond_expr.span.in_external_macro(fcx.tcx.sess.source_map())
&& !matches!(
cond_expr.kind,

View file

@ -10,8 +10,8 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind,
WherePredicateKind, expr_needs_parens, is_range_literal,
GenericBound, HirId, LoopSource, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind,
TyKind, WherePredicateKind, expr_needs_parens, is_range_literal,
};
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_hir_analysis::suggest_impl_trait;
@ -1170,15 +1170,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let found = self.resolve_vars_if_possible(found);
let in_loop = self.is_loop(id)
|| self
.tcx
let innermost_loop = if self.is_loop(id) {
Some(self.tcx.hir_node(id))
} else {
self.tcx
.hir_parent_iter(id)
.take_while(|(_, node)| {
// look at parents until we find the first body owner
node.body_id().is_none()
})
.any(|(parent_id, _)| self.is_loop(parent_id));
.find_map(|(parent_id, node)| self.is_loop(parent_id).then_some(node))
};
let can_break_with_value = innermost_loop.is_some_and(|node| {
matches!(
node,
Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::Loop, ..), .. })
)
});
let in_local_statement = self.is_local_statement(id)
|| self
@ -1186,7 +1194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.hir_parent_iter(id)
.any(|(parent_id, _)| self.is_local_statement(parent_id));
if in_loop && in_local_statement {
if can_break_with_value && in_local_statement {
err.multipart_suggestion(
"you might have meant to break the loop with this value",
vec![

View file

@ -1190,6 +1190,8 @@ impl UnusedParens {
// `&(a..=b)`, there is a recursive `check_pat` on `a` and `b`, but we will assume
// that if there are unnecessary parens they serve a purpose of readability.
PatKind::Range(..) => return,
// Parentheses may be necessary to disambiguate precedence in guard patterns.
PatKind::Guard(..) => return,
// Avoid `p0 | .. | pn` if we should.
PatKind::Or(..) if avoid_or => return,
// Avoid `mut x` and `mut x @ p` if we should:

View file

@ -191,8 +191,7 @@ impl<'tcx> Value<'tcx> {
}
}
/// Destructures array, ADT or tuple constants into the constants
/// of their fields.
/// Destructures ADT constants into the constants of their fields.
pub fn destructure_adt_const(&self) -> ty::DestructuredAdtConst<'tcx> {
let fields = self.to_branch();

View file

@ -184,6 +184,9 @@ pub enum Suggestion {
/// `format!("{foo:?x}")` -> `format!("{foo:x?}")`
/// `format!("{foo:?X}")` -> `format!("{foo:X?}")`
ReorderFormatParameter(Range<usize>, String),
/// Add missing colon:
/// `format!("{foo?}")` -> `format!("{foo:?}")`
AddMissingColon(Range<usize>),
}
/// The parser structure for interpreting the input format string. This is
@ -453,10 +456,11 @@ impl<'input> Parser<'input> {
suggestion: Suggestion::None,
});
if let Some((_, _, c)) = self.peek() {
match c {
'?' => self.suggest_format_debug(),
'<' | '^' | '>' => self.suggest_format_align(c),
if let (Some((_, _, c)), Some((_, _, nc))) = (self.peek(), self.peek_ahead()) {
match (c, nc) {
('?', '}') => self.missing_colon_before_debug_formatter(),
('?', _) => self.suggest_format_debug(),
('<' | '^' | '>', _) => self.suggest_format_align(c),
_ => self.suggest_positional_arg_instead_of_captured_arg(arg),
}
}
@ -849,6 +853,23 @@ impl<'input> Parser<'input> {
}
}
fn missing_colon_before_debug_formatter(&mut self) {
if let Some((range, _)) = self.consume_pos('?') {
let span = range.clone();
self.errors.insert(
0,
ParseError {
description: "expected `}`, found `?`".to_owned(),
note: Some(format!("to print `{{`, you can escape it using `{{{{`",)),
label: "expected `:` before `?` to format with `Debug`".to_owned(),
span: range,
secondary_label: None,
suggestion: Suggestion::AddMissingColon(span),
},
);
}
}
fn suggest_format_align(&mut self, alignment: char) {
if let Some((range, _)) = self.consume_pos(alignment) {
self.errors.insert(

View file

@ -1051,7 +1051,53 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
| ty::ConstKind::Placeholder(..) => {
// These variants are trivially WF, so nothing to do here.
}
ty::ConstKind::Value(..) => {
ty::ConstKind::Value(val) => {
// FIXME(mgca): no need to feature-gate once valtree lifetimes are not erased
if tcx.features().min_generic_const_args() {
match val.ty.kind() {
ty::Adt(adt_def, args) => {
let adt_val = val.destructure_adt_const();
let variant_def = adt_def.variant(adt_val.variant);
let cause = self.cause(ObligationCauseCode::WellFormed(None));
self.out.extend(variant_def.fields.iter().zip(adt_val.fields).map(
|(field_def, &field_val)| {
let field_ty =
tcx.type_of(field_def.did).instantiate(tcx, args);
let predicate = ty::PredicateKind::Clause(
ty::ClauseKind::ConstArgHasType(field_val, field_ty),
);
traits::Obligation::with_depth(
tcx,
cause.clone(),
self.recursion_depth,
self.param_env,
predicate,
)
},
));
}
ty::Tuple(field_tys) => {
let field_vals = val.to_branch();
let cause = self.cause(ObligationCauseCode::WellFormed(None));
self.out.extend(field_tys.iter().zip(field_vals).map(
|(field_ty, &field_val)| {
let predicate = ty::PredicateKind::Clause(
ty::ClauseKind::ConstArgHasType(field_val, field_ty),
);
traits::Obligation::with_depth(
tcx,
cause.clone(),
self.recursion_depth,
self.param_env,
predicate,
)
},
));
}
_ => {}
}
}
// FIXME: Enforce that values are structurally-matchable.
}
}

View file

@ -10,7 +10,7 @@ use crate::{cmp, ptr};
/// This is currently the default hashing function used by standard library
/// (e.g., `collections::HashMap` uses it by default).
///
/// See: <https://131002.net/siphash>
/// See: <https://github.com/veorq/SipHash>
#[unstable(feature = "hashmap_internals", issue = "none")]
#[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)]
@ -21,7 +21,7 @@ pub struct SipHasher13 {
/// An implementation of SipHash 2-4.
///
/// See: <https://131002.net/siphash/>
/// See: <https://github.com/veorq/SipHash>
#[unstable(feature = "hashmap_internals", issue = "none")]
#[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)]
@ -31,7 +31,7 @@ struct SipHasher24 {
/// An implementation of SipHash 2-4.
///
/// See: <https://131002.net/siphash/>
/// See: <https://github.com/veorq/SipHash>
///
/// SipHash is a general-purpose hashing function: it runs at a good
/// speed (competitive with Spooky and City) and permits strong _keyed_

View file

@ -4,7 +4,8 @@ use std::fs;
use std::path::{Path, PathBuf};
use crate::core::build_steps::compile::{
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
ArtifactKeepMode, add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo,
std_crates_for_run_make,
};
use crate::core::build_steps::tool;
use crate::core::build_steps::tool::{
@ -111,8 +112,7 @@ impl Step for Std {
builder.config.free_args.clone(),
&check_stamp,
vec![],
true,
false,
ArtifactKeepMode::OnlyRmeta,
);
drop(_guard);
@ -148,7 +148,14 @@ impl Step for Std {
build_compiler,
target,
);
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&stamp,
vec![],
ArtifactKeepMode::OnlyRmeta,
);
check_stamp
}
@ -368,7 +375,14 @@ impl Step for Rustc {
let stamp =
build_stamp::librustc_stamp(builder, build_compiler, target).with_prefix("check");
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&stamp,
vec![],
ArtifactKeepMode::OnlyRmeta,
);
stamp
}
@ -568,7 +582,14 @@ impl Step for CraneliftCodegenBackend {
)
.with_prefix("check");
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&stamp,
vec![],
ArtifactKeepMode::OnlyRmeta,
);
}
fn metadata(&self) -> Option<StepMetadata> {
@ -639,7 +660,14 @@ impl Step for GccCodegenBackend {
)
.with_prefix("check");
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&stamp,
vec![],
ArtifactKeepMode::OnlyRmeta,
);
}
fn metadata(&self) -> Option<StepMetadata> {
@ -777,7 +805,14 @@ fn run_tool_check_step(
.with_prefix(&format!("{display_name}-check"));
let _guard = builder.msg(builder.kind, display_name, mode, build_compiler, target);
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
run_cargo(
builder,
cargo,
builder.config.free_args.clone(),
&stamp,
vec![],
ArtifactKeepMode::OnlyRmeta,
);
}
tool_check_step!(Rustdoc {

View file

@ -15,7 +15,7 @@
use build_helper::exit;
use super::compile::{run_cargo, rustc_cargo, std_cargo};
use super::compile::{ArtifactKeepMode, run_cargo, rustc_cargo, std_cargo};
use super::tool::{SourceType, prepare_tool_cargo};
use crate::builder::{Builder, ShouldRun};
use crate::core::build_steps::check::{CompilerForCheck, prepare_compiler_for_check};
@ -214,8 +214,7 @@ impl Step for Std {
lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC),
&build_stamp::libstd_stamp(builder, build_compiler, target),
vec![],
true,
false,
ArtifactKeepMode::OnlyRmeta,
);
}
@ -309,8 +308,7 @@ impl Step for Rustc {
lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC),
&build_stamp::librustc_stamp(builder, build_compiler, target),
vec![],
true,
false,
ArtifactKeepMode::OnlyRmeta,
);
}
@ -380,7 +378,7 @@ impl Step for CodegenGcc {
.with_prefix("rustc_codegen_gcc-check");
let args = lint_args(builder, &self.config, &[]);
run_cargo(builder, cargo, args.clone(), &stamp, vec![], true, false);
run_cargo(builder, cargo, args.clone(), &stamp, vec![], ArtifactKeepMode::OnlyRmeta);
// Same but we disable the features enabled by default.
let mut cargo = prepare_tool_cargo(
@ -396,7 +394,7 @@ impl Step for CodegenGcc {
self.build_compiler.configure_cargo(&mut cargo);
println!("Now running clippy on `rustc_codegen_gcc` with `--no-default-features`");
cargo.arg("--no-default-features");
run_cargo(builder, cargo, args, &stamp, vec![], true, false);
run_cargo(builder, cargo, args, &stamp, vec![], ArtifactKeepMode::OnlyRmeta);
}
fn metadata(&self) -> Option<StepMetadata> {
@ -478,8 +476,7 @@ macro_rules! lint_any {
lint_args(builder, &self.config, &[]),
&stamp,
vec![],
true,
false,
ArtifactKeepMode::OnlyRmeta
);
}

View file

@ -296,8 +296,11 @@ impl Step for Std {
vec![],
&stamp,
target_deps,
self.is_for_mir_opt_tests, // is_check
false,
if self.is_for_mir_opt_tests {
ArtifactKeepMode::OnlyRmeta
} else {
ArtifactKeepMode::OnlyRlib
},
);
builder.ensure(StdLink::from_std(
@ -1167,14 +1170,28 @@ impl Step for Rustc {
target,
);
let stamp = build_stamp::librustc_stamp(builder, build_compiler, target);
run_cargo(
builder,
cargo,
vec![],
&stamp,
vec![],
false,
true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files.
ArtifactKeepMode::Custom(Box::new(|filename| {
if filename.contains("jemalloc_sys")
|| filename.contains("rustc_public_bridge")
|| filename.contains("rustc_public")
{
// jemalloc_sys and rustc_public_bridge are not linked into librustc_driver.so,
// so we need to distribute them as rlib to be able to use them.
filename.ends_with(".rlib")
} else {
// Distribute the rest of the rustc crates as rmeta files only to reduce
// the tarball sizes by about 50%. The object files are linked into
// librustc_driver.so, so it is still possible to link against them.
filename.ends_with(".rmeta")
}
})),
);
let target_root_dir = stamp.path().parent().unwrap();
@ -1714,7 +1731,7 @@ impl Step for GccCodegenBackend {
let _guard =
builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host);
let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
let files = run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib);
GccCodegenBackendOutput {
stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()),
@ -1790,7 +1807,7 @@ impl Step for CraneliftCodegenBackend {
build_compiler,
target,
);
let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
let files = run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib);
write_codegen_backend_stamp(stamp, files, builder.config.dry_run())
}
@ -2620,14 +2637,26 @@ pub fn add_to_sysroot(
}
}
/// Specifies which rlib/rmeta artifacts outputted by Cargo should be put into the resulting
/// build stamp, and thus be included in dist archives and copied into sysroots by default.
/// Note that some kinds of artifacts are copied automatically (e.g. native libraries).
pub enum ArtifactKeepMode {
/// Only keep .rlib files, ignore .rmeta files
OnlyRlib,
/// Only keep .rmeta files, ignore .rlib files
OnlyRmeta,
/// Custom logic for keeping an artifact
/// It receives the filename of an artifact, and returns true if it should be kept.
Custom(Box<dyn Fn(&str) -> bool>),
}
pub fn run_cargo(
builder: &Builder<'_>,
cargo: Cargo,
tail_args: Vec<String>,
stamp: &BuildStamp,
additional_target_deps: Vec<(PathBuf, DependencyType)>,
is_check: bool,
rlib_only_metadata: bool,
artifact_keep_mode: ArtifactKeepMode,
) -> Vec<PathBuf> {
// `target_root_dir` looks like $dir/$target/release
let target_root_dir = stamp.path().parent().unwrap();
@ -2661,36 +2690,20 @@ pub fn run_cargo(
};
for filename in filenames_vec {
// Skip files like executables
let mut keep = false;
if filename.ends_with(".lib")
let keep = if filename.ends_with(".lib")
|| filename.ends_with(".a")
|| is_debug_info(&filename)
|| is_dylib(Path::new(&*filename))
{
// Always keep native libraries, rust dylibs and debuginfo
keep = true;
}
if is_check && filename.ends_with(".rmeta") {
// During check builds we need to keep crate metadata
keep = true;
} else if rlib_only_metadata {
if filename.contains("jemalloc_sys")
|| filename.contains("rustc_public_bridge")
|| filename.contains("rustc_public")
{
// jemalloc_sys and rustc_public_bridge are not linked into librustc_driver.so,
// so we need to distribute them as rlib to be able to use them.
keep |= filename.ends_with(".rlib");
} else {
// Distribute the rest of the rustc crates as rmeta files only to reduce
// the tarball sizes by about 50%. The object files are linked into
// librustc_driver.so, so it is still possible to link against them.
keep |= filename.ends_with(".rmeta");
}
true
} else {
// In all other cases keep all rlibs
keep |= filename.ends_with(".rlib");
}
match &artifact_keep_mode {
ArtifactKeepMode::OnlyRlib => filename.ends_with(".rlib"),
ArtifactKeepMode::OnlyRmeta => filename.ends_with(".rmeta"),
ArtifactKeepMode::Custom(func) => func(&filename),
}
};
if !keep {
continue;

View file

@ -14,7 +14,7 @@ use std::{env, fs, iter};
use build_helper::exit;
use crate::core::build_steps::compile::{Std, run_cargo};
use crate::core::build_steps::compile::{ArtifactKeepMode, Std, run_cargo};
use crate::core::build_steps::doc::{DocumentationFormat, prepare_doc_compiler};
use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags};
use crate::core::build_steps::llvm::get_llvm_version;
@ -2587,7 +2587,8 @@ impl BookTest {
let stamp = BuildStamp::new(&builder.cargo_out(test_compiler, mode, target))
.with_prefix(PathBuf::from(dep).file_name().and_then(|v| v.to_str()).unwrap());
let output_paths = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
let output_paths =
run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib);
let directories = output_paths
.into_iter()
.filter_map(|p| p.parent().map(ToOwned::to_owned))

View file

@ -22,6 +22,7 @@ The following external projects are managed using some form of a `subtree`:
* [rustfmt](https://github.com/rust-lang/rustfmt)
* [rust-analyzer](https://github.com/rust-lang/rust-analyzer)
* [rustc_codegen_cranelift](https://github.com/rust-lang/rustc_codegen_cranelift)
* [rustc_codegen_gcc](https://github.com/rust-lang/rustc_codegen_gcc)
* [rustc-dev-guide](https://github.com/rust-lang/rustc-dev-guide)
* [compiler-builtins](https://github.com/rust-lang/compiler-builtins)
* [stdarch](https://github.com/rust-lang/stdarch)
@ -40,6 +41,7 @@ implement a new tool feature or test, that should happen in one collective rustc
* `portable-simd` ([sync script](https://github.com/rust-lang/portable-simd/blob/master/subtree-sync.sh))
* `rustfmt`
* `rustc_codegen_cranelift` ([sync script](https://github.com/rust-lang/rustc_codegen_cranelift/blob/113af154d459e41b3dc2c5d7d878e3d3a8f33c69/scripts/rustup.sh#L7))
* `rustc_codegen_gcc` ([sync guide](https://github.com/rust-lang/rustc_codegen_gcc/blob/master/doc/subtree.md))
* Using the [josh](#synchronizing-a-josh-subtree) tool
* `miri`
* `rust-analyzer`

View file

@ -7,7 +7,6 @@ platform.
## Target maintainers
[@RDambrosio016](https://github.com/RDambrosio016)
[@kjetilkjeka](https://github.com/kjetilkjeka)
## Requirements

View file

@ -104,22 +104,6 @@ impl<'tcx> JsonRenderer<'tcx> {
})
.unwrap_or_default()
}
fn serialize_and_write<T: Write>(
&self,
output_crate: types::Crate,
mut writer: BufWriter<T>,
path: &str,
) -> Result<(), Error> {
self.sess().time("rustdoc_json_serialize_and_write", || {
try_err!(
serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()),
path
);
try_err!(writer.flush(), path);
Ok(())
})
}
}
impl<'tcx> JsonRenderer<'tcx> {
@ -252,26 +236,23 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
unreachable!("RUN_ON_MODULE = false, should never call mod_item_in")
}
fn after_krate(mut self) -> Result<(), Error> {
fn after_krate(self) -> Result<(), Error> {
debug!("Done with crate");
let e = ExternalCrate { crate_num: LOCAL_CRATE };
// We've finished using the index, and don't want to clone it, because it is big.
let index = std::mem::take(&mut self.index);
let sess = self.sess();
// Note that tcx.rust_target_features is inappropriate here because rustdoc tries to run for
// multiple targets: https://github.com/rust-lang/rust/pull/137632
//
// We want to describe a single target, so pass tcx.sess rather than tcx.
let target = conversions::target(self.tcx.sess);
let target = conversions::target(sess);
debug!("Constructing Output");
let output_crate = types::Crate {
root: self.id_from_item_default(e.def_id().into()),
crate_version: self.cache.crate_version.clone(),
includes_private: self.cache.document_private,
index,
paths: self
.cache
.paths
@ -313,6 +294,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
)
})
.collect(),
// Be careful to not clone the `index`, it is big.
index: self.index,
target,
format_version: types::FORMAT_VERSION,
};
@ -323,17 +306,34 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
p.push(output_crate.index.get(&output_crate.root).unwrap().name.clone().unwrap());
p.set_extension("json");
self.serialize_and_write(
serialize_and_write(
sess,
output_crate,
try_err!(File::create_buffered(&p), p),
&p.display().to_string(),
)
} else {
self.serialize_and_write(output_crate, BufWriter::new(stdout().lock()), "<stdout>")
serialize_and_write(sess, output_crate, BufWriter::new(stdout().lock()), "<stdout>")
}
}
}
fn serialize_and_write<T: Write>(
sess: &Session,
output_crate: types::Crate,
mut writer: BufWriter<T>,
path: &str,
) -> Result<(), Error> {
sess.time("rustdoc_json_serialize_and_write", || {
try_err!(
serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()),
path
);
try_err!(writer.flush(), path);
Ok(())
})
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
//
// These assertions are here, not in `src/rustdoc-json-types/lib.rs` where the types are defined,

View file

@ -450,6 +450,7 @@ fn main() -> anyhow::Result<()> {
"rust-docs-json",
"rust-analyzer",
"rustc-src",
"rustc-src-gpl",
"extended",
"clippy",
"miri",

View file

@ -9,12 +9,8 @@ LL | while true {
error[E0308]: mismatched types
--> $DIR/block-must-not-have-result-while.rs:5:9
|
LL | / while true {
LL | | true
| | ^^^^ expected `()`, found `bool`
LL | |
LL | | }
| |_____- expected this to be `()`
LL | true
| ^^^^ expected `()`, found `bool`
error: aborting due to 1 previous error; 1 warning emitted

View file

@ -12,7 +12,7 @@ fn foo<const N: Option<u32>>() {}
trait Trait {
#[type_const]
const ASSOC: usize;
const ASSOC: u32;
}
fn bar<T: Trait, const N: u32>() {

View file

@ -0,0 +1,26 @@
#![feature(min_generic_const_args, adt_const_params, unsized_const_params)]
#![expect(incomplete_features)]
trait Trait {
#[type_const]
const ASSOC: usize;
}
fn takes_tuple<const A: (u32, u32)>() {}
fn takes_nested_tuple<const A: (u32, (u32, u32))>() {}
fn generic_caller<T: Trait, const N: usize, const N2: u32>() {
takes_tuple::<{ (N, N2) }>();
//~^ ERROR the constant `N` is not of type `u32`
takes_tuple::<{ (N, T::ASSOC) }>();
//~^ ERROR the constant `N` is not of type `u32`
//~| ERROR the constant `<T as Trait>::ASSOC` is not of type `u32`
takes_nested_tuple::<{ (N, (N, N2)) }>();
//~^ ERROR the constant `N` is not of type `u32`
takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>();
//~^ ERROR the constant `N` is not of type `u32`
//~| ERROR the constant `<T as Trait>::ASSOC` is not of type `u32`
}
fn main() {}

View file

@ -0,0 +1,38 @@
error: the constant `N` is not of type `u32`
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:13:21
|
LL | takes_tuple::<{ (N, N2) }>();
| ^^^^^^^ expected `u32`, found `usize`
error: the constant `N` is not of type `u32`
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:15:21
|
LL | takes_tuple::<{ (N, T::ASSOC) }>();
| ^^^^^^^^^^^^^ expected `u32`, found `usize`
error: the constant `<T as Trait>::ASSOC` is not of type `u32`
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:15:21
|
LL | takes_tuple::<{ (N, T::ASSOC) }>();
| ^^^^^^^^^^^^^ expected `u32`, found `usize`
error: the constant `N` is not of type `u32`
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:19:28
|
LL | takes_nested_tuple::<{ (N, (N, N2)) }>();
| ^^^^^^^^^^^^ expected `u32`, found `usize`
error: the constant `N` is not of type `u32`
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:21:28
|
LL | takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>();
| ^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize`
error: the constant `<T as Trait>::ASSOC` is not of type `u32`
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:21:28
|
LL | takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>();
| ^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize`
error: aborting due to 6 previous errors

View file

@ -5,7 +5,7 @@
trait Trait {
#[type_const]
const ASSOC: usize;
const ASSOC: u32;
}
fn takes_tuple<const A: (u32, u32)>() {}

View file

@ -1,17 +1,38 @@
//@ check-pass
// FIXME(mgca): This should error
#![feature(min_generic_const_args, adt_const_params)]
#![expect(incomplete_features)]
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
struct Foo<T> { field: T }
struct S1<T> {
f1: T,
f2: isize,
}
fn accepts<const N: Foo<u8>>() {}
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
struct S2<T>(T, isize);
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
enum En<T> {
Var1(bool, T),
Var2 { field: i64 },
}
fn accepts_1<const N: S1<u8>>() {}
fn accepts_2<const N: S2<u8>>() {}
fn accepts_3<const N: En<u8>>() {}
fn bar<const N: bool>() {
// `N` is not of type `u8` but we don't actually check this anywhere yet
accepts::<{ Foo::<u8> { field: N }}>();
accepts_1::<{ S1::<u8> { f1: N, f2: N } }>();
//~^ ERROR the constant `N` is not of type `u8`
//~| ERROR the constant `N` is not of type `isize`
accepts_2::<{ S2::<u8>(N, N) }>();
//~^ ERROR the constant `N` is not of type `u8`
//~| ERROR the constant `N` is not of type `isize`
accepts_3::<{ En::Var1::<u8>(N, N) }>();
//~^ ERROR the constant `N` is not of type `u8`
accepts_3::<{ En::Var2::<u8> { field: N } }>();
//~^ ERROR the constant `N` is not of type `i64`
accepts_3::<{ En::Var2::<u8> { field: const { false } } }>();
//~^ ERROR mismatched types
}
fn main() {}

View file

@ -0,0 +1,45 @@
error: the constant `N` is not of type `u8`
--> $DIR/adt_expr_fields_type_check.rs:24:19
|
LL | accepts_1::<{ S1::<u8> { f1: N, f2: N } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `bool`
error: the constant `N` is not of type `isize`
--> $DIR/adt_expr_fields_type_check.rs:24:19
|
LL | accepts_1::<{ S1::<u8> { f1: N, f2: N } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `bool`
error: the constant `N` is not of type `u8`
--> $DIR/adt_expr_fields_type_check.rs:27:19
|
LL | accepts_2::<{ S2::<u8>(N, N) }>();
| ^^^^^^^^^^^^^^ expected `u8`, found `bool`
error: the constant `N` is not of type `isize`
--> $DIR/adt_expr_fields_type_check.rs:27:19
|
LL | accepts_2::<{ S2::<u8>(N, N) }>();
| ^^^^^^^^^^^^^^ expected `isize`, found `bool`
error: the constant `N` is not of type `u8`
--> $DIR/adt_expr_fields_type_check.rs:30:19
|
LL | accepts_3::<{ En::Var1::<u8>(N, N) }>();
| ^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `bool`
error: the constant `N` is not of type `i64`
--> $DIR/adt_expr_fields_type_check.rs:32:19
|
LL | accepts_3::<{ En::Var2::<u8> { field: N } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i64`, found `bool`
error[E0308]: mismatched types
--> $DIR/adt_expr_fields_type_check.rs:34:51
|
LL | accepts_3::<{ En::Var2::<u8> { field: const { false } } }>();
| ^^^^^ expected `i64`, found `bool`
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -9,7 +9,7 @@ struct Foo;
trait Trait {
#[type_const]
const ASSOC: usize;
const ASSOC: u32;
}
fn foo<const N: Foo>() {}
@ -27,7 +27,7 @@ fn baz<T: Trait>() {
fn main() {}
fn test_ice_missing_bound<T>() {
foo::<{Option::Some::<u32>{0: <T as Trait>::ASSOC}}>();
foo::<{ Option::Some::<u32> { 0: <T as Trait>::ASSOC } }>();
//~^ ERROR the trait bound `T: Trait` is not satisfied
//~| ERROR the constant `Option::<u32>::Some(_)` is not of type `Foo`
}

View file

@ -25,8 +25,8 @@ LL | fn foo<const N: Foo>() {}
error[E0277]: the trait bound `T: Trait` is not satisfied
--> $DIR/printing_valtrees_supports_non_values.rs:30:5
|
LL | foo::<{Option::Some::<u32>{0: <T as Trait>::ASSOC}}>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
LL | foo::<{ Option::Some::<u32> { 0: <T as Trait>::ASSOC } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
|
help: consider restricting type parameter `T` with trait `Trait`
|
@ -34,10 +34,10 @@ LL | fn test_ice_missing_bound<T: Trait>() {
| +++++++
error: the constant `Option::<u32>::Some(_)` is not of type `Foo`
--> $DIR/printing_valtrees_supports_non_values.rs:30:12
--> $DIR/printing_valtrees_supports_non_values.rs:30:13
|
LL | foo::<{Option::Some::<u32>{0: <T as Trait>::ASSOC}}>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option<u32>`
LL | foo::<{ Option::Some::<u32> { 0: <T as Trait>::ASSOC } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option<u32>`
|
note: required by a const generic parameter in `foo`
--> $DIR/printing_valtrees_supports_non_values.rs:15:8

View file

@ -83,4 +83,7 @@ raw { \n
println!(r#"\x7B}\u8 {"#, 1);
//~^ ERROR invalid format string: unmatched `}` found
println!("{x?}, world!",);
//~^ ERROR invalid format string: expected `}`, found `?`
}

View file

@ -177,5 +177,16 @@ LL | println!(r#"\x7B}\u8 {"#, 1);
|
= note: if you intended to print `}`, you can escape it using `}}`
error: aborting due to 18 previous errors
error: invalid format string: expected `}`, found `?`
--> $DIR/format-string-error-2.rs:87:17
|
LL | println!("{x?}, world!",);
| ^
| |
| expected `:` before `?` to format with `Debug` in format string
| help: add a colon before the format specifier: `:?`
|
= note: to print `{`, you can escape it using `{{`
error: aborting due to 19 previous errors

View file

@ -0,0 +1,39 @@
//! Don't suggest breaking with value from `for` or `while` loops
//!
//! Regression test for https://github.com/rust-lang/rust/issues/150850
fn returns_i32() -> i32 { 0 }
fn suggest_breaking_from_loop() {
let _ = loop {
returns_i32() //~ ERROR mismatched types
//~^ SUGGESTION ;
//~| SUGGESTION break
};
}
fn dont_suggest_breaking_from_for() {
let _ = for _ in 0.. {
returns_i32() //~ ERROR mismatched types
//~^ SUGGESTION ;
};
}
fn dont_suggest_breaking_from_while() {
let cond = true;
let _ = while cond {
returns_i32() //~ ERROR mismatched types
//~^ SUGGESTION ;
};
}
fn dont_suggest_breaking_from_for_nested_in_loop() {
let _ = loop {
for _ in 0.. {
returns_i32() //~ ERROR mismatched types
//~^ SUGGESTION ;
}
};
}
fn main() {}

View file

@ -0,0 +1,42 @@
error[E0308]: mismatched types
--> $DIR/dont-suggest-break-from-unbreakable-loops.rs:9:9
|
LL | returns_i32()
| ^^^^^^^^^^^^^ expected `()`, found `i32`
|
help: consider using a semicolon here
|
LL | returns_i32();
| +
help: you might have meant to break the loop with this value
|
LL | break returns_i32();
| +++++ +
error[E0308]: mismatched types
--> $DIR/dont-suggest-break-from-unbreakable-loops.rs:17:9
|
LL | returns_i32()
| ^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
| |
| expected `()`, found `i32`
error[E0308]: mismatched types
--> $DIR/dont-suggest-break-from-unbreakable-loops.rs:25:9
|
LL | returns_i32()
| ^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
| |
| expected `()`, found `i32`
error[E0308]: mismatched types
--> $DIR/dont-suggest-break-from-unbreakable-loops.rs:33:13
|
LL | returns_i32()
| ^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
| |
| expected `()`, found `i32`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,13 @@
//! Guard patterns require parentheses to disambiguate precedence
//!
//! Regression test for https://github.com/rust-lang/rust/issues/149594
//@ check-pass
#![feature(guard_patterns)]
#![expect(incomplete_features)]
#![warn(unused_parens)]
fn main() {
let (_ if false) = ();
}

View file

@ -2,7 +2,7 @@
//
//@ check-pass
#![feature(guard_patterns, never_type)]
#![expect(incomplete_features, unused_parens)]
#![expect(incomplete_features)]
#![deny(unreachable_code)]
fn main() {