Auto merge of #125463 - GuillaumeGomez:rollup-287wx4y, r=GuillaumeGomez

Rollup of 6 pull requests

Successful merges:

 - #125263 (rust-lld: fallback to rustc's sysroot if there's no path to the linker in the target sysroot)
 - #125345 (rustc_codegen_llvm: add support for writing summary bitcode)
 - #125362 (Actually use TAIT instead of emulating it)
 - #125412 (Don't suggest adding the unexpected cfgs to the build-script it-self)
 - #125445 (Migrate `run-make/rustdoc-with-short-out-dir-option` to `rmake.rs`)
 - #125452 (Cleanup check-cfg handling in core and std)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-05-24 03:04:06 +00:00
commit 7601adcc76
32 changed files with 335 additions and 187 deletions

View File

@ -200,7 +200,7 @@ fn produce_final_output_artifacts(
// to get rid of it.
for output_type in crate_output.outputs.keys() {
match *output_type {
OutputType::Bitcode => {
OutputType::Bitcode | OutputType::ThinLinkBitcode => {
// Cranelift doesn't have bitcode
// user_wants_bitcode = true;
// // Copy to .bc, but always keep the .0.bc. There is a later

View File

@ -335,6 +335,10 @@ impl ThinBufferMethods for ThinBuffer {
fn data(&self) -> &[u8] {
unimplemented!();
}
fn thin_link_data(&self) -> &[u8] {
unimplemented!();
}
}
pub struct GccContext {
@ -414,7 +418,7 @@ impl WriteBackendMethods for GccCodegenBackend {
back::write::codegen(cgcx, dcx, module, config)
}
fn prepare_thin(_module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
fn prepare_thin(_module: ModuleCodegen<Self::Module>, _emit_summary: bool) -> (String, Self::ThinBuffer) {
unimplemented!();
}

View File

@ -230,9 +230,12 @@ pub(crate) fn run_thin(
thin_lto(cgcx, &dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold)
}
pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBuffer) {
pub(crate) fn prepare_thin(
module: ModuleCodegen<ModuleLlvm>,
emit_summary: bool,
) -> (String, ThinBuffer) {
let name = module.name;
let buffer = ThinBuffer::new(module.module_llvm.llmod(), true);
let buffer = ThinBuffer::new(module.module_llvm.llmod(), true, emit_summary);
(name, buffer)
}
@ -672,9 +675,9 @@ unsafe impl Send for ThinBuffer {}
unsafe impl Sync for ThinBuffer {}
impl ThinBuffer {
pub fn new(m: &llvm::Module, is_thin: bool) -> ThinBuffer {
pub fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer {
unsafe {
let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin);
let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin, emit_summary);
ThinBuffer(buffer)
}
}
@ -688,6 +691,14 @@ impl ThinBufferMethods for ThinBuffer {
slice::from_raw_parts(ptr, len)
}
}
fn thin_link_data(&self) -> &[u8] {
unsafe {
let ptr = llvm::LLVMRustThinLTOBufferThinLinkDataPtr(self.0) as *const _;
let len = llvm::LLVMRustThinLTOBufferThinLinkDataLen(self.0);
slice::from_raw_parts(ptr, len)
}
}
}
impl Drop for ThinBuffer {

View File

@ -709,13 +709,15 @@ pub(crate) unsafe fn codegen(
// asm from LLVM and use `gcc` to create the object file.
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
let bc_summary_out =
cgcx.output_filenames.temp_path(OutputType::ThinLinkBitcode, module_name);
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
if config.bitcode_needed() {
let _timer = cgcx
.prof
.generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name);
let thin = ThinBuffer::new(llmod, config.emit_thin_lto);
let thin = ThinBuffer::new(llmod, config.emit_thin_lto, config.emit_thin_lto_summary);
let data = thin.data();
if let Some(bitcode_filename) = bc_out.file_name() {
@ -726,6 +728,25 @@ pub(crate) unsafe fn codegen(
);
}
if config.emit_thin_lto_summary
&& let Some(thin_link_bitcode_filename) = bc_summary_out.file_name()
{
let summary_data = thin.thin_link_data();
cgcx.prof.artifact_size(
"llvm_bitcode_summary",
thin_link_bitcode_filename.to_string_lossy(),
summary_data.len() as u64,
);
let _timer = cgcx.prof.generic_activity_with_arg(
"LLVM_module_codegen_emit_bitcode_summary",
&*module.name,
);
if let Err(err) = fs::write(&bc_summary_out, summary_data) {
dcx.emit_err(WriteBytecode { path: &bc_summary_out, err });
}
}
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
let _timer = cgcx
.prof

View File

@ -237,8 +237,11 @@ impl WriteBackendMethods for LlvmCodegenBackend {
) -> Result<CompiledModule, FatalError> {
back::write::codegen(cgcx, dcx, module, config)
}
fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
back::lto::prepare_thin(module)
fn prepare_thin(
module: ModuleCodegen<Self::Module>,
emit_summary: bool,
) -> (String, Self::ThinBuffer) {
back::lto::prepare_thin(module, emit_summary)
}
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
(module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))

View File

@ -2350,10 +2350,16 @@ extern "C" {
#[allow(improper_ctypes)]
pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString);
pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool) -> &'static mut ThinLTOBuffer;
pub fn LLVMRustThinLTOBufferCreate(
M: &Module,
is_thin: bool,
emit_summary: bool,
) -> &'static mut ThinLTOBuffer;
pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer);
pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char;
pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t;
pub fn LLVMRustThinLTOBufferThinLinkDataPtr(M: &ThinLTOBuffer) -> *const c_char;
pub fn LLVMRustThinLTOBufferThinLinkDataLen(M: &ThinLTOBuffer) -> size_t;
pub fn LLVMRustCreateThinLTOData(
Modules: *const ThinLTOModule,
NumModules: c_uint,

View File

@ -212,6 +212,8 @@ codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, fo
codegen_ssa_select_cpp_build_tool_workload = in the Visual Studio installer, ensure the "C++ build tools" workload is selected
codegen_ssa_self_contained_linker_missing = the self-contained linker was requested, but it wasn't found in the target's sysroot, or in rustc's sysroot
codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time
codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link

View File

@ -3141,13 +3141,21 @@ fn add_lld_args(
let self_contained_linker = self_contained_cli || self_contained_target;
if self_contained_linker && !sess.opts.cg.link_self_contained.is_linker_disabled() {
let mut linker_path_exists = false;
for path in sess.get_tools_search_paths(false) {
let linker_path = path.join("gcc-ld");
linker_path_exists |= linker_path.exists();
cmd.arg({
let mut arg = OsString::from("-B");
arg.push(path.join("gcc-ld"));
arg.push(linker_path);
arg
});
}
if !linker_path_exists {
// As a sanity check, we emit an error if none of these paths exist: we want
// self-contained linking and have no linker.
sess.dcx().emit_fatal(errors::SelfContainedLinkerMissing);
}
}
// 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of

View File

@ -108,6 +108,7 @@ pub struct ModuleConfig {
pub emit_asm: bool,
pub emit_obj: EmitObj,
pub emit_thin_lto: bool,
pub emit_thin_lto_summary: bool,
pub bc_cmdline: String,
// Miscellaneous flags. These are mostly copied from command-line
@ -232,6 +233,10 @@ impl ModuleConfig {
),
emit_obj,
emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto,
emit_thin_lto_summary: if_regular!(
sess.opts.output_types.contains_key(&OutputType::ThinLinkBitcode),
false
),
bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(),
verify_llvm_ir: sess.verify_llvm_ir(),
@ -283,6 +288,7 @@ impl ModuleConfig {
pub fn bitcode_needed(&self) -> bool {
self.emit_bc
|| self.emit_thin_lto_summary
|| self.emit_obj == EmitObj::Bitcode
|| self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full)
}
@ -630,6 +636,9 @@ fn produce_final_output_artifacts(
// them for making an rlib.
copy_if_one_unit(OutputType::Bitcode, true);
}
OutputType::ThinLinkBitcode => {
copy_if_one_unit(OutputType::ThinLinkBitcode, false);
}
OutputType::LlvmAssembly => {
copy_if_one_unit(OutputType::LlvmAssembly, false);
}
@ -883,7 +892,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
match lto_type {
ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config),
ComputedLtoType::Thin => {
let (name, thin_buffer) = B::prepare_thin(module);
let (name, thin_buffer) = B::prepare_thin(module, false);
if let Some(path) = bitcode {
fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| {
panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);

View File

@ -413,6 +413,10 @@ pub struct UnableToExeLinker {
#[diag(codegen_ssa_msvc_missing_linker)]
pub struct MsvcMissingLinker;
#[derive(Diagnostic)]
#[diag(codegen_ssa_self_contained_linker_missing)]
pub struct SelfContainedLinkerMissing;
#[derive(Diagnostic)]
#[diag(codegen_ssa_check_installed_visual_studio)]
pub struct CheckInstalledVisualStudio;

View File

@ -56,12 +56,16 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
module: ModuleCodegen<Self::Module>,
config: &ModuleConfig,
) -> Result<CompiledModule, FatalError>;
fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer);
fn prepare_thin(
module: ModuleCodegen<Self::Module>,
want_summary: bool,
) -> (String, Self::ThinBuffer);
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
}
pub trait ThinBufferMethods: Send + Sync {
fn data(&self) -> &[u8];
fn thin_link_data(&self) -> &[u8];
}
pub trait ModuleBufferMethods: Send + Sync {

View File

@ -42,6 +42,22 @@ fn to_check_cfg_arg(name: Symbol, value: Option<Symbol>, quotes: EscapeQuotes) -
}
}
fn cargo_help_sub(
sess: &Session,
inst: &impl Fn(EscapeQuotes) -> String,
) -> lints::UnexpectedCfgCargoHelp {
// We don't want to suggest the `build.rs` way to expected cfgs if we are already in a
// `build.rs`. We therefor do a best effort check (looking if the `--crate-name` is
// `build_script_build`) to try to figure out if we are building a Cargo build script
let unescaped = &inst(EscapeQuotes::No);
if matches!(&sess.opts.crate_name, Some(crate_name) if crate_name == "build_script_build") {
lints::UnexpectedCfgCargoHelp::lint_cfg(unescaped)
} else {
lints::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes))
}
}
pub(super) fn unexpected_cfg_name(
sess: &Session,
(name, name_span): (Symbol, Span),
@ -162,14 +178,7 @@ pub(super) fn unexpected_cfg_name(
let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes);
let invocation_help = if is_from_cargo {
let sub = if !is_feature_cfg {
Some(lints::UnexpectedCfgCargoHelp::new(
&inst(EscapeQuotes::No),
&inst(EscapeQuotes::Yes),
))
} else {
None
};
let sub = if !is_feature_cfg { Some(cargo_help_sub(sess, &inst)) } else { None };
lints::unexpected_cfg_name::InvocationHelp::Cargo { sub }
} else {
lints::unexpected_cfg_name::InvocationHelp::Rustc(lints::UnexpectedCfgRustcHelp::new(
@ -267,10 +276,7 @@ pub(super) fn unexpected_cfg_value(
Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures)
}
} else if !is_cfg_a_well_know_name {
Some(lints::unexpected_cfg_value::CargoHelp::Other(lints::UnexpectedCfgCargoHelp::new(
&inst(EscapeQuotes::No),
&inst(EscapeQuotes::Yes),
)))
Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
} else {
None
};

View File

@ -1962,21 +1962,33 @@ pub struct UnitBindingsDiag {
pub struct BuiltinNamedAsmLabel;
#[derive(Subdiagnostic)]
#[help(lint_unexpected_cfg_add_cargo_feature)]
#[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)]
#[help(lint_unexpected_cfg_add_build_rs_println)]
pub struct UnexpectedCfgCargoHelp {
pub build_rs_println: String,
pub cargo_toml_lint_cfg: String,
pub enum UnexpectedCfgCargoHelp {
#[help(lint_unexpected_cfg_add_cargo_feature)]
#[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)]
LintCfg { cargo_toml_lint_cfg: String },
#[help(lint_unexpected_cfg_add_cargo_feature)]
#[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)]
#[help(lint_unexpected_cfg_add_build_rs_println)]
LintCfgAndBuildRs { cargo_toml_lint_cfg: String, build_rs_println: String },
}
impl UnexpectedCfgCargoHelp {
pub fn new(unescaped: &str, escaped: &str) -> Self {
Self {
cargo_toml_lint_cfg: format!(
"\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}",
),
build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");",),
fn cargo_toml_lint_cfg(unescaped: &str) -> String {
format!(
"\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}"
)
}
pub fn lint_cfg(unescaped: &str) -> Self {
UnexpectedCfgCargoHelp::LintCfg {
cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
}
}
pub fn lint_cfg_and_build_rs(unescaped: &str, escaped: &str) -> Self {
UnexpectedCfgCargoHelp::LintCfgAndBuildRs {
cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");"),
}
}
}

View File

@ -1488,13 +1488,15 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
// a ThinLTO summary attached.
struct LLVMRustThinLTOBuffer {
std::string data;
std::string thin_link_data;
};
extern "C" LLVMRustThinLTOBuffer*
LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) {
auto Ret = std::make_unique<LLVMRustThinLTOBuffer>();
{
auto OS = raw_string_ostream(Ret->data);
auto ThinLinkOS = raw_string_ostream(Ret->thin_link_data);
{
if (is_thin) {
PassBuilder PB;
@ -1508,7 +1510,10 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
PB.registerLoopAnalyses(LAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
ModulePassManager MPM;
MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr));
// We only pass ThinLinkOS to be filled in if we want the summary,
// because otherwise LLVM does extra work and may double-emit some
// errors or warnings.
MPM.addPass(ThinLTOBitcodeWriterPass(OS, emit_summary ? &ThinLinkOS : nullptr));
MPM.run(*unwrap(M), MAM);
} else {
WriteBitcodeToFile(*unwrap(M), OS);
@ -1533,6 +1538,16 @@ LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) {
return Buffer->data.length();
}
extern "C" const void*
LLVMRustThinLTOBufferThinLinkDataPtr(const LLVMRustThinLTOBuffer *Buffer) {
return Buffer->thin_link_data.data();
}
extern "C" size_t
LLVMRustThinLTOBufferThinLinkDataLen(const LLVMRustThinLTOBuffer *Buffer) {
return Buffer->thin_link_data.length();
}
// This is what we used to parse upstream bitcode for actual ThinLTO
// processing. We'll call this once per module optimized through ThinLTO, and
// it'll be called concurrently on many threads.

View File

@ -465,6 +465,7 @@ impl FromStr for SplitDwarfKind {
#[derive(Encodable, Decodable)]
pub enum OutputType {
Bitcode,
ThinLinkBitcode,
Assembly,
LlvmAssembly,
Mir,
@ -492,6 +493,7 @@ impl OutputType {
match *self {
OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
OutputType::Bitcode
| OutputType::ThinLinkBitcode
| OutputType::Assembly
| OutputType::LlvmAssembly
| OutputType::Mir
@ -502,6 +504,7 @@ impl OutputType {
pub fn shorthand(&self) -> &'static str {
match *self {
OutputType::Bitcode => "llvm-bc",
OutputType::ThinLinkBitcode => "thin-link-bitcode",
OutputType::Assembly => "asm",
OutputType::LlvmAssembly => "llvm-ir",
OutputType::Mir => "mir",
@ -518,6 +521,7 @@ impl OutputType {
"llvm-ir" => OutputType::LlvmAssembly,
"mir" => OutputType::Mir,
"llvm-bc" => OutputType::Bitcode,
"thin-link-bitcode" => OutputType::ThinLinkBitcode,
"obj" => OutputType::Object,
"metadata" => OutputType::Metadata,
"link" => OutputType::Exe,
@ -528,8 +532,9 @@ impl OutputType {
fn shorthands_display() -> String {
format!(
"`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
"`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
OutputType::Bitcode.shorthand(),
OutputType::ThinLinkBitcode.shorthand(),
OutputType::Assembly.shorthand(),
OutputType::LlvmAssembly.shorthand(),
OutputType::Mir.shorthand(),
@ -543,6 +548,7 @@ impl OutputType {
pub fn extension(&self) -> &'static str {
match *self {
OutputType::Bitcode => "bc",
OutputType::ThinLinkBitcode => "indexing.o",
OutputType::Assembly => "s",
OutputType::LlvmAssembly => "ll",
OutputType::Mir => "mir",
@ -559,9 +565,11 @@ impl OutputType {
| OutputType::LlvmAssembly
| OutputType::Mir
| OutputType::DepInfo => true,
OutputType::Bitcode | OutputType::Object | OutputType::Metadata | OutputType::Exe => {
false
}
OutputType::Bitcode
| OutputType::ThinLinkBitcode
| OutputType::Object
| OutputType::Metadata
| OutputType::Exe => false,
}
}
}
@ -644,6 +652,7 @@ impl OutputTypes {
pub fn should_codegen(&self) -> bool {
self.0.keys().any(|k| match *k {
OutputType::Bitcode
| OutputType::ThinLinkBitcode
| OutputType::Assembly
| OutputType::LlvmAssembly
| OutputType::Mir
@ -657,6 +666,7 @@ impl OutputTypes {
pub fn should_link(&self) -> bool {
self.0.keys().any(|k| match *k {
OutputType::Bitcode
| OutputType::ThinLinkBitcode
| OutputType::Assembly
| OutputType::LlvmAssembly
| OutputType::Mir
@ -1769,6 +1779,12 @@ fn parse_output_types(
display = OutputType::shorthands_display(),
))
});
if output_type == OutputType::ThinLinkBitcode && !unstable_opts.unstable_options {
early_dcx.early_fatal(format!(
"{} requested but -Zunstable-options not specified",
OutputType::ThinLinkBitcode.shorthand()
));
}
output_types.insert(output_type, path);
}
}

View File

@ -51,6 +51,14 @@ pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("lib")])
}
/// Returns a path to the target's `bin` folder within its `rustlib` path in the sysroot. This is
/// where binaries are usually installed, e.g. the self-contained linkers, lld-wrappers, LLVM tools,
/// etc.
pub fn make_target_bin_path(sysroot: &Path, target_triple: &str) -> PathBuf {
let rustlib_path = rustc_target::target_rustlib_path(sysroot, target_triple);
PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("bin")])
}
#[cfg(unix)]
fn current_dll_path() -> Result<PathBuf, String> {
use std::ffi::{CStr, OsStr};

View File

@ -449,15 +449,24 @@ impl Session {
)
}
/// Returns a list of directories where target-specific tool binaries are located.
/// Returns a list of directories where target-specific tool binaries are located. Some fallback
/// directories are also returned, for example if `--sysroot` is used but tools are missing
/// (#125246): we also add the bin directories to the sysroot where rustc is located.
pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
let rustlib_path = rustc_target::target_rustlib_path(&self.sysroot, config::host_triple());
let p = PathBuf::from_iter([
Path::new(&self.sysroot),
Path::new(&rustlib_path),
Path::new("bin"),
]);
if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] }
let bin_path = filesearch::make_target_bin_path(&self.sysroot, config::host_triple());
let fallback_sysroot_paths = filesearch::sysroot_candidates()
.into_iter()
.map(|sysroot| filesearch::make_target_bin_path(&sysroot, config::host_triple()));
let search_paths = std::iter::once(bin_path).chain(fallback_sysroot_paths);
if self_contained {
// The self-contained tools are expected to be e.g. in `bin/self-contained` in the
// sysroot's `rustlib` path, so we add such a subfolder to the bin path, and the
// fallback paths.
search_paths.flat_map(|path| [path.clone(), path.join("self-contained")]).collect()
} else {
search_paths.collect()
}
}
pub fn init_incr_comp_session(&self, session_dir: PathBuf, lock_file: flock::Lock) {

View File

@ -46,6 +46,8 @@ check-cfg = [
'cfg(bootstrap)',
'cfg(no_fp_fmt_parse)',
'cfg(stdarch_intel_sde)',
# This matches `EXTRA_CHECK_CFGS` in `src/bootstrap/src/lib.rs`.
# core use #[path] imports to portable-simd `core_simd` crate
# and to stdarch `core_arch` crate which messes-up with Cargo list
# of declared features, we therefor expect any feature cfg
'cfg(feature, values(any()))',
]

View File

@ -80,47 +80,6 @@ macro_rules! forward_ref_op_assign {
}
}
/// Create a zero-size type similar to a closure type, but named.
macro_rules! impl_fn_for_zst {
($(
$( #[$attr: meta] )*
struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
|$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
$body: block;
)+) => {
$(
$( #[$attr] )*
struct $Name;
impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
#[inline]
extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
$body
}
}
impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
#[inline]
extern "rust-call" fn call_mut(
&mut self,
($( $arg, )*): ($( $ArgTy, )*)
) -> $ReturnTy {
Fn::call(&*self, ($( $arg, )*))
}
}
impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
type Output = $ReturnTy;
#[inline]
extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
Fn::call(&self, ($( $arg, )*))
}
}
)+
}
}
/// A macro for defining `#[cfg]` if-else statements.
///
/// `cfg_if` is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade

View File

@ -255,6 +255,7 @@
#![feature(trait_alias)]
#![feature(transparent_unions)]
#![feature(try_blocks)]
#![feature(type_alias_impl_trait)]
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
#![feature(with_negative_coherence)]

View File

@ -108,7 +108,7 @@ impl [u8] {
without modifying the original"]
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
pub fn escape_ascii(&self) -> EscapeAscii<'_> {
EscapeAscii { inner: self.iter().flat_map(EscapeByte) }
EscapeAscii { inner: self.iter().flat_map(|byte| byte.escape_ascii()) }
}
/// Returns a byte slice with leading ASCII whitespace bytes removed.
@ -190,12 +190,7 @@ impl [u8] {
}
}
impl_fn_for_zst! {
#[derive(Clone)]
struct EscapeByte impl Fn = |byte: &u8| -> ascii::EscapeDefault {
ascii::escape_default(*byte)
};
}
type EscapeByte = impl (Fn(&u8) -> ascii::EscapeDefault) + Copy;
/// An iterator over the escaped version of a byte slice.
///

View File

@ -1274,8 +1274,10 @@ pub struct SplitWhitespace<'a> {
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
#[derive(Clone, Debug)]
pub struct SplitAsciiWhitespace<'a> {
pub(super) inner:
Map<Filter<SliceSplit<'a, u8, IsAsciiWhitespace>, BytesIsNotEmpty>, UnsafeBytesToStr>,
pub(super) inner: Map<
Filter<SliceSplit<'a, u8, IsAsciiWhitespace>, BytesIsNotEmpty<'a>>,
UnsafeBytesToStr<'a>,
>,
}
/// An iterator over the substrings of a string,

View File

@ -983,7 +983,7 @@ impl str {
#[cfg_attr(not(test), rustc_diagnostic_item = "str_split_whitespace")]
#[inline]
pub fn split_whitespace(&self) -> SplitWhitespace<'_> {
SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) }
SplitWhitespace { inner: self.split(char::is_whitespace).filter(|s| !s.is_empty()) }
}
/// Splits a string slice by ASCII whitespace.
@ -1032,8 +1032,13 @@ impl str {
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
#[inline]
pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_> {
let inner =
self.as_bytes().split(IsAsciiWhitespace).filter(BytesIsNotEmpty).map(UnsafeBytesToStr);
let inner = self
.as_bytes()
.split(u8::is_ascii_whitespace)
.filter(|s| !s.is_empty())
// SAFETY: the byte slice came from a string and was only split
// along character boundaries, so the resulting slices are strings.
.map(|bytes| unsafe { from_utf8_unchecked(bytes) });
SplitAsciiWhitespace { inner }
}
@ -1085,7 +1090,11 @@ impl str {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn lines(&self) -> Lines<'_> {
Lines(self.split_inclusive('\n').map(LinesMap))
Lines(self.split_inclusive('\n').map(|line| {
let Some(line) = line.strip_suffix('\n') else { return line };
let Some(line) = line.strip_suffix('\r') else { return line };
line
}))
}
/// An iterator over the lines of a string.
@ -2636,14 +2645,19 @@ impl str {
#[stable(feature = "str_escape", since = "1.34.0")]
pub fn escape_debug(&self) -> EscapeDebug<'_> {
let mut chars = self.chars();
EscapeDebug {
inner: chars
let first = chars
.next()
.map(|first| first.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL))
.into_iter()
.flatten()
.chain(chars.flat_map(CharEscapeDebugContinue)),
}
.flatten();
let inner = first.chain(chars.flat_map(|c| {
c.escape_debug_ext(EscapeDebugExtArgs {
escape_grapheme_extended: false,
escape_single_quote: true,
escape_double_quote: true,
})
}));
EscapeDebug { inner }
}
/// Return an iterator that escapes each char in `self` with [`char::escape_default`].
@ -2681,7 +2695,7 @@ impl str {
without modifying the original"]
#[stable(feature = "str_escape", since = "1.34.0")]
pub fn escape_default(&self) -> EscapeDefault<'_> {
EscapeDefault { inner: self.chars().flat_map(CharEscapeDefault) }
EscapeDefault { inner: self.chars().flat_map(char::escape_default) }
}
/// Return an iterator that escapes each char in `self` with [`char::escape_unicode`].
@ -2719,7 +2733,7 @@ impl str {
without modifying the original"]
#[stable(feature = "str_escape", since = "1.34.0")]
pub fn escape_unicode(&self) -> EscapeUnicode<'_> {
EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) }
EscapeUnicode { inner: self.chars().flat_map(char::escape_unicode) }
}
}
@ -2750,59 +2764,15 @@ impl Default for &mut str {
}
}
impl_fn_for_zst! {
/// A nameable, cloneable fn type
#[derive(Clone)]
struct LinesMap impl<'a> Fn = |line: &'a str| -> &'a str {
let Some(line) = line.strip_suffix('\n') else { return line };
let Some(line) = line.strip_suffix('\r') else { return line };
line
};
#[derive(Clone)]
struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug {
c.escape_debug_ext(EscapeDebugExtArgs {
escape_grapheme_extended: false,
escape_single_quote: true,
escape_double_quote: true
})
};
#[derive(Clone)]
struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode {
c.escape_unicode()
};
#[derive(Clone)]
struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault {
c.escape_default()
};
#[derive(Clone)]
struct IsWhitespace impl Fn = |c: char| -> bool {
c.is_whitespace()
};
#[derive(Clone)]
struct IsAsciiWhitespace impl Fn = |byte: &u8| -> bool {
byte.is_ascii_whitespace()
};
#[derive(Clone)]
struct IsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b str| -> bool {
!s.is_empty()
};
#[derive(Clone)]
struct BytesIsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b [u8]| -> bool {
!s.is_empty()
};
#[derive(Clone)]
struct UnsafeBytesToStr impl<'a> Fn = |bytes: &'a [u8]| -> &'a str {
// SAFETY: not safe
unsafe { from_utf8_unchecked(bytes) }
};
}
type LinesMap = impl (Fn(&str) -> &str) + Copy;
type CharEscapeDebugContinue = impl (FnMut(char) -> char::EscapeDebug) + Copy;
type CharEscapeUnicode = impl (Fn(char) -> char::EscapeUnicode) + Copy;
type CharEscapeDefault = impl (Fn(char) -> char::EscapeDefault) + Copy;
type IsWhitespace = impl (Fn(char) -> bool) + Copy;
type IsAsciiWhitespace = impl (Fn(&u8) -> bool) + Copy;
type IsNotEmpty = impl (Fn(&&str) -> bool) + Copy;
type BytesIsNotEmpty<'a> = impl (FnMut(&&'a [u8]) -> bool) + Copy;
type UnsafeBytesToStr<'a> = impl (FnMut(&'a [u8]) -> &'a str) + Copy;
// This is required to make `impl From<&str> for Box<dyn Error>` and `impl<E> From<E> for Box<dyn Error>` not overlap.
#[stable(feature = "rust1", since = "1.0.0")]

