Skip to content

Rollup of 4 pull requests #134266

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -992,12 +992,12 @@ fn link_natively(
let mut output = prog.stderr.clone();
output.extend_from_slice(&prog.stdout);
let escaped_output = escape_linker_output(&output, flavor);
// FIXME: Add UI tests for this error.
let err = errors::LinkingFailed {
linker_path: &linker_path,
exit_status: prog.status,
command: &cmd,
command: cmd,
escaped_output,
verbose: sess.opts.verbose,
};
sess.dcx().emit_err(err);
// If MSVC's `link.exe` was expected but the return code
Expand Down
70 changes: 66 additions & 4 deletions compiler/rustc_codegen_ssa/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Errors emitted by codegen_ssa

use std::borrow::Cow;
use std::ffi::OsString;
use std::io::Error;
use std::num::ParseIntError;
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -345,21 +346,82 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ThorinErrorWrapper {
}

pub(crate) struct LinkingFailed<'a> {
pub linker_path: &'a PathBuf,
pub linker_path: &'a Path,
pub exit_status: ExitStatus,
pub command: &'a Command,
pub command: Command,
pub escaped_output: String,
pub verbose: bool,
}

impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed);
diag.arg("linker_path", format!("{}", self.linker_path.display()));
diag.arg("exit_status", format!("{}", self.exit_status));

let contains_undefined_ref = self.escaped_output.contains("undefined reference to");

diag.note(format!("{:?}", self.command)).note(self.escaped_output);
if self.verbose {
diag.note(format!("{:?}", self.command));
} else {
enum ArgGroup {
Regular(OsString),
Objects(usize),
Rlibs(PathBuf, Vec<OsString>),
}

// Omit rust object files and fold rlibs in the error by default to make linker errors a
// bit less verbose.
let orig_args = self.command.take_args();
let mut args: Vec<ArgGroup> = vec![];
for arg in orig_args {
if arg.as_encoded_bytes().ends_with(b".rcgu.o") {
if let Some(ArgGroup::Objects(n)) = args.last_mut() {
*n += 1;
} else {
args.push(ArgGroup::Objects(1));
}
} else if arg.as_encoded_bytes().ends_with(b".rlib") {
let rlib_path = Path::new(&arg);
let dir = rlib_path.parent().unwrap();
let filename = rlib_path.file_name().unwrap().to_owned();
if let Some(ArgGroup::Rlibs(parent, rlibs)) = args.last_mut() {
if parent == dir {
rlibs.push(filename);
} else {
args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename]));
}
} else {
args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename]));
}
} else {
args.push(ArgGroup::Regular(arg));
}
}
self.command.args(args.into_iter().map(|arg_group| match arg_group {
ArgGroup::Regular(arg) => arg,
ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
ArgGroup::Rlibs(dir, rlibs) => {
let mut arg = dir.into_os_string();
arg.push("/{");
let mut first = true;
for rlib in rlibs {
if !first {
arg.push(",");
}
first = false;
arg.push(rlib);
}
arg.push("}");
arg
}
}));

diag.note(format!("{:?}", self.command));
diag.note("some arguments are omitted. use `--verbose` to show all linker arguments");
}

diag.note(self.escaped_output);

