Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub(crate) enum ImportKind<'a> {
/// `source` in `use prefix::source as target`.
source: Ident,
/// `target` in `use prefix::source as target`.
/// It will directly use `source` when the format is `use prefix::source`.
target: Ident,
/// Bindings to which `source` refers to.
source_bindings: PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,
Expand Down
3 changes: 2 additions & 1 deletion config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,8 @@
# This is mostly useful for tools; if you have changes to `compiler/` or `library/` they will be ignored.
#
# Set this to "if-unchanged" to only download if the compiler and standard library have not been modified.
# Set this to `true` to download unconditionally (useful if e.g. you are only changing doc-comments).
# Set this to `true` to download unconditionally. This is useful if you are working on tools, doc-comments,
# or library (you will be able to build the standard library without needing to build the compiler).
#download-rustc = false

# Number of codegen units to use for each compiler invocation. A value of 0
Expand Down
12 changes: 11 additions & 1 deletion library/std/src/sys/pal/unix/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,18 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {

Ok(NonZero::new_unchecked(sinfo.cpu_count as usize))
}
} else if #[cfg(target_os = "vxworks")] {
// Note: there is also `vxCpuConfiguredGet`, closer to _SC_NPROCESSORS_CONF
// expectations than the actual cores availability.
extern "C" {
fn vxCpuEnabledGet() -> libc::cpuset_t;
}