View File

@ -100,10 +100,14 @@ test = true
[lints.rust.unexpected_cfgs]
level = "warn"
# x.py uses beta cargo, so `check-cfg` entries do not yet take effect
# for rust-lang/rust. But for users of `-Zbuild-std` it does.
# The unused warning is waiting for rust-lang/cargo#13925 to reach beta.
check-cfg = [
'cfg(bootstrap)',
'cfg(backtrace_in_libstd)',
'cfg(netbsd10)',
'cfg(target_arch, values("xtensa"))',
'cfg(feature, values("std", "as_crate"))',
# std use #[path] imports to portable-simd `std_float` crate
# and to the `backtrace` crate which messes-up with Cargo list
# of declared features, we therefor expect any feature cfg
'cfg(feature, values(any()))',
]

View File

@ -7,9 +7,13 @@ fn main() {
let target_vendor =
env::var("CARGO_CFG_TARGET_VENDOR").expect("CARGO_CFG_TARGET_VENDOR was not set");
let target_env = env::var("CARGO_CFG_TARGET_ENV").expect("CARGO_CFG_TARGET_ENV was not set");
println!("cargo:rustc-check-cfg=cfg(netbsd10)");
if target_os == "netbsd" && env::var("RUSTC_STD_NETBSD10").is_ok() {
println!("cargo:rustc-cfg=netbsd10");
}
println!("cargo:rustc-check-cfg=cfg(restricted_std)");
if target_os == "linux"
|| target_os == "android"
|| target_os == "netbsd"
@ -59,8 +63,11 @@ fn main() {
// - arch=avr
// - JSON targets
// - Any new targets that have not been explicitly added above.
println!("cargo:rustc-cfg=feature=\"restricted-std\"");
println!("cargo:rustc-cfg=restricted_std");
}
println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap());
println!("cargo:rustc-check-cfg=cfg(backtrace_in_libstd)");
println!("cargo:rustc-cfg=backtrace_in_libstd");
println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap());
}