// Trying to match an error from OS linkers
// which by now we have no way to translate.
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
kind = AnnotationKind::DeprecationProhibited;
const_stab_inherit = InheritConstStability::Yes;
}
hir::ItemKind::Use(_, _) => {
kind = AnnotationKind::DeprecationProhibited;
}
hir::ItemKind::Struct(ref sd, _) => {
if let Some(ctor_def_id) = sd.ctor_def_id() {
self.annotate(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/callconv/powerpc64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec,
{
let abi = if cx.target_spec().env == "musl" {
let abi = if cx.target_spec().env == "musl" || cx.target_spec().os == "freebsd" {
ELFv2
} else if cx.target_spec().os == "aix" {
AIX
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
Target {
llvm_target: "powerpc64-unknown-freebsd".into(),
metadata: crate::spec::TargetMetadata {
description: Some("PPC64 FreeBSD (ELFv1 and ELFv2)".into()),
description: Some("PPC64 FreeBSD (ELFv2)".into()),
tier: Some(3),
host_tools: Some(true),
std: Some(true),
Expand Down
5 changes: 0 additions & 5 deletions library/core/src/alloc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ pub use self::global::GlobalAlloc;
#[stable(feature = "alloc_layout", since = "1.28.0")]
pub use self::layout::Layout;
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[deprecated(
since = "1.52.0",
note = "Name does not follow std convention, use LayoutError",
suggestion = "LayoutError"
)]
#[allow(deprecated, deprecated_in_future)]
pub use self::layout::LayoutErr;
#[stable(feature = "alloc_layout_error", since = "1.50.0")]
Expand Down
92 changes: 89 additions & 3 deletions library/core/src/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,13 +310,17 @@ pub fn spin_loop() {
/// behavior in the calling code. This property makes `black_box` useful for writing code in which
/// certain optimizations are not desired, such as benchmarks.
///
/// <div class="warning">
///
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness*, beyond it behaving as the
/// identity function. As such, it **must not be relied upon to control critical program behavior.**
/// This also means that this function does not offer any guarantees for cryptographic or security
/// purposes.
///
/// </div>
///
/// [`std::convert::identity`]: crate::convert::identity
///
/// # When is this useful?
Expand Down Expand Up @@ -357,7 +361,7 @@ pub fn spin_loop() {
/// ```
/// use std::hint::black_box;
///
/// // Same `contains` function
/// // Same `contains` function.
/// fn contains(haystack: &[&str], needle: &str) -> bool {
/// haystack.iter().any(|x| x == &needle)
/// }
Expand All @@ -366,8 +370,13 @@ pub fn spin_loop() {
/// let haystack = vec!["abc", "def", "ghi", "jkl", "mno"];
/// let needle = "ghi";
/// for _ in 0..10 {
/// // Adjust our benchmark loop contents
/// black_box(contains(black_box(&haystack), black_box(needle)));
/// // Force the compiler to run `contains`, even though it is a pure function whose
/// // results are unused.
/// black_box(contains(
/// // Prevent the compiler from making assumptions about the input.
/// black_box(&haystack),
/// black_box(needle),
/// ));
/// }
/// }
/// ```
Expand All @@ -382,6 +391,83 @@ pub fn spin_loop() {
///
/// This makes our benchmark much more realistic to how the function would actually be used, where
/// arguments are usually not known at compile time and the result is used in some way.
///
/// # How to use this
///
/// In practice, `black_box` serves two purposes:
///
/// 1. It prevents the compiler from making optimizations related to the value returned by `black_box`
/// 2. It forces the value passed to `black_box` to be calculated, even if the return value of `black_box` is unused
///
/// ```
/// use std::hint::black_box;
///
/// let zero = 0;
/// let five = 5;
///
/// // The compiler will see this and remove the `* five` call, because it knows that multiplying
/// // any integer by 0 will result in 0.
/// let c = zero * five;
///
/// // Adding `black_box` here disables the compiler's ability to reason about the first operand in the multiplication.
/// // It is forced to assume that it can be any possible number, so it cannot remove the `* five`
/// // operation.
/// let c = black_box(zero) * five;
/// ```
///
/// While most cases will not be as clear-cut as the above example, it still illustrates how
/// `black_box` can be used. When benchmarking a function, you usually want to wrap its inputs in
/// `black_box` so the compiler cannot make optimizations that would be unrealistic in real-life
/// use.
///
/// ```
/// use std::hint::black_box;
///
/// // This is a simple function that increments its input by 1. Note that it is pure, meaning it
/// // has no side-effects. This function has no effect if its result is unused. (An example of a
/// // function *with* side-effects is `println!()`.)
/// fn increment(x: u8) -> u8 {
/// x + 1
/// }
///
/// // Here, we call `increment` but discard its result. The compiler, seeing this and knowing that
/// // `increment` is pure, will eliminate this function call entirely. This may not be desired,
/// // though, especially if we're trying to track how much time `increment` takes to execute.
/// let _ = increment(black_box(5));
///
/// // Here, we force `increment` to be executed. This is because the compiler treats `black_box`
/// // as if it has side-effects, and thus must compute its input.
/// let _ = black_box(increment(black_box(5)));
/// ```
///
/// There may be additional situations where you want to wrap the result of a function in
/// `black_box` to force its execution. This is situational though, and may not have any effect
/// (such as when the function returns a zero-sized type such as [`()` unit][unit]).
///
/// Note that `black_box` has no effect on how its input is treated, only its output. As such,
/// expressions passed to `black_box` may still be optimized:
///
/// ```
/// use std::hint::black_box;
///
/// // The compiler sees this...
/// let y = black_box(5 * 10);
///
/// // ...as this. As such, it will likely simplify `5 * 10` to just `50`.
/// let _0 = 5 * 10;
/// let y = black_box(_0);
/// ```
///
/// In the above example, the `5 * 10` expression is considered distinct from the `black_box` call,
/// and thus is still optimized by the compiler. You can prevent this by moving the multiplication
/// operation outside of `black_box`:
///
/// ```
/// use std::hint::black_box;
///
/// // No assumptions can be made about either operand, so the multiplication is not optimized out.
/// let y = black_box(5) * black_box(10);
/// ```
#[inline]
#[stable(feature = "bench_black_box", since = "1.66.0")]
#[rustc_const_unstable(feature = "const_black_box", issue = "none")]
Expand Down
3 changes: 1 addition & 2 deletions library/std/src/collections/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,7 @@ pub use self::hash_map::HashMap;
#[doc(inline)]
pub use self::hash_set::HashSet;
#[stable(feature = "rust1", since = "1.0.0")]
// FIXME(#82080) The deprecation here is only theoretical, and does not actually produce a warning.
#[deprecated(note = "moved to `std::ops::Bound`", since = "1.26.0")]
// FIXME(#82080) This has moved but #[deprecated] on `use` is unsupported.
#[doc(hidden)]
pub use crate::ops::Bound;

Expand Down
2 changes: 1 addition & 1 deletion src/doc/rustc/src/platform-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ target | std | host | notes
[`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * | |
[`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | |
[`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ | |
`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv2)
`powerpc64le-unknown-freebsd` | ✓ | ✓ | PPC64LE FreeBSD
`powerpc-unknown-freebsd` | ? | | PowerPC FreeBSD
`powerpc64-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3
Expand Down
6 changes: 6 additions & 0 deletions src/tools/run-make-support/src/external_deps/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,12 @@ impl Rustc {
self
}

/// Pass the `--verbose` flag.
pub fn verbose(&mut self) -> &mut Self {
self.cmd.arg("--verbose");
self
}

/// `EXTRARSCXXFLAGS`
pub fn extra_rs_cxx_flags(&mut self) -> &mut Self {
// Adapted from tools.mk (trimmed):
Expand Down
6 changes: 4 additions & 2 deletions tests/run-make/link-args-order/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ fn main() {
.link_args("b c")
.link_args("d e")
.link_arg("f")
.arg("--print=link-args")
.run_fail()
.assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
.assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#);
rustc()
.input("empty.rs")
.linker_flavor(linker)
.arg("-Zpre-link-arg=a")
.arg("-Zpre-link-args=b c")
.arg("-Zpre-link-args=d e")
.arg("-Zpre-link-arg=f")
.arg("--print=link-args")
.run_fail()
.assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
.assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#);
}
12 changes: 6 additions & 6 deletions tests/run-make/link-dedup/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ fn main() {
rustc().input("depb.rs").run();
rustc().input("depc.rs").run();

let output = rustc().input("empty.rs").cfg("bar").run_fail();
output.assert_stderr_contains(needle_from_libs(&["testa", "testb", "testa"]));
let output = rustc().input("empty.rs").cfg("bar").arg("--print=link-args").run_fail();
output.assert_stdout_contains(needle_from_libs(&["testa", "testb", "testa"]));

let output = rustc().input("empty.rs").run_fail();
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"]));
let output = rustc().input("empty.rs").arg("--print=link-args").run_fail();
output.assert_stdout_contains(needle_from_libs(&["testa"]));
output.assert_stdout_not_contains(needle_from_libs(&["testb"]));
output.assert_stdout_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:
Expand Down
13 changes: 13 additions & 0 deletions tests/run-make/linker-warning/fake-linker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
fn main() {
for arg in std::env::args() {
match &*arg {
"run_make_info" => println!("foo"),
"run_make_warn" => eprintln!("warning: bar"),
"run_make_error" => {
eprintln!("error: baz");
std::process::exit(1);
}
_ => (),
}
}
}
1 change: 1 addition & 0 deletions tests/run-make/linker-warning/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fn main() {}
28 changes: 28 additions & 0 deletions tests/run-make/linker-warning/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use run_make_support::{Rustc, rustc};

fn run_rustc() -> Rustc {
let mut rustc = rustc();
rustc.arg("main.rs").output("main").linker("./fake-linker");
rustc
}

fn main() {
// first, compile our linker
rustc().arg("fake-linker.rs").output("fake-linker").run();

// Make sure we don't show the linker args unless `--verbose` is passed
run_rustc()
.link_arg("run_make_error")
.verbose()
.run_fail()
.assert_stderr_contains_regex("fake-linker.*run_make_error")
.assert_stderr_not_contains("object files omitted")
.assert_stderr_contains_regex(r"lib[/\\]libstd");
run_rustc()
.link_arg("run_make_error")
.run_fail()
.assert_stderr_contains("fake-linker")
.assert_stderr_contains("object files omitted")
.assert_stderr_contains_regex(r"\{")
.assert_stderr_not_contains_regex(r"lib[/\\]libstd");
}
Loading
Loading