Auto merge of #147140 - Zalathar:rollup-rtnqek7, r=Zalathar

Rollup of 7 pull requests

Successful merges:

 - rust-lang/rust#133477 (Detect tuple structs that are unconstructable due to re-export)
 - rust-lang/rust#146929 (compiletest: Remove old-output-capture and become a stage0 bootstrap tool)
 - rust-lang/rust#146979 (constify Default on Nanoseconds)
 - rust-lang/rust#147092 (Do not compute optimized MIR if code does not type-check.)
 - rust-lang/rust#147112 (all 48 keywords in just 300 characters)
 - rust-lang/rust#147122 (Fix some crash-test directives)
 - rust-lang/rust#147127 (Add a leading dash to linker plugin arguments in the gcc codegen)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-09-29 05:37:18 +00:00
commit 7af913fc90
38 changed files with 359 additions and 311 deletions

View file

@ -165,6 +165,10 @@ impl CodegenBackend for CraneliftCodegenBackend {
""
}
fn name(&self) -> &'static str {
"cranelift"
}
fn init(&self, sess: &Session) {
use rustc_session::config::{InstrumentCoverage, Lto};
match sess.lto() {

View file

@ -184,6 +184,10 @@ impl CodegenBackend for GccCodegenBackend {
crate::DEFAULT_LOCALE_RESOURCE
}
fn name(&self) -> &'static str {
"gcc"
}
fn init(&self, _sess: &Session) {
#[cfg(feature = "master")]
{

View file

@ -232,6 +232,10 @@ impl CodegenBackend for LlvmCodegenBackend {
crate::DEFAULT_LOCALE_RESOURCE
}
fn name(&self) -> &'static str {
"llvm"
}
fn init(&self, sess: &Session) {
llvm_util::init(sess); // Make sure llvm is inited
}
@ -350,7 +354,14 @@ impl CodegenBackend for LlvmCodegenBackend {
// Run the linker on any artifacts that resulted from the LLVM run.
// This should produce either a finished executable or library.
link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, metadata, outputs);
link_binary(
sess,
&LlvmArchiveBuilderBuilder,
codegen_results,
metadata,
outputs,
self.name(),
);
}
}

View file

@ -79,6 +79,7 @@ pub fn link_binary(
codegen_results: CodegenResults,
metadata: EncodedMetadata,
outputs: &OutputFilenames,
codegen_backend: &'static str,
) {
let _timer = sess.timer("link_binary");
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
@ -154,6 +155,7 @@ pub fn link_binary(
&codegen_results,
&metadata,
path.as_ref(),
codegen_backend,
);
}
}
@ -680,6 +682,7 @@ fn link_natively(
codegen_results: &CodegenResults,
metadata: &EncodedMetadata,
tmpdir: &Path,
codegen_backend: &'static str,
) {
info!("preparing {:?} to {:?}", crate_type, out_filename);
let (linker_path, flavor) = linker_and_flavor(sess);
@ -705,6 +708,7 @@ fn link_natively(
codegen_results,
metadata,
self_contained_components,
codegen_backend,
);
linker::disable_localization(&mut cmd);
@ -2208,6 +2212,7 @@ fn linker_with_args(
codegen_results: &CodegenResults,
metadata: &EncodedMetadata,
self_contained_components: LinkSelfContainedComponents,
codegen_backend: &'static str,
) -> Command {
let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled();
let cmd = &mut *super::linker::get_linker(
@ -2216,6 +2221,7 @@ fn linker_with_args(
flavor,
self_contained_components.are_any_components_enabled(),
&codegen_results.crate_info.target_cpu,
codegen_backend,
);
let link_output_kind = link_output_kind(sess, crate_type);

View file

@ -52,6 +52,7 @@ pub(crate) fn get_linker<'a>(
flavor: LinkerFlavor,
self_contained: bool,
target_cpu: &'a str,
codegen_backend: &'static str,
) -> Box<dyn Linker + 'a> {
let msvc_tool = find_msvc_tools::find_tool(&sess.target.arch, "link.exe");
@ -154,6 +155,7 @@ pub(crate) fn get_linker<'a>(
is_ld: cc == Cc::No,
is_gnu: flavor.is_gnu(),
uses_lld: flavor.uses_lld(),
codegen_backend,
}) as Box<dyn Linker>,
LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
@ -367,6 +369,7 @@ struct GccLinker<'a> {
is_ld: bool,
is_gnu: bool,
uses_lld: bool,
codegen_backend: &'static str,
}
impl<'a> GccLinker<'a> {
@ -423,9 +426,15 @@ impl<'a> GccLinker<'a> {
if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use {
self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
};
let prefix = if self.codegen_backend == "gcc" {
// The GCC linker plugin requires a leading dash.
"-"
} else {
""
};
self.link_args(&[
&format!("-plugin-opt={opt_level}"),
&format!("-plugin-opt=mcpu={}", self.target_cpu),
&format!("-plugin-opt={prefix}{opt_level}"),
&format!("-plugin-opt={prefix}mcpu={}", self.target_cpu),
]);
}

View file

@ -41,6 +41,8 @@ pub trait CodegenBackend {
/// Called before `init` so that all other functions are able to emit translatable diagnostics.
fn locale_resource(&self) -> &'static str;
fn name(&self) -> &'static str;
fn init(&self, _sess: &Session) {}
fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
@ -96,7 +98,14 @@ pub trait CodegenBackend {
metadata: EncodedMetadata,
outputs: &OutputFilenames,
) {
link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, metadata, outputs);
link_binary(
sess,
&ArArchiveBuilderBuilder,
codegen_results,
metadata,
outputs,
self.name(),
);
}
}