// always fetches a valid bitmask
let set = unsafe { vxCpuEnabledGet() };
Ok(NonZero::new_unchecked(set.count_ones() as usize))
} else {
// FIXME: implement on vxWorks, Redox, l4re
// FIXME: implement on Redox, l4re
Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform"))
}
}
Expand Down
39 changes: 31 additions & 8 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ use crate::core::builder::{
use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
use crate::utils::exec::command;
use crate::utils::helpers::{
exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
self, exe, get_clang_cl_resource_dir, get_closest_merge_base_commit, is_debug_info, is_dylib,
symlink_dir, t, up_to_date,
};
use crate::{CLang, Compiler, DependencyType, GitRepo, Mode, LLVM_TOOLS};

Expand Down Expand Up @@ -114,21 +115,43 @@ impl Step for Std {
const DEFAULT: bool = true;

fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
// When downloading stage1, the standard library has already been copied to the sysroot, so
// there's no need to rebuild it.
let builder = run.builder;
run.crate_or_deps("sysroot")
.path("library")
.lazy_default_condition(Box::new(|| !builder.download_rustc()))
run.crate_or_deps("sysroot").path("library")
}

fn make_run(run: RunConfig<'_>) {
let crates = std_crates_for_run_make(&run);
let builder = run.builder;

// Force compilation of the standard library from source if the `library` is modified. This allows
// library team to compile the standard library without needing to compile the compiler with
// the `rust.download-rustc=true` option.
let force_recompile =
if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() {
let closest_merge_commit = get_closest_merge_base_commit(
Some(&builder.src),
&builder.config.git_config(),
&builder.config.stage0_metadata.config.git_merge_commit_email,
&[],
)
.unwrap();

// Check if `library` has changes (returns false otherwise)
!t!(helpers::git(Some(&builder.src))
.args(["diff-index", "--quiet", &closest_merge_commit])
.arg("--")
.arg(builder.src.join("library"))
.as_command_mut()
.status())
.success()
} else {
false
};

run.builder.ensure(Std {
compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
target: run.target,
crates,
force_recompile: false,
force_recompile,
extra_rust_args: &[],
is_for_mir_opt_tests: false,
});
Expand Down
8 changes: 7 additions & 1 deletion src/bootstrap/src/core/build_steps/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,17 @@ impl Step for JsonDocs {
));

let dest = "share/doc/rust/json";
let out = builder.json_doc_out(host);

// Make sure these are present in the component.
for f in ["alloc.json", "core.json", "std.json"] {
assert!(out.join(f).exists(), "rust-docs-json is missing `{f}`.");
}

let mut tarball = Tarball::new(builder, "rust-docs-json", &host.triple);
tarball.set_product_name("Rust Documentation In JSON Format");
tarball.is_preview(true);
tarball.add_bulk_dir(builder.json_doc_out(host), dest);
tarball.add_bulk_dir(out, dest);
Some(tarball.generate())
}
}
Expand Down
14 changes: 12 additions & 2 deletions src/bootstrap/src/core/build_steps/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,16 @@ impl Step for Std {
fn run(self, builder: &Builder<'_>) {
let stage = self.stage;
let target = self.target;
let crates = if self.crates.is_empty() {
builder
.in_tree_crates("sysroot", Some(target))
.iter()
.map(|c| c.name.to_string())
.collect()
} else {
self.crates
};

let out = match self.format {
DocumentationFormat::Html => builder.doc_out(target),
DocumentationFormat::Json => builder.json_doc_out(target),
Expand Down Expand Up @@ -627,7 +637,7 @@ impl Step for Std {
extra_args.push("--disable-minification");
}

doc_std(builder, self.format, stage, target, &out, &extra_args, &self.crates);
doc_std(builder, self.format, stage, target, &out, &extra_args, &crates);

// Don't open if the format is json
if let DocumentationFormat::Json = self.format {
Expand All @@ -639,7 +649,7 @@ impl Step for Std {
let index = out.join("std").join("index.html");
builder.open_in_browser(index);
} else {
for requested_crate in &*self.crates {
for requested_crate in crates {
if STD_PUBLIC_CRATES.iter().any(|&k| k == requested_crate) {
let index = out.join(requested_crate).join("index.html");
builder.open_in_browser(index);
Expand Down
19 changes: 19 additions & 0 deletions tests/codegen/issues/issue-122600-ptr-discriminant-update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//@ compile-flags: -O
//@ min-llvm-version: 19

#![crate_type = "lib"]

pub enum State {
A([u8; 753]),
B([u8; 753]),
}

// CHECK-LABEL: @update
#[no_mangle]
pub unsafe fn update(s: *mut State) {
// CHECK-NEXT: start:
// CHECK-NEXT: store i8
// CHECK-NEXT: ret
let State::A(v) = s.read() else { std::hint::unreachable_unchecked() };
s.write(State::B(v));
}
33 changes: 25 additions & 8 deletions tests/run-make/link-dedup/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,37 @@
// Without the --cfg flag, there should be a single -ltesta, no more, no less.
// See https://github.com/rust-lang/rust/pull/84794

//@ ignore-msvc
use std::fmt::Write;

use run_make_support::rustc;
use run_make_support::{is_msvc, rustc};

fn main() {
rustc().input("depa.rs").run();
rustc().input("depb.rs").run();
rustc().input("depc.rs").run();

let output = rustc().input("empty.rs").cfg("bar").run_fail();
output.assert_stderr_contains(r#""-ltesta" "-ltestb" "-ltesta""#);
let output = rustc().input("empty.rs").run_fail();
output.assert_stderr_contains(r#""-ltesta""#);
let output = rustc().input("empty.rs").run_fail();
output.assert_stderr_not_contains(r#""-ltestb""#);
output.assert_stderr_contains(needle_from_libs(&["testa", "testb", "testa"]));

let output = rustc().input("empty.rs").run_fail();
output.assert_stderr_not_contains(r#""-ltesta" "-ltesta" "-ltesta""#);
output.assert_stderr_contains(needle_from_libs(&["testa"]));
output.assert_stderr_not_contains(needle_from_libs(&["testb"]));
output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
// Adjacent identical native libraries are no longer deduplicated if
// they come from different crates (https://github.com/rust-lang/rust/pull/103311)
// so the following will fail:
//output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa"]));
}

fn needle_from_libs(libs: &[&str]) -> String {
let mut needle = String::new();
for lib in libs {
if is_msvc() {
let _ = needle.write_fmt(format_args!(r#""{lib}.lib" "#));
} else {
let _ = needle.write_fmt(format_args!(r#""-l{lib}" "#));
}
}
needle.pop(); // remove trailing space
needle
}
87 changes: 87 additions & 0 deletions tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#![feature(naked_functions, asm_const, linkage)]
#![crate_type = "dylib"]

use std::arch::asm;

pub trait TraitWithConst {
const COUNT: u32;
}

struct Test;

impl TraitWithConst for Test {
const COUNT: u32 = 1;
}

#[no_mangle]
fn entry() {
private_vanilla_rust_function_from_rust_dylib();
private_naked_rust_function_from_rust_dylib();

public_vanilla_generic_function_from_rust_dylib::<Test>();
public_naked_generic_function_from_rust_dylib::<Test>();
}

extern "C" fn private_vanilla_rust_function_from_rust_dylib() -> u32 {
42
}

#[no_mangle]
pub extern "C" fn public_vanilla_rust_function_from_rust_dylib() -> u32 {
42
}

pub extern "C" fn public_vanilla_generic_function_from_rust_dylib<T: TraitWithConst>() -> u32 {
T::COUNT
}

#[linkage = "weak"]
extern "C" fn vanilla_weak_linkage() -> u32 {
42
}

#[linkage = "external"]
extern "C" fn vanilla_external_linkage() -> u32 {
42
}

#[naked]
extern "C" fn private_naked_rust_function_from_rust_dylib() -> u32 {
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
}

#[naked]
#[no_mangle]
pub extern "C" fn public_naked_rust_function_from_rust_dylib() -> u32 {
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
}

#[naked]
pub extern "C" fn public_naked_generic_function_from_rust_dylib<T: TraitWithConst>() -> u32 {
unsafe { asm!("mov rax, {}", "ret", const T::COUNT, options(noreturn)) }
}

#[naked]
#[linkage = "weak"]
extern "C" fn naked_weak_linkage() -> u32 {
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
}

#[naked]
#[linkage = "external"]
extern "C" fn naked_external_linkage() -> u32 {
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
}

// functions that are declared in an `extern "C"` block are currently not exported
// this maybe should change in the future, this is just tracking the current behavior
// reported in https://github.com/rust-lang/rust/issues/128071
std::arch::global_asm! {
".globl function_defined_in_global_asm",
"function_defined_in_global_asm:",
"ret",
}

extern "C" {
pub fn function_defined_in_global_asm();
}
80 changes: 80 additions & 0 deletions tests/run-make/naked-symbol-visibility/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//@ only-x86_64
use run_make_support::object::read::{File, Object, Symbol};
use run_make_support::object::ObjectSymbol;
use run_make_support::{dynamic_lib_name, rfs, rustc};

fn main() {
let rdylib_name = dynamic_lib_name("a_rust_dylib");
rustc().arg("-Zshare-generics=no").input("a_rust_dylib.rs").run();

let binary_data = rfs::read(&rdylib_name);
let rdylib = File::parse(&*binary_data).unwrap();

// check vanilla symbols
not_exported(&rdylib, "private_vanilla_rust_function_from_rust_dylib");
global_function(&rdylib, "public_vanilla_rust_function_from_rust_dylib");
not_exported(&rdylib, "public_vanilla_generic_function_from_rust_dylib");

weak_function(&rdylib, "vanilla_weak_linkage");
global_function(&rdylib, "vanilla_external_linkage");

// naked should mirror vanilla
not_exported(&rdylib, "private_naked_rust_function_from_rust_dylib");
global_function(&rdylib, "public_naked_rust_function_from_rust_dylib");
not_exported(&rdylib, "public_naked_generic_function_from_rust_dylib");

weak_function(&rdylib, "naked_weak_linkage");
global_function(&rdylib, "naked_external_linkage");

// functions that are declared in an `extern "C"` block are currently not exported
// this maybe should change in the future, this is just tracking the current behavior
// reported in https://github.com/rust-lang/rust/issues/128071
not_exported(&rdylib, "function_defined_in_global_asm");

// share generics should expose the generic functions
rustc().arg("-Zshare-generics=yes").input("a_rust_dylib.rs").run();
let binary_data = rfs::read(&rdylib_name);
let rdylib = File::parse(&*binary_data).unwrap();

global_function(&rdylib, "public_vanilla_generic_function_from_rust_dylib");
global_function(&rdylib, "public_naked_generic_function_from_rust_dylib");
}

#[track_caller]
fn global_function(file: &File, symbol_name: &str) {
let symbols = find_dynamic_symbol(file, symbol_name);
let [symbol] = symbols.as_slice() else {
panic!("symbol {symbol_name} occurs {} times", symbols.len())
};

assert!(symbol.is_definition(), "`{symbol_name}` is not a function");
assert!(symbol.is_global(), "`{symbol_name}` is not marked as global");
}

#[track_caller]
fn weak_function(file: &File, symbol_name: &str) {
let symbols = find_dynamic_symbol(file, symbol_name);
let [symbol] = symbols.as_slice() else {
panic!("symbol {symbol_name} occurs {} times", symbols.len())
};

assert!(symbol.is_definition(), "`{symbol_name}` is not a function");
assert!(symbol.is_weak(), "`{symbol_name}` is not marked as weak");
}

#[track_caller]
fn not_exported(file: &File, symbol_name: &str) {
assert_eq!(find_dynamic_symbol(file, symbol_name).len(), 0)
}

fn find_dynamic_symbol<'file, 'data>(
file: &'file File<'data>,
expected: &str,
) -> Vec<Symbol<'data, 'file>> {
file.dynamic_symbols()
.filter(|symbol| {
let name = symbol.name().unwrap();
!name.contains("__imp_") && name.contains(expected)
})
.collect()
}