Skip to content

Commit 90d664b

Browse files
bors-ferrocene[bot]Hoverbearpvdrz
authored
1733: Validate `-fuse-ld=lld` is passed, enable on aarch64 r=Hoverbear a=Hoverbear Also needed to edit the test harness to allow non-strict args. [I am upstreaming the aarch64 enablement as well.](rust-lang/rust#146604). -- I do not expect it to merge as is, as Upstream is changing some stuff to make this story better. :) This is manually backported to 1.90/25.11: #1804 1792: Add more tests to `coretests` r=Hoverbear a=pvdrz Improve coverage numbers. This will get upstreamed. 1816: Remove `compare_and_swap` from the subset r=Hoverbear a=pvdrz This function is deprecated and not having it in the subset allows us to not write tests to increase coverage for a function that our users aren't supposed to use Co-authored-by: Ana Hobden <operator@hoverbear.org> Co-authored-by: Christian Poveda <christian.poveda@ferrous-systems.com>
4 parents 103f39e + 8ccba39 + 7c3bf43 + 49e3a4e commit 90d664b

File tree

23 files changed

+732
-63
lines changed

23 files changed

+732
-63
lines changed

bootstrap.example.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -763,10 +763,11 @@
763763
#rust.codegen-backends = ["llvm"]
764764

765765
# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, and
766-
# whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu`. This will also only be
767-
# when *not* building an external LLVM (so only when using `download-ci-llvm` or building LLVM from
768-
# the in-tree source): setting `llvm-config` in the `[target.x86_64-unknown-linux-gnu]` section will
769-
# make this default to false.
766+
# whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu` and
767+
# `aarch64-unknown-linux-gnu`. This will also only be when *not* building an external LLVM (so only
768+
# when using `download-ci-llvm` or building LLVM from the in-tree source): setting `llvm-config` in
769+
# the `[target.x86_64-unknown-linux-gnu]` or `[target.aarch64-unknown-linux-gnu`] section will make
770+
# this default to false.
770771
#rust.lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true
771772

772773
# Indicates if we should override the linker used to link Rust crates during bootstrap to be LLD.
Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,41 @@
11
use crate::spec::{
2-
FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base,
2+
Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata,
3+
TargetOptions, base,
34
};
45

56
pub(crate) fn target() -> Target {
7+
// Ferrocene annotation: Ferrocene has `lld` enabled for this target,
8+
// so the `TargetOptions` are moved out of the `Target`,
9+
// these changes can likely go away once https://github.com/rust-lang/rust/pull/146604
10+
// lands.
11+
let mut base = TargetOptions {
12+
features: "+v8a,+outline-atomics".into(),
13+
// the AAPCS64 expects use of non-leaf frame pointers per
14+
// https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
15+
// and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
16+
frame_pointer: FramePointer::NonLeaf,
17+
mcount: "\u{1}_mcount".into(),
18+
max_atomic_width: Some(128),
19+
stack_probes: StackProbeType::Inline,
20+
supported_sanitizers: SanitizerSet::ADDRESS
21+
| SanitizerSet::CFI
22+
| SanitizerSet::KCFI
23+
| SanitizerSet::LEAK
24+
| SanitizerSet::MEMORY
25+
| SanitizerSet::MEMTAG
26+
| SanitizerSet::THREAD
27+
| SanitizerSet::HWADDRESS,
28+
supports_xray: true,
29+
..base::linux_gnu::opts()
30+
};
31+
32+
// When we're asked to use the `rust-lld` linker by default, set the appropriate lld-using
33+
// linker flavor, and self-contained linker component.
34+
if option_env!("CFG_USE_SELF_CONTAINED_LINKER").is_some() {
35+
base.linker_flavor = LinkerFlavor::Gnu(Cc::Yes, Lld::Yes);
36+
base.link_self_contained = crate::spec::LinkSelfContainedDefault::with_linker();
37+
}
38+
639
Target {
740
llvm_target: "aarch64-unknown-linux-gnu".into(),
841
metadata: TargetMetadata {
@@ -14,25 +47,6 @@ pub(crate) fn target() -> Target {
1447
pointer_width: 64,
1548
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
1649
arch: "aarch64".into(),
17-
options: TargetOptions {
18-
features: "+v8a,+outline-atomics".into(),
19-
// the AAPCS64 expects use of non-leaf frame pointers per
20-
// https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
21-
// and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
22-
frame_pointer: FramePointer::NonLeaf,
23-
mcount: "\u{1}_mcount".into(),
24-
max_atomic_width: Some(128),
25-
stack_probes: StackProbeType::Inline,
26-
supported_sanitizers: SanitizerSet::ADDRESS
27-
| SanitizerSet::CFI
28-
| SanitizerSet::KCFI
29-
| SanitizerSet::LEAK
30-
| SanitizerSet::MEMORY
31-
| SanitizerSet::MEMTAG
32-
| SanitizerSet::THREAD
33-
| SanitizerSet::HWADDRESS,
34-
supports_xray: true,
35-
..base::linux_gnu::opts()
36-
},
50+
options: base,
3751
}
3852
}

ferrocene/tools/self-test/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pub(crate) enum Error {
3737
BinaryVersionMismatch { binary: String, field: String, expected: String, found: String },
3838
#[error("library {library} is missing from target {target}")]
3939
TargetLibraryMissing { target: String, library: String },
40+
#[error("default link arg {link_arg} is missing from target {target}")]
41+
TargetDefaultLinkArgMissing { target: String, link_arg: String },
4042
#[error("there are conflicting copies of library {library} for target {target}")]
4143
DuplicateTargetLibrary { target: String, library: String },
4244
#[error("failed to access {} while discovering target libraries", path.display())]
@@ -128,6 +130,7 @@ impl Error {
128130
Error::WrongLinkerArgs { .. } => 24,
129131
Error::RunningSampleProgramFailed { .. } => 25,
130132
Error::SampleProgramOutputWrong { .. } => 26,
133+
Error::TargetDefaultLinkArgMissing { .. } => 27,
131134
}
132135
}
133136

ferrocene/tools/self-test/src/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22
// SPDX-FileCopyrightText: The Ferrocene Developers
3-
43
mod binaries;
54
mod compile;
65
mod env;

ferrocene/tools/self-test/src/targets.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
use std::collections::{HashMap, HashSet};
55
use std::ops::Deref;
66
use std::path::Path;
7+
use std::process::Command;
78

89
use crate::error::Error;
910
use crate::linkers::Linker;
1011
use crate::report::Reporter;
12+
use crate::utils::run_command;
1113

1214
static SUPPORTED_TARGETS: &[TargetSpec] = &[
1315
// Targets with architecture specific tuning
@@ -127,11 +129,52 @@ fn check_target(
127129
false => ["core", "alloc"].as_slice(),
128130
};
129131
check_libraries(target, &target_dir, expected_libs)?;
132+
check_default_link_args(sysroot, target)?;
130133

131134
reporter.success(&format!("target installed correctly: {}", target.tuple));
132135
Ok(CheckTargetOutcome::Found)
133136
}
134137

138+
/// Check if the default link args for the target are what is expected
139+
fn check_default_link_args(sysroot: &Path, target: &TargetSpec) -> Result<(), Error> {
140+
match target.linker {
141+
Linker::HostCc => (),
142+
Linker::BundledLld | Linker::CrossCc(_) => return Ok(()), // No default link args expected
143+
}
144+
145+
let rustc = sysroot.join("bin").join("rustc");
146+
let temp_dir = tempfile::tempdir()
147+
.map_err(|error| Error::TemporaryCompilationDirectoryCreationFailed { error })?;
148+
let temp_main = temp_dir.path().join("main.rs");
149+
std::fs::write(&temp_main, "fn main() {}").map_err(|error| {
150+
Error::WritingSampleProgramFailed {
151+
name: "link_arg_example".into(),
152+
dest: temp_main.clone(),
153+
error,
154+
}
155+
})?;
156+
157+
let mut command = Command::new(rustc);
158+
command.arg("--target");
159+
command.arg(target.tuple);
160+
command.arg("--print");
161+
command.arg("link-args");
162+
command.arg(temp_main);
163+
let output = run_command(&mut command)
164+
.map_err(|error| Error::sample_program_compilation_failed("link-args", error))?;
165+
166+
// All our `HostCc` targets require `-fuse-ld=lld` to be passed
167+
let fuse_ld_arg = "-fuse-ld=lld";
168+
if !output.stdout.contains(fuse_ld_arg) {
169+
Err(Error::TargetDefaultLinkArgMissing {
170+
target: target.tuple.into(),
171+
link_arg: fuse_ld_arg.into(),
172+
})
173+
} else {
174+
Ok(())
175+
}
176+
}
177+
135178
#[derive(Debug, PartialEq, Eq)]
136179
enum CheckTargetOutcome {
137180
Missing,
@@ -210,13 +253,48 @@ mod tests {
210253
.lib("other", "0123456789abcdef") // Unknown libraries are ignored
211254
.create();
212255

256+
let _bin = utils
257+
.bin("rustc")
258+
.expected_args(&["--target", tuple, "--print", "link-args"])
259+
.expected_args_strict(false)
260+
.stdout("-fuse-ld=lld")
261+
.create();
262+
213263
assert_eq!(
214264
CheckTargetOutcome::Found,
215265
check_target(utils.reporter(), utils.sysroot(), &target).unwrap()
216266
);
217267
utils.assert_report_success("target installed correctly: x86_64-unknown-linux-gnu");
218268
}
219269

270+
#[cfg(all(target_os = "linux", target_arch = "x86_64"))] // Only on x86_64 Linux since the test is specific to that.
271+
#[test]
272+
#[should_panic]
273+
fn test_check_target_std_fails_if_lld_not_used() {
274+
let tuple = "x86_64-unknown-linux-gnu";
275+
let target = TargetSpec { tuple, std: true, linker: Linker::HostCc };
276+
277+
let utils = TestUtils::new();
278+
utils
279+
.target(tuple)
280+
.lib("core", "0123456789abcdef")
281+
.lib("alloc", "0123456789abcdef")
282+
.lib("std", "0123456789abcdef")
283+
.lib("test", "0123456789abcdef")
284+
.lib("proc_macro", "0123456789abcdef")
285+
.lib("other", "0123456789abcdef") // Unknown libraries are ignored
286+
.create();
287+
288+
let _bin = utils
289+
.bin("rustc")
290+
.expected_args(&["--target", tuple, "--print", "link-args"])
291+
.expected_args_strict(false)
292+
.stdout("-fuse-ld=not-lld-this-should-fail")
293+
.create();
294+
295+
check_target(utils.reporter(), utils.sysroot(), &target).unwrap(); // Panic!
296+
}
297+
220298
#[test]
221299
fn test_check_target_no_std() {
222300
let tuple = "x86_64-unknown-none";
@@ -362,4 +440,29 @@ mod tests {
362440
assert_fail("libcore-0123456789abcdef.so"); // Different extension
363441
assert_fail("libcore-0123456789abcdef"); // No extension
364442
}
443+
444+
fn check_target_default_link_args(tuple: &'static str) -> Result<(), Error> {
445+
let target = TargetSpec { tuple, std: true, linker: Linker::HostCc };
446+
447+
let utils = TestUtils::new();
448+
let _bin = utils
449+
.bin("rustc")
450+
.expected_args(&["--target", tuple, "--print", "link-args"])
451+
.expected_args_strict(false)
452+
.stdout("-fuse-ld=lld")
453+
.create();
454+
check_default_link_args(utils.sysroot(), &target)
455+
}
456+
457+
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
458+
#[test]
459+
fn test_check_target_default_link_args_x86_64() -> Result<(), Error> {
460+
check_target_default_link_args("x86_64-unknown-linux-gnu")
461+
}
462+
463+
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
464+
#[test]
465+
fn test_check_target_default_link_args_x86_64() -> Result<(), Error> {
466+
check_target_default_link_args("aarch64-unknown-linux-gnu")
467+
}
365468
}

ferrocene/tools/self-test/src/test_utils/bin_builder.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ pub(crate) struct BinBuilder<'a> {
2121
stderr: Option<String>,
2222
exit: Option<i32>,
2323
expected_args: Option<&'a [&'a str]>,
24+
/// If true test that all expected args and no additional ones are present.
25+
/// If false only check expected args are present and in order,
26+
/// but there can be additional arguments before, between, or after.
27+
expected_args_strict: bool,
2428
dest: BinaryDestination,
2529
program: &'static str,
2630
}
@@ -36,6 +40,7 @@ impl<'a> BinBuilder<'a> {
3640
stderr: None,
3741
exit: None,
3842
expected_args: None,
43+
expected_args_strict: true,
3944
dest: BinaryDestination::Sysroot,
4045
program: BIN_PROGRAM,
4146
}
@@ -91,6 +96,11 @@ impl<'a> BinBuilder<'a> {
9196
self
9297
}
9398

99+
pub(crate) fn expected_args_strict(mut self, strict: bool) -> Self {
100+
self.expected_args_strict = strict;
101+
self
102+
}
103+
94104
pub(crate) fn program_source(mut self, source: &'static str) -> Self {
95105
self.program = source;
96106
self
@@ -134,11 +144,13 @@ impl<'a> BinBuilder<'a> {
134144
if let Some(expected_args) = self.expected_args {
135145
rustc.env("EXPECTED_ARGS", expected_args.join("\t"));
136146
}
147+
rustc.env("EXPECTED_ARGS_STRICT", self.expected_args_strict.to_string());
137148

138149
let mut rustc = rustc.spawn().unwrap();
139150
let stdin = rustc.stdin.as_mut().unwrap();
140151
stdin.write_all(self.program.as_bytes()).unwrap();
141-
assert!(rustc.wait().unwrap().success());
152+
let res = rustc.wait_with_output().unwrap();
153+
assert!(res.status.success(), "stdout: \n{}", String::from_utf8_lossy(&res.stdout));
142154

143155
#[cfg(not(windows))]
144156
if let Some(mode) = self.mode {
@@ -160,8 +172,20 @@ const BIN_PROGRAM: &str = r#"
160172
fn main() {
161173
if let Some(expected_args) = option_env!("EXPECTED_ARGS") {
162174
let expected = expected_args.split("\t").collect::<Vec<_>>();
163-
let found = std::env::args().skip(1).collect::<Vec<_>>();
164-
assert_eq!(expected, found);
175+
let mut found = std::env::args().skip(1).collect::<Vec<_>>();
176+
if Some("true") == option_env!("EXPECTED_ARGS_STRICT") {
177+
assert_eq!(expected, found);
178+
} else {
179+
// Validate each of the args is present in the order provided,
180+
// ignore the rest.
181+
for item in expected {
182+
let val = found.iter().enumerate().find(|(_, v)| *v == &item.to_string());
183+
assert!(val.is_some(), "Did not find argument");
184+
// Get rid of all the previous args so that we can validate the expected
185+
// args are in-order.
186+
found = found.split_off(val.unwrap().0);
187+
}
188+
}
165189
}
166190
if let Some(stdout) = option_env!("OVERRIDE_STDOUT") {
167191
print!("{stdout}");

library/core/src/clone.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,8 @@ mod impls {
624624
#[stable(feature = "rust1", since = "1.0.0")]
625625
impl<T: PointeeSized> Clone for *const T {
626626
#[inline(always)]
627+
// Ferrocene annotation: This function is thoroughly tested inside the `test_clone`
628+
// test in `coretests`. It is unclear why this particular line is marked as uncovered.
627629
fn clone(&self) -> Self {
628630
*self
629631
}
@@ -632,6 +634,8 @@ mod impls {
632634
#[stable(feature = "rust1", since = "1.0.0")]
633635
impl<T: PointeeSized> Clone for *mut T {
634636
#[inline(always)]
637+
// Ferrocene annotation: This function is thoroughly tested inside the `test_clone`
638+
// test in `coretests`. It is unclear why this particular line is marked as uncovered.
635639
fn clone(&self) -> Self {
636640
*self
637641
}

library/core/src/intrinsics/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2580,6 +2580,7 @@ pub(crate) macro const_eval_select {
25802580
}
25812581

25822582
$(#[$compiletime_attr])*
2583+
// Ferrocene annotation: Cannot be covered as this only runs during compilation.
25832584
const fn compiletime$(<$($binders)*>)?($($arg: $ty),*) $( -> $ret )? {
25842585
// Don't warn if one of the arguments is unused.
25852586
$(let _ = $arg;)*
@@ -2738,6 +2739,8 @@ pub const unsafe fn typed_swap_nonoverlapping<T>(x: *mut T, y: *mut T) {
27382739
#[rustc_intrinsic_const_stable_indirect] // just for UB checks
27392740
#[inline(always)]
27402741
#[rustc_intrinsic]
2742+
// Ferrocene annotation: This function is always used in `assert_unsafe_precondition` which produces
2743+
// an unwinding panic, meaning that we cannot cover it.
27412744
pub const fn ub_checks() -> bool {
27422745
cfg!(ub_checks)
27432746
}
@@ -2785,6 +2788,8 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize)
27852788
#[rustc_nounwind]
27862789
#[rustc_intrinsic]
27872790
#[miri::intrinsic_fallback_is_spec]
2791+
// Ferrocene annotation: This function is only used as part of the `ThinBox` inner implementation.
2792+
// It is also a noop in runtime so we can't cover it currently.
27882793
pub const unsafe fn const_make_global(ptr: *mut u8) -> *const u8 {
27892794
// const eval overrides this function; at runtime, it is a NOP.
27902795
ptr

library/core/src/ops/drop.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,5 +237,7 @@ pub const trait Drop {
237237
/// [`mem::drop`]: drop
238238
/// [`ptr::drop_in_place`]: crate::ptr::drop_in_place
239239
#[stable(feature = "rust1", since = "1.0.0")]
240+
// Ferrocene annotation: This method declaration has no code to be covered, the fact that this
241+
// shows up as uncovered is a bug in our coverage tooling.
240242
fn drop(&mut self);
241243
}

library/core/src/option.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,10 @@ impl<T> Option<T> {
12031203
F: [const] FnOnce(&T) + [const] Destruct,
12041204
{
12051205
if let Some(ref x) = self {
1206+
// Ferrocene annotation: This function is thoroughly tested inside the `option_methods`
1207+
// test in `coretests`. Additionally, the `inspect_option` test guarantees that `f` is
1208+
// being called by panicking inside the `predicate` body and marking the test as
1209+
// `#[should_panic]`.
12061210
f(x);
12071211
}
12081212

@@ -1591,6 +1595,10 @@ impl<T> Option<T> {
15911595
T: [const] Destruct,
15921596
{
15931597
if let Some(x) = self {
1598+
// Ferrocene annotation: This function is thoroughly tested inside the `option_methods`
1599+
// test in `coretests`. Additionally, the `filter_option` test guarantees that
1600+
// `predicate` is being called by panicking inside the `predicate` body and marking the
1601+
// test as `#[should_panic]`.
15941602
if predicate(&x) {
15951603
return Some(x);
15961604
}

0 commit comments

Comments
 (0)