View file

@ -1122,18 +1122,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
sess.time("layout_testing", || layout_test::test_layout(tcx));
sess.time("abi_testing", || abi_test::test_abi(tcx));
// If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
// (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
// in MIR optimizations that may only be reachable through codegen, or other codepaths
// that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts.
if tcx.sess.opts.unstable_opts.validate_mir {
sess.time("ensuring_final_MIR_is_computable", || {
tcx.par_hir_body_owners(|def_id| {
tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
});
});
}
}
/// Runs the type-checking, region checking and other miscellaneous analysis
@ -1199,6 +1187,20 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
// we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
let _ = tcx.all_diagnostic_items(());
});
// If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
// (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
// in MIR optimizations that may only be reachable through codegen, or other codepaths
// that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts.
// Nevertheless, wait after type checking is finished, as optimizing code that does not
// type-check is very prone to ICEs.
if tcx.sess.opts.unstable_opts.validate_mir {
sess.time("ensuring_final_MIR_is_computable", || {
tcx.par_hir_body_owners(|def_id| {
tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
});
});
}
}
/// Runs the codegen backend, after which the AST and analysis can

View file

@ -901,6 +901,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
binding,
if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None },
parent_scope,
module,
finalize,
shadowing,
);
@ -1025,6 +1026,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
binding: Option<NameBinding<'ra>>,
shadowed_glob: Option<NameBinding<'ra>>,
parent_scope: &ParentScope<'ra>,
module: Module<'ra>,
finalize: Finalize,
shadowing: Shadowing,
) -> Result<NameBinding<'ra>, (Determinacy, Weak)> {
@ -1076,6 +1078,37 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
self.macro_expanded_macro_export_errors.insert((path_span, binding.span));
}
// If we encounter a re-export for a type with private fields, it will not be able to
// be constructed through this re-export. We track that case here to expand later
// privacy errors with appropriate information.
if let Res::Def(_, def_id) = binding.res() {
let struct_ctor = match def_id.as_local() {
Some(def_id) => self.struct_constructors.get(&def_id).cloned(),
None => {
let ctor = self.cstore().ctor_untracked(def_id);
ctor.map(|(ctor_kind, ctor_def_id)| {
let ctor_res = Res::Def(
DefKind::Ctor(rustc_hir::def::CtorOf::Struct, ctor_kind),
ctor_def_id,
);
let ctor_vis = self.tcx.visibility(ctor_def_id);
let field_visibilities = self
.tcx
.associated_item_def_ids(def_id)
.iter()
.map(|field_id| self.tcx.visibility(field_id))
.collect();
(ctor_res, ctor_vis, field_visibilities)
})
}
};
if let Some((_, _, fields)) = struct_ctor
&& fields.iter().any(|vis| !self.is_accessible_from(*vis, module))
{
self.inaccessible_ctor_reexport.insert(path_span, binding.span);
}
}
self.record_use(ident, binding, used);
return Ok(binding);
}

View file

@ -1942,44 +1942,77 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
return true;
};
let update_message =
|this: &mut Self, err: &mut Diag<'_>, source: &PathSource<'_, '_, '_>| {
match source {
// e.g. `if let Enum::TupleVariant(field1, field2) = _`
PathSource::TupleStruct(_, pattern_spans) => {
err.primary_message(
"cannot match against a tuple struct which contains private fields",
);
// Use spans of the tuple struct pattern.
Some(Vec::from(*pattern_spans))
}
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
PathSource::Expr(Some(Expr {
kind: ExprKind::Call(path, args),
span: call_span,
..
})) => {
err.primary_message(
"cannot initialize a tuple struct which contains private fields",
);
this.suggest_alternative_construction_methods(
def_id,
err,
path.span,
*call_span,
&args[..],
);
// Use spans of the tuple struct definition.
this.r
.field_idents(def_id)
.map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
}
_ => None,
}
};
let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
if let Some(use_span) = self.r.inaccessible_ctor_reexport.get(&span)
&& is_accessible
{
err.span_note(
*use_span,
"the type is accessed through this re-export, but the type's constructor \
is not visible in this import's scope due to private fields",
);
if is_accessible
&& fields
.iter()
.all(|vis| self.r.is_accessible_from(*vis, self.parent_scope.module))
{
err.span_suggestion_verbose(
span,
"the type can be constructed directly, because its fields are \
available from the current scope",
// Using `tcx.def_path_str` causes the compiler to hang.
// We don't need to handle foreign crate types because in that case you
// can't access the ctor either way.
format!(
"crate{}", // The method already has leading `::`.
self.r.tcx.def_path(def_id).to_string_no_crate_verbose(),
),
Applicability::MachineApplicable,
);
}
update_message(self, err, &source);
}
if !is_expected(ctor_def) || is_accessible {
return true;
}
let field_spans = match source {
// e.g. `if let Enum::TupleVariant(field1, field2) = _`
PathSource::TupleStruct(_, pattern_spans) => {
err.primary_message(
"cannot match against a tuple struct which contains private fields",
);
// Use spans of the tuple struct pattern.
Some(Vec::from(pattern_spans))
}
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
PathSource::Expr(Some(Expr {
kind: ExprKind::Call(path, args),
span: call_span,
..
})) => {
err.primary_message(
"cannot initialize a tuple struct which contains private fields",
);
self.suggest_alternative_construction_methods(
def_id,
err,
path.span,
*call_span,
&args[..],
);
// Use spans of the tuple struct definition.
self.r
.field_idents(def_id)
.map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
}
_ => None,
};
let field_spans = update_message(self, err, &source);
if let Some(spans) =
field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len())