View File

@ -213,9 +213,9 @@
//! [array]: prim@array
//! [slice]: prim@slice
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(not(restricted_std), stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(
feature = "restricted-std",
restricted_std,
unstable(
feature = "restricted_std",
issue = "none",

View File

@ -92,8 +92,6 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
(Some(Mode::Std), "no_global_oom_handling", None),
(Some(Mode::Std), "no_rc", None),
(Some(Mode::Std), "no_sync", None),
(Some(Mode::Std), "netbsd10", None),
(Some(Mode::Std), "backtrace_in_libstd", None),
/* Extra values not defined in the built-in targets yet, but used in std */
(Some(Mode::Std), "target_env", Some(&["libnx", "p2"])),
(Some(Mode::Std), "target_os", Some(&["visionos"])),

View File

@ -229,7 +229,6 @@ run-make/rustc-macro-dep-files/Makefile
run-make/rustdoc-io-error/Makefile
run-make/rustdoc-verify-output-files/Makefile
run-make/rustdoc-with-output-option/Makefile
run-make/rustdoc-with-short-out-dir-option/Makefile
run-make/sanitizer-cdylib-link/Makefile
run-make/sanitizer-dylib-link/Makefile
run-make/sanitizer-staticlib-link/Makefile

View File

@ -1,8 +0,0 @@
include ../tools.mk
OUTPUT_DIR := "$(TMPDIR)/rustdoc"
all:
$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib -o $(OUTPUT_DIR)
$(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs

View File

@ -0,0 +1,16 @@
use run_make_support::{htmldocck, rustdoc, tmp_dir};
fn main() {
let out_dir = tmp_dir().join("rustdoc");
rustdoc()
.input("src/lib.rs")
.crate_name("foobar")
.crate_type("lib")
// This is intentionally using `-o` option flag and not the `output()` method.
.arg("-o")
.arg(&out_dir)
.run();
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
}

View File

@ -0,0 +1,22 @@
// This test checks that when we are building a build script provided
// by Cargo we only suggest expecting the unexpected cfgs in the Cargo.toml.
//
//@ check-pass
//@ no-auto-check-cfg
//@ rustc-env:CARGO_CRATE_NAME=build_script_build
//@ compile-flags:--crate-name=build_script_build
//@ compile-flags:--check-cfg=cfg(has_bar)
#[cfg(has_foo)]
//~^ WARNING unexpected `cfg` condition name
fn foo() {}
#[cfg(has_foo = "yes")]
//~^ WARNING unexpected `cfg` condition name
fn foo() {}
#[cfg(has_bar = "yes")]
//~^ WARNING unexpected `cfg` condition value
fn has_bar() {}
fn main() {}

View File

@ -0,0 +1,43 @@
warning: unexpected `cfg` condition name: `has_foo`
--> $DIR/cargo-build-script.rs:10:7
|
LL | #[cfg(has_foo)]
| ^^^^^^^
|
= help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `has_bar`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
= help: consider using a Cargo feature instead
= help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(has_foo)'] }
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition name: `has_foo`
--> $DIR/cargo-build-script.rs:14:7
|
LL | #[cfg(has_foo = "yes")]
| ^^^^^^^^^^^^^^^
|
= help: consider using a Cargo feature instead
= help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(has_foo, values("yes"))'] }
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `yes`
--> $DIR/cargo-build-script.rs:18:7
|
LL | #[cfg(has_bar = "yes")]
| ^^^^^^^--------
| |
| help: remove the value
|
= note: no expected value for `has_bar`
= help: consider using a Cargo feature instead
= help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(has_bar, values("yes"))'] }
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: 3 warnings emitted