View file

@ -1167,6 +1167,11 @@ pub struct Resolver<'ra, 'tcx> {
/// Crate-local macro expanded `macro_export` referred to by a module-relative path.
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(),
/// When a type is re-exported that has an inaccessible constructor because it has fields that
/// are inaccessible from the import's scope, we mark that as the type won't be able to be built
/// through the re-export. We use this information to extend the existing diagnostic.
inaccessible_ctor_reexport: FxHashMap<Span, Span>,
arenas: &'ra ResolverArenas<'ra>,
dummy_binding: NameBinding<'ra>,
builtin_types_bindings: FxHashMap<Symbol, NameBinding<'ra>>,
@ -1595,6 +1600,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
glob_map: Default::default(),
used_imports: FxHashSet::default(),
maybe_unused_trait_imports: Default::default(),
inaccessible_ctor_reexport: Default::default(),
arenas,
dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT),

View file

@ -112,7 +112,8 @@ impl Nanoseconds {
pub const ZERO: Self = unsafe { Nanoseconds::new_unchecked(0) };
}
impl Default for Nanoseconds {
#[rustc_const_unstable(feature = "const_default", issue = "143894")]
impl const Default for Nanoseconds {
#[inline]
fn default() -> Self {
Self::ZERO

View file

@ -8,8 +8,8 @@ use crate::core::build_steps::compile::{
};
use crate::core::build_steps::tool;
use crate::core::build_steps::tool::{
COMPILETEST_ALLOW_FEATURES, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode,
get_tool_target_compiler, prepare_tool_cargo,
SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode, get_tool_target_compiler,
prepare_tool_cargo,
};
use crate::core::builder::{
self, Alias, Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,
@ -654,7 +654,7 @@ macro_rules! tool_check_step {
// The part of this path after the final '/' is also used as a display name.
path: $path:literal
$(, alt_path: $alt_path:literal )*
// Closure that returns `Mode` based on the passed `&Builder<'_>`
// `Mode` to use when checking this tool
, mode: $mode:expr
// Subset of nightly features that are allowed to be used when checking
$(, allow_features: $allow_features:expr )?
@ -682,8 +682,7 @@ macro_rules! tool_check_step {
fn make_run(run: RunConfig<'_>) {
let target = run.target;
let builder = run.builder;
let mode = $mode(builder);
let mode: Mode = $mode;
let compiler = prepare_compiler_for_check(run.builder, target, mode);
@ -704,7 +703,7 @@ macro_rules! tool_check_step {
_value
};
let extra_features: &[&str] = &[$($($enable_features),*)?];
let mode = $mode(builder);
let mode: Mode = $mode;
run_tool_check_step(builder, compiler, target, $path, mode, allow_features, extra_features);
}
@ -767,57 +766,50 @@ fn run_tool_check_step(
tool_check_step!(Rustdoc {
path: "src/tools/rustdoc",
alt_path: "src/librustdoc",
mode: |_builder| Mode::ToolRustcPrivate
mode: Mode::ToolRustcPrivate
});
// Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead
// of a submodule. Since the SourceType only drives the deny-warnings
// behavior, treat it as in-tree so that any new warnings in clippy will be
// rejected.
tool_check_step!(Clippy { path: "src/tools/clippy", mode: |_builder| Mode::ToolRustcPrivate });
tool_check_step!(Miri { path: "src/tools/miri", mode: |_builder| Mode::ToolRustcPrivate });
tool_check_step!(CargoMiri {
path: "src/tools/miri/cargo-miri",
mode: |_builder| Mode::ToolRustcPrivate
});
tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: |_builder| Mode::ToolRustcPrivate });
tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustcPrivate });
tool_check_step!(Miri { path: "src/tools/miri", mode: Mode::ToolRustcPrivate });
tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustcPrivate });
tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustcPrivate });
tool_check_step!(RustAnalyzer {
path: "src/tools/rust-analyzer",
mode: |_builder| Mode::ToolRustcPrivate,
mode: Mode::ToolRustcPrivate,
allow_features: tool::RustAnalyzer::ALLOW_FEATURES,
enable_features: ["in-rust-tree"],
});
tool_check_step!(MiroptTestTools {
path: "src/tools/miropt-test-tools",
mode: |_builder| Mode::ToolBootstrap
mode: Mode::ToolBootstrap
});
// We want to test the local std
tool_check_step!(TestFloatParse {
path: "src/tools/test-float-parse",
mode: |_builder| Mode::ToolStd,
mode: Mode::ToolStd,
allow_features: TEST_FLOAT_PARSE_ALLOW_FEATURES
});
tool_check_step!(FeaturesStatusDump {
path: "src/tools/features-status-dump",
mode: |_builder| Mode::ToolBootstrap
mode: Mode::ToolBootstrap
});
tool_check_step!(Bootstrap {
path: "src/bootstrap",
mode: |_builder| Mode::ToolBootstrap,
default: false
});
tool_check_step!(Bootstrap { path: "src/bootstrap", mode: Mode::ToolBootstrap, default: false });
// `run-make-support` will be built as part of suitable run-make compiletest test steps, but support
// check to make it easier to work on.
tool_check_step!(RunMakeSupport {
path: "src/tools/run-make-support",
mode: |_builder| Mode::ToolBootstrap,
mode: Mode::ToolBootstrap,
default: false
});
tool_check_step!(CoverageDump {
path: "src/tools/coverage-dump",
mode: |_builder| Mode::ToolBootstrap,
mode: Mode::ToolBootstrap,
default: false
});
@ -825,23 +817,18 @@ tool_check_step!(CoverageDump {
// so this is mainly for people working on compiletest to run locally.
tool_check_step!(Compiletest {
path: "src/tools/compiletest",
mode: |builder: &Builder<'_>| if builder.config.compiletest_use_stage0_libtest {
Mode::ToolBootstrap
} else {
Mode::ToolStd
},
allow_features: COMPILETEST_ALLOW_FEATURES,
mode: Mode::ToolBootstrap,
default: false,
});
tool_check_step!(Linkchecker {
path: "src/tools/linkchecker",
mode: |_builder| Mode::ToolBootstrap,
mode: Mode::ToolBootstrap,
default: false
});
tool_check_step!(BumpStage0 {
path: "src/tools/bump-stage0",
mode: |_builder| Mode::ToolBootstrap,
mode: Mode::ToolBootstrap,
default: false
});

View file

@ -18,8 +18,8 @@ use crate::core::build_steps::llvm::get_llvm_version;
use crate::core::build_steps::run::get_completion_paths;
use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
use crate::core::build_steps::tool::{
self, COMPILETEST_ALLOW_FEATURES, RustcPrivateCompilers, SourceType,
TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool, ToolTargetBuildMode, get_tool_target_compiler,
self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool,
ToolTargetBuildMode, get_tool_target_compiler,
};
use crate::core::build_steps::toolstate::ToolState;
use crate::core::build_steps::{compile, dist, llvm};
@ -36,7 +36,7 @@ use crate::utils::helpers::{
linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date,
};
use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, debug, envify};
use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, envify};
const ADB_TEST_DIR: &str = "/data/local/tmp/work";
@ -786,26 +786,26 @@ impl Step for CompiletestTest {
fn run(self, builder: &Builder<'_>) {
let host = self.host;
// Now that compiletest uses only stable Rust, building it always uses
// the stage 0 compiler. However, some of its unit tests need to be able
// to query information from an in-tree compiler, so we treat `--stage`
// as selecting the stage of that secondary compiler.
if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
eprintln!("\
ERROR: `--stage 0` runs compiletest self-tests against the stage0 (precompiled) compiler, not the in-tree compiler, and will almost always cause tests to fail
ERROR: `--stage 0` causes compiletest to query information from the stage0 (precompiled) compiler, instead of the in-tree compiler, which can cause some tests to fail inappropriately
NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`."
);
crate::exit!(1);
}
let compiler = builder.compiler(builder.top_stage, host);
debug!(?compiler);
let bootstrap_compiler = builder.compiler(0, host);
let staged_compiler = builder.compiler(builder.top_stage, host);
// We need `ToolStd` for the locally-built sysroot because
// compiletest uses unstable features of the `test` crate.
builder.std(compiler, host);
let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
// compiletest uses libtest internals; make it use the in-tree std to make sure it never
// breaks when std sources change.
Mode::ToolStd,
bootstrap_compiler,
Mode::ToolBootstrap,
host,
Kind::Test,
"src/tools/compiletest",
@ -816,9 +816,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
// Used for `compiletest` self-tests to have the path to the *staged* compiler. Getting this
// right is important, as `compiletest` is intended to only support one target spec JSON
// format, namely that of the staged compiler.
cargo.env("TEST_RUSTC", builder.rustc(compiler));
cargo.env("TEST_RUSTC", builder.rustc(staged_compiler));
cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);
}
}

View file

@ -380,7 +380,6 @@ macro_rules! bootstrap_tool {
($(
$name:ident, $path:expr, $tool_name:expr
$(,is_external_tool = $external:expr)*
$(,is_unstable_tool = $unstable:expr)*
$(,allow_features = $allow_features:expr)?
$(,submodules = $submodules:expr)?
$(,artifact_kind = $artifact_kind:expr)?
@ -438,19 +437,11 @@ macro_rules! bootstrap_tool {
}
)*
let is_unstable = false $(|| $unstable)*;
let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest;
builder.ensure(ToolBuild {
build_compiler: self.compiler,
target: self.target,
tool: $tool_name,
mode: if is_unstable && !compiletest_wants_stage0 {
// use in-tree libraries for unstable features
Mode::ToolStd
} else {
Mode::ToolBootstrap
},
mode: Mode::ToolBootstrap,
path: $path,
source_type: if false $(|| $external)* {
SourceType::Submodule
@ -483,8 +474,6 @@ macro_rules! bootstrap_tool {
}
}
pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "internal_output_capture";
bootstrap_tool!(
// This is marked as an external tool because it includes dependencies
// from submodules. Trying to keep the lints in sync between all the repos
@ -495,7 +484,7 @@ bootstrap_tool!(
Tidy, "src/tools/tidy", "tidy";
Linkchecker, "src/tools/linkchecker", "linkchecker";
CargoTest, "src/tools/cargotest", "cargotest";
Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
Compiletest, "src/tools/compiletest", "compiletest";
BuildManifest, "src/tools/build-manifest", "build-manifest";
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
RustInstaller, "src/tools/rust-installer", "rust-installer";
@ -509,8 +498,7 @@ bootstrap_tool!(
CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata";
GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
// rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features.
RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test";
CoverageDump, "src/tools/coverage-dump", "coverage-dump";
UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator";
FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump";

View file

@ -2004,21 +2004,6 @@ mod snapshot {
.render_steps(), @"[check] rustc 0 <host> -> Compiletest 1 <host>");
}
#[test]
fn check_compiletest_stage1_libtest() {
let ctx = TestCtx::new();
insta::assert_snapshot!(
ctx.config("check")
.path("compiletest")
.args(&["--set", "build.compiletest-use-stage0-libtest=false"])
.render_steps(), @r"
[build] llvm <host>
[build] rustc 0 <host> -> rustc 1 <host>
[build] rustc 1 <host> -> std 1 <host>
[check] rustc 1 <host> -> Compiletest 2 <host>
");
}
#[test]
fn check_codegen() {
let ctx = TestCtx::new();
@ -2145,6 +2130,17 @@ mod snapshot {
");
}
#[test]
fn test_compiletest_self_test() {
let ctx = TestCtx::new();
let steps = ctx.config("test").arg("compiletest").render_steps();
insta::assert_snapshot!(steps, @r"
[build] llvm <host>
[build] rustc 0 <host> -> rustc 1 <host>
[build] rustdoc 0 <host>
");
}
#[test]
fn test_compiletest_suites_stage1() {
let ctx = TestCtx::new();

View file

@ -310,9 +310,6 @@ pub struct Config {
/// sources.
pub compiletest_allow_stage0: bool,
/// Whether to use the precompiled stage0 libtest with compiletest.
pub compiletest_use_stage0_libtest: bool,
/// Default value for `--extra-checks`
pub tidy_extra_checks: Option<String>,
pub is_running_on_ci: bool,
@ -497,7 +494,8 @@ impl Config {
optimized_compiler_builtins: build_optimized_compiler_builtins,
jobs: build_jobs,
compiletest_diff_tool: build_compiletest_diff_tool,
compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest,
// No longer has any effect; kept (for now) to avoid breaking people's configs.
compiletest_use_stage0_libtest: _,
tidy_extra_checks: build_tidy_extra_checks,
ccache: build_ccache,
exclude: build_exclude,
@ -1197,7 +1195,6 @@ impl Config {
compiler_docs: build_compiler_docs.unwrap_or(false),
compiletest_allow_stage0: build_compiletest_allow_stage0.unwrap_or(false),
compiletest_diff_tool: build_compiletest_diff_tool,
compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest.unwrap_or(true),
config: toml_path,
configure_args: build_configure_args.unwrap_or_default(),
control_flow_guard: rust_control_flow_guard.unwrap_or(false),

View file

@ -47,11 +47,17 @@ use crate::str::FromStr;
#[macro_export]
macro_rules! define_config {
($(#[$attr:meta])* struct $name:ident {
$($field:ident: Option<$field_ty:ty> = $field_key:literal,)*
$(
$(#[$field_attr:meta])*
$field:ident: Option<$field_ty:ty> = $field_key:literal,
)*
}) => {
$(#[$attr])*
pub struct $name {
$(pub $field: Option<$field_ty>,)*
$(
$(#[$field_attr])*
pub $field: Option<$field_ty>,
)*
}
impl Merge for $name {

View file

@ -70,6 +70,8 @@ define_config! {
jobs: Option<u32> = "jobs",
compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
compiletest_allow_stage0: Option<bool> = "compiletest-allow-stage0",
/// No longer has any effect; kept (for now) to avoid breaking people's configs.
/// FIXME(#146929): Remove this in 2026.
compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest",
tidy_extra_checks: Option<String> = "tidy-extra-checks",
ccache: Option<StringOrBool> = "ccache",

View file

@ -327,8 +327,8 @@ pub enum Mode {
ToolTarget,
/// Build a tool which uses the locally built std, placing output in the
/// "stageN-tools" directory. Its usage is quite rare, mainly used by
/// compiletest which needs libtest.
/// "stageN-tools" directory. Its usage is quite rare; historically it was
/// needed by compiletest, but now it is mainly used by `test-float-parse`.
ToolStd,
/// Build a tool which uses the `rustc_private` mechanism, and thus

View file

@ -557,8 +557,13 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
summary: "New option `build.windows-rc` that will override which resource compiler on Windows will be used to compile Rust.",
},
ChangeInfo {
change_id: 99999,
change_id: 147046,
severity: ChangeSeverity::Warning,
summary: "The `rust.use-lld` option has been renamed to `rust.bootstrap-override-lld`. Note that it only serves for overriding the linker used when building Rust code in bootstrap to be LLD.",
},
ChangeInfo {
change_id: 146929,
severity: ChangeSeverity::Info,
summary: "`compiletest` is now always built with the stage 0 compiler, so `build.compiletest-use-stage0-libtest` has no effect.",
},
];

View file

@ -661,18 +661,10 @@ pub struct Config {
pub builtin_cfg_names: OnceLock<HashSet<String>>,
pub supported_crate_types: OnceLock<HashSet<String>>,
/// FIXME: this is why we still need to depend on *staged* `std`, it's because we currently rely
/// on `#![feature(internal_output_capture)]` for [`std::io::set_output_capture`] to implement
/// `libtest`-esque `--no-capture`.
///
/// FIXME: rename this to the more canonical `no_capture`, or better, invert this to `capture`
/// to avoid `!nocapture` double-negatives.
pub nocapture: bool,
/// True if the experimental new output-capture implementation should be
/// used, avoiding the need for `#![feature(internal_output_capture)]`.
pub new_output_capture: bool,
/// Needed both to construct [`build_helper::git::GitConfig`].
pub nightly_branch: String,
pub git_merge_commit_email: String,
@ -790,7 +782,6 @@ impl Config {
builtin_cfg_names: Default::default(),
supported_crate_types: Default::default(),
nocapture: Default::default(),
new_output_capture: Default::default(),
nightly_branch: Default::default(),
git_merge_commit_email: Default::default(),
profiler_runtime: Default::default(),

View file

@ -9,8 +9,8 @@ use std::borrow::Cow;
use std::collections::HashMap;
use std::hash::{BuildHasherDefault, DefaultHasher};
use std::num::NonZero;
use std::sync::{Arc, Mutex, mpsc};
use std::{env, hint, io, mem, panic, thread};
use std::sync::{Arc, mpsc};
use std::{env, hint, mem, panic, thread};
use camino::Utf8PathBuf;
@ -130,10 +130,6 @@ fn run_test_inner(
panic_hook::set_capture_buf(Default::default());
}
if let CaptureKind::Old { ref buf } = capture {
io::set_output_capture(Some(Arc::clone(buf)));
}
let stdout = capture.stdout();
let stderr = capture.stderr();
@ -144,9 +140,6 @@ fn run_test_inner(
// Forward any captured panic message to (captured) stderr.
write!(stderr, "{panic_buf}");
}
if matches!(capture, CaptureKind::Old { .. }) {
io::set_output_capture(None);
}
let outcome = match (should_panic, panic_payload) {
(ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded,
@ -167,31 +160,24 @@ enum CaptureKind {
/// runners, whose output is always captured.)
None,
/// Use the old output-capture implementation, which relies on the unstable
/// library feature `#![feature(internal_output_capture)]`.
Old { buf: Arc<Mutex<Vec<u8>>> },
/// Use the new output-capture implementation, which only uses stable Rust.
New { buf: output_capture::CaptureBuf },
/// Capture all console output that would be printed by test runners via
/// their `stdout` and `stderr` trait objects, or via the custom panic hook.
Capture { buf: output_capture::CaptureBuf },
}
impl CaptureKind {
fn for_config(config: &Config) -> Self {
if config.nocapture {
Self::None
} else if config.new_output_capture {
Self::New { buf: output_capture::CaptureBuf::new() }
} else {
// Create a capure buffer for `io::set_output_capture`.
Self::Old { buf: Default::default() }
Self::Capture { buf: output_capture::CaptureBuf::new() }
}
}
fn should_set_panic_hook(&self) -> bool {
match self {
Self::None => false,
Self::Old { .. } => true,
Self::New { .. } => true,
Self::Capture { .. } => true,
}
}
@ -205,16 +191,15 @@ impl CaptureKind {
fn capture_buf_or<'a>(&'a self, fallback: &'a dyn ConsoleOut) -> &'a dyn ConsoleOut {
match self {
Self::None | Self::Old { .. } => fallback,
Self::New { buf } => buf,
Self::None => fallback,
Self::Capture { buf } => buf,
}
}
fn into_inner(self) -> Option<Vec<u8>> {
match self {
Self::None => None,
Self::Old { buf } => Some(buf.lock().unwrap_or_else(|e| e.into_inner()).to_vec()),
Self::New { buf } => Some(buf.into_inner().into()),
Self::Capture { buf } => Some(buf.into_inner().into()),
}
}
}

View file

@ -1,9 +1,4 @@
#![crate_name = "compiletest"]
// Needed by the "new" test executor that does not depend on libtest.
// FIXME(Zalathar): We should be able to get rid of `internal_output_capture`,
// by having `runtest` manually capture all of its println-like output instead.
// That would result in compiletest being written entirely in stable Rust!
#![feature(internal_output_capture)]
#[cfg(test)]
mod tests;
@ -178,12 +173,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
// FIXME: Temporarily retained so we can point users to `--no-capture`
.optflag("", "nocapture", "")
.optflag("", "no-capture", "don't capture stdout/stderr of tests")
.optopt(
"N",
"new-output-capture",
"enables or disables the new output-capture implementation",
"off|on",
)
.optflag("", "profiler-runtime", "is the profiler runtime enabled for this target")
.optflag("h", "help", "show this message")
.reqopt("", "channel", "current Rust channel", "CHANNEL")
@ -480,14 +469,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
supported_crate_types: OnceLock::new(),
nocapture: matches.opt_present("no-capture"),
new_output_capture: {
let value = matches
.opt_str("new-output-capture")
.or_else(|| env::var("COMPILETEST_NEW_OUTPUT_CAPTURE").ok())
.unwrap_or_else(|| "on".to_owned());
parse_bool_option(&value)
.unwrap_or_else(|| panic!("unknown `--new-output-capture` value `{value}` given"))
},
nightly_branch: matches.opt_str("nightly-branch").unwrap(),
git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
@ -503,19 +484,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
}
}
/// Parses the same set of boolean values accepted by rustc command-line arguments.
///
/// Accepting all of these values is more complicated than just picking one
/// pair, but has the advantage that contributors who are used to rustc
/// shouldn't have to think about which values are legal.
fn parse_bool_option(value: &str) -> Option<bool> {
match value {
"off" | "no" | "n" | "false" => Some(false),
"on" | "yes" | "y" | "true" => Some(true),
_ => None,
}
}
pub fn opt_str(maybestr: &Option<String>) -> &str {
match *maybestr {
None => "(none)",

View file

@ -1,5 +1,5 @@
//@ known-bug: rust-lang/rust#125772
//@ only-x86_64
//@ only-64bit
#![feature(generic_const_exprs)]
struct Outer<const A: i64, const B: i64>();

View file

@ -1,13 +0,0 @@
//@ known-bug: rust-lang/rust#129095
//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir
#![feature(adt_const_params, unsized_const_params)]
#![allow(incomplete_features)]
pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
BYTES
}
pub fn main() {
assert_eq!(function_with_bytes::<b"AAAAA">(), &[0x41, 0x41, 0x41, 0x41]);
}

View file

@ -1,5 +1,5 @@
//@ known-bug: #131292
//@ only-x86_64
//@ needs-asm-support
use std::arch::asm;
unsafe fn f6() {

View file

@ -1,17 +0,0 @@
//@ known-bug: #134175
//@compile-flags: -Zvalidate-mir -Zinline-mir=yes
use std::vec::IntoIter;
pub(crate) trait Foo: Iterator<Item = <Self as Foo>::Key> {
type Key;
}
impl Foo for IntoIter<i16> {}
fn sum_foo<F: Foo<Key = i32>>(f: F) -> i32 {
f.fold(0, |a, b| a + b)
}
fn main() {
let x = sum_foo(vec![11, 10, 1].into_iter());
}

View file

@ -1,15 +0,0 @@
//@ known-bug: #134654
//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir
//@ only-x86_64
#![feature(adt_const_params, unsized_const_params)]
#![allow(incomplete_features)]
fn function_with_bytes<const BYTES:
&'static [u8; 0xa9008fb6c9d81e42_0e25730562a601c8_u128]>() -> &'static [u8] {
BYTES
}
fn main() {
function_with_bytes::<b"aa">() == &[];
}

View file

@ -1,15 +0,0 @@
//@ known-bug: #135570
//@compile-flags: -Zvalidate-mir -Zmir-enable-passes=+Inline -Copt-level=0 -Zmir-enable-passes=+GVN
//@ only-x86_64
#![feature(adt_const_params, unsized_const_params)]
#![allow(incomplete_features)]
fn function_with_bytes<const BYTES: &'static [u8; 0xc7b889180b67b07d_bc1a3c88783d35b5_u128]>(
) -> &'static [u8] {
BYTES
}
fn main() {
function_with_bytes::<b"aa">() == &[];
}

View file

@ -1,18 +0,0 @@
//@ known-bug: #136381
//@ compile-flags: -Zvalidate-mir -Zmir-enable-passes=+GVN
#![feature(trait_upcasting)]
trait A {}
trait B: A {
fn c(&self);
}
impl B for i32 {
fn c(self) {
todo!();
}
}
fn main() {
let baz: &dyn B = &1;
let bar: &dyn A = baz;
}

View file

@ -1,10 +0,0 @@
//@ known-bug: #137190
//@ compile-flags: -Zmir-opt-level=2 -Zvalidate-mir
trait A {
fn b(&self);
}
trait C: A {}
impl C for () {}
fn main() {
(&() as &dyn C as &dyn A).b();
}

View file

@ -1,16 +0,0 @@
//@ known-bug: #137468
//@ compile-flags: -Copt-level=0 -Zmir-enable-passes=+GVN -Zvalidate-mir
trait Supertrait<T> {}
trait Identity {
type Selff;
}
trait Trait<P>: Supertrait<()> + Supertrait<<P as Identity>::Selff> {}
impl<P> Trait<P> for () {}
fn main() {
let x: &dyn Trait<()> = &();
let x: &dyn Supertrait<()> = x;
}

View file

@ -1,6 +1,6 @@
//@ compile-flags: -g -Copt-level=0 -Z verify-llvm-ir
//@ known-bug: #34127
//@ only-x86_64
//@ only-64bit
pub fn main() {
let _a = [(); 1 << 63];

View file

@ -33,6 +33,10 @@ impl CodegenBackend for TheBackend {
""
}
fn name(&self) -> &'static str {
"the-backend"
}
fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box<dyn Any> {
Box::new(CodegenResults {
modules: vec![],

30
tests/ui/keyword/soup.rs Normal file
View file

@ -0,0 +1,30 @@
//@ edition:2024
//@ check-pass
#![allow(unused_imports)]
#![allow(missing_abi)]
#![allow(unused_macros)]
#![allow(non_camel_case_types)]
#![allow(unreachable_code)]
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(unused_must_use)]
// all 48 keywords in 300 characters
mod x {
pub(super) struct X;
use Ok;
impl X {
pub(in crate) async fn x(self: Self, x: &'static &'_ dyn for<> Fn()) where {
unsafe extern { safe fn x(); }
macro_rules! x { () => {}; }
if 'x: loop {
return match while let true = break 'x false { continue } {
ref x => { &raw mut x; async { const { enum A {} } }.await as () },
};
} { type x = X; } else { move || { trait x { } union B { x: () } }; }
}
}
}
fn main() {}

View file

@ -0,0 +1,20 @@
#![allow(dead_code, unused_variables)]
//@ run-rustfix
pub use my_mod::Foo;
//~^ NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields
//~| NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields
mod my_mod {
pub struct Foo(u32);
mod my_sub_mod {
fn my_func() {
let crate::my_mod::Foo(x) = crate::my_mod::Foo(42);
//~^ ERROR cannot initialize a tuple struct which contains private fields
//~| HELP the type can be constructed directly, because its fields are available from the current scope
//~| ERROR cannot match against a tuple struct which contains private fields
//~| HELP the type can be constructed directly, because its fields are available from the current scope
}
}
}
fn main() {}

View file

@ -0,0 +1,20 @@
#![allow(dead_code, unused_variables)]
//@ run-rustfix
pub use my_mod::Foo;
//~^ NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields
//~| NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields
mod my_mod {
pub struct Foo(u32);
mod my_sub_mod {
fn my_func() {
let crate::Foo(x) = crate::Foo(42);
//~^ ERROR cannot initialize a tuple struct which contains private fields
//~| HELP the type can be constructed directly, because its fields are available from the current scope
//~| ERROR cannot match against a tuple struct which contains private fields
//~| HELP the type can be constructed directly, because its fields are available from the current scope
}
}
}
fn main() {}

View file

@ -0,0 +1,36 @@
error[E0423]: cannot initialize a tuple struct which contains private fields
--> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:12:33
|
LL | let crate::Foo(x) = crate::Foo(42);
| ^^^^^^^^^^
|
note: the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields
--> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:3:9
|
LL | pub use my_mod::Foo;
| ^^^^^^^^^^^
help: the type can be constructed directly, because its fields are available from the current scope
|
LL | let crate::Foo(x) = crate::my_mod::Foo(42);
| ++++++++
error[E0532]: cannot match against a tuple struct which contains private fields
--> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:12:17
|
LL | let crate::Foo(x) = crate::Foo(42);
| ^^^^^^^^^^
|
note: the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields
--> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:3:9
|
LL | pub use my_mod::Foo;
| ^^^^^^^^^^^
help: the type can be constructed directly, because its fields are available from the current scope
|
LL | let crate::my_mod::Foo(x) = crate::Foo(42);
| ++++++++
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0423, E0532.
For more information about an error, try `rustc --explain E0423`.