Skip to content

Commit c8dff28

Browse files
committedSep 17, 2024
Auto merge of #130456 - matthiaskrgr:rollup-h2qvk1f, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - #130380 (coverage: Clarify some parts of coverage counter creation) - #130427 (run_make_support: rectify symlink handling) - #130447 (rustc_llvm: update for llvm/llvm-project@2ae968a0d9fb61606b020e898d88…) - #130448 (fix: Remove duplicate `LazyLock` example.) r? `@ghost` `@rustbot` modify labels: rollup
·
1.88.01.83.0
2 parents e2dc1a1 + 558b302 commit c8dff28

File tree

10 files changed

+334
-235
lines changed

10 files changed

+334
-235
lines changed
 

‎compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "llvm/Target/TargetMachine.h"
2626
#include "llvm/Target/TargetOptions.h"
2727
#include "llvm/Transforms/IPO.h"
28-
#include "llvm/Transforms/Instrumentation.h"
2928
#include "llvm/Transforms/Scalar.h"
3029

3130
#define LLVM_VERSION_GE(major, minor) \
@@ -34,6 +33,12 @@
3433

3534
#define LLVM_VERSION_LT(major, minor) (!LLVM_VERSION_GE((major), (minor)))
3635

36+
#if LLVM_VERSION_GE(20, 0)
37+
#include "llvm/Transforms/Utils/Instrumentation.h"
38+
#else
39+
#include "llvm/Transforms/Instrumentation.h"
40+
#endif
41+
3742
#include "llvm/IR/LegacyPassManager.h"
3843

3944
#include "llvm/Bitcode/BitcodeReader.h"

‎compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
#include "llvm/TargetParser/Host.h"
4040
#endif
4141
#include "llvm/Support/TimeProfiler.h"
42-
#include "llvm/Transforms/Instrumentation.h"
4342
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
4443
#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
4544
#if LLVM_VERSION_GE(19, 0)

‎compiler/rustc_mir_transform/src/coverage/counters.rs

Lines changed: 109 additions & 122 deletions
Large diffs are not rendered by default.

‎compiler/rustc_mir_transform/src/coverage/graph.rs

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,11 @@ impl CoverageGraph {
8787
for &bb in basic_blocks.iter() {
8888
bb_to_bcb[bb] = Some(bcb);
8989
}
90-
let bcb_data = BasicCoverageBlockData::from(basic_blocks);
90+
91+
let is_out_summable = basic_blocks.last().map_or(false, |&bb| {
92+
bcb_filtered_successors(mir_body[bb].terminator()).is_out_summable()
93+
});
94+
let bcb_data = BasicCoverageBlockData { basic_blocks, is_out_summable };
9195
debug!("adding bcb{}: {:?}", bcb.index(), bcb_data);
9296
bcbs.push(bcb_data);
9397
};
@@ -161,23 +165,33 @@ impl CoverageGraph {
161165
self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b)
162166
}
163167

164-
/// Returns true if the given node has 2 or more in-edges, i.e. 2 or more
165-
/// predecessors.
166-
///
167-
/// This property is interesting to code that assigns counters to nodes and
168-
/// edges, because if a node _doesn't_ have multiple in-edges, then there's
169-
/// no benefit in having a separate counter for its in-edge, because it
170-
/// would have the same value as the node's own counter.
171-
///
172-
/// FIXME: That assumption might not be true for [`TerminatorKind::Yield`]?
173-
#[inline(always)]
174-
pub(crate) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool {
175-
// Even though bcb0 conceptually has an extra virtual in-edge due to
176-
// being the entry point, we've already asserted that it has no _other_
177-
// in-edges, so there's no possibility of it having _multiple_ in-edges.
178-
// (And since its virtual in-edge doesn't exist in the graph, that edge
179-
// can't have a separate counter anyway.)
180-
self.predecessors[bcb].len() > 1
168+
/// Returns the source of this node's sole in-edge, if it has exactly one.
169+
/// That edge can be assumed to have the same execution count as the node
170+
/// itself (in the absence of panics).
171+
pub(crate) fn sole_predecessor(
172+
&self,
173+
to_bcb: BasicCoverageBlock,
174+
) -> Option<BasicCoverageBlock> {
175+
// Unlike `simple_successor`, there is no need for extra checks here.
176+
if let &[from_bcb] = self.predecessors[to_bcb].as_slice() { Some(from_bcb) } else { None }
177+
}
178+
179+
/// Returns the target of this node's sole out-edge, if it has exactly
180+
/// one, but only if that edge can be assumed to have the same execution
181+
/// count as the node itself (in the absence of panics).
182+
pub(crate) fn simple_successor(
183+
&self,
184+
from_bcb: BasicCoverageBlock,
185+
) -> Option<BasicCoverageBlock> {
186+
// If a node's count is the sum of its out-edges, and it has exactly
187+
// one out-edge, then that edge has the same count as the node.
188+
if self.bcbs[from_bcb].is_out_summable
189+
&& let &[to_bcb] = self.successors[from_bcb].as_slice()
190+
{
191+
Some(to_bcb)
192+
} else {
193+
None
194+
}
181195
}
182196
}
183197

@@ -266,14 +280,16 @@ rustc_index::newtype_index! {
266280
#[derive(Debug, Clone)]
267281
pub(crate) struct BasicCoverageBlockData {
268282
pub(crate) basic_blocks: Vec<BasicBlock>,
283+
284+
/// If true, this node's execution count can be assumed to be the sum of the
285+
/// execution counts of all of its **out-edges** (assuming no panics).
286+
///
287+
/// Notably, this is false for a node ending with [`TerminatorKind::Yield`],
288+
/// because the yielding coroutine might not be resumed.
289+
pub(crate) is_out_summable: bool,
269290
}
270291

271292
impl BasicCoverageBlockData {
272-
fn from(basic_blocks: Vec<BasicBlock>) -> Self {
273-
assert!(basic_blocks.len() > 0);
274-
Self { basic_blocks }
275-
}
276-
277293
#[inline(always)]
278294
pub(crate) fn leader_bb(&self) -> BasicBlock {
279295
self.basic_blocks[0]
@@ -295,13 +311,27 @@ enum CoverageSuccessors<'a> {
295311
Chainable(BasicBlock),
296312
/// The block cannot be combined into the same BCB as its successor(s).
297313
NotChainable(&'a [BasicBlock]),
314+
/// Yield terminators are not chainable, and their execution count can also
315+
/// differ from the execution count of their out-edge.
316+
Yield(BasicBlock),
298317
}
299318

300319
impl CoverageSuccessors<'_> {
301320
fn is_chainable(&self) -> bool {
302321
match self {
303322
Self::Chainable(_) => true,
304323
Self::NotChainable(_) => false,
324+
Self::Yield(_) => false,
325+
}
326+
}
327+
328+
/// Returns true if the terminator itself is assumed to have the same
329+
/// execution count as the sum of its out-edges (assuming no panics).
330+
fn is_out_summable(&self) -> bool {
331+
match self {
332+
Self::Chainable(_) => true,
333+
Self::NotChainable(_) => true,
334+
Self::Yield(_) => false,
305335
}
306336
}
307337
}
@@ -312,7 +342,9 @@ impl IntoIterator for CoverageSuccessors<'_> {
312342

313343
fn into_iter(self) -> Self::IntoIter {
314344
match self {
315-
Self::Chainable(bb) => Some(bb).into_iter().chain((&[]).iter().copied()),
345+
Self::Chainable(bb) | Self::Yield(bb) => {
346+
Some(bb).into_iter().chain((&[]).iter().copied())
347+
}
316348
Self::NotChainable(bbs) => None.into_iter().chain(bbs.iter().copied()),
317349
}
318350
}
@@ -331,7 +363,7 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
331363

332364
// A yield terminator has exactly 1 successor, but should not be chained,
333365
// because its resume edge has a different execution count.
334-
Yield { ref resume, .. } => CoverageSuccessors::NotChainable(std::slice::from_ref(resume)),
366+
Yield { resume, .. } => CoverageSuccessors::Yield(resume),
335367

336368
// These terminators have exactly one coverage-relevant successor,
337369
// and can be chained into it.
@@ -341,15 +373,15 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
341373
| FalseUnwind { real_target: target, .. }
342374
| Goto { target } => CoverageSuccessors::Chainable(target),
343375

344-
// A call terminator can normally be chained, except when they have no
345-
// successor because they are known to diverge.
376+
// A call terminator can normally be chained, except when it has no
377+
// successor because it is known to diverge.
346378
Call { target: maybe_target, .. } => match maybe_target {
347379
Some(target) => CoverageSuccessors::Chainable(target),
348380
None => CoverageSuccessors::NotChainable(&[]),
349381
},
350382

351-
// An inline asm terminator can normally be chained, except when it diverges or uses asm
352-
// goto.
383+
// An inline asm terminator can normally be chained, except when it
384+
// diverges or uses asm goto.
353385
InlineAsm { ref targets, .. } => {
354386
if let [target] = targets[..] {
355387
CoverageSuccessors::Chainable(target)

‎library/std/src/sync/lazy_lock.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ union Data<T, F> {
4444
///
4545
/// // The `String` is built, stored in the `LazyLock`, and returned as `&String`.
4646
/// let _ = &*DEEP_THOUGHT;
47-
/// // The `String` is retrieved from the `LazyLock` and returned as `&String`.
48-
/// let _ = &*DEEP_THOUGHT;
4947
/// ```
5048
///
5149
/// Initialize fields with `LazyLock`.

‎src/tools/run-make-support/src/fs.rs

Lines changed: 130 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,6 @@
11
use std::io;
22
use std::path::{Path, PathBuf};
33

4-
// FIXME(jieyouxu): modify create_symlink to panic on windows.
5-
6-
/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
7-
#[cfg(target_family = "windows")]
8-
pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
9-
if link.as_ref().exists() {
10-
std::fs::remove_dir(link.as_ref()).unwrap();
11-
}
12-
if original.as_ref().is_file() {
13-
std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
14-
"failed to create symlink {:?} for {:?}",
15-
link.as_ref().display(),
16-
original.as_ref().display(),
17-
));
18-
} else {
19-
std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()).expect(&format!(
20-
"failed to create symlink {:?} for {:?}",
21-
link.as_ref().display(),
22-
original.as_ref().display(),
23-
));
24-
}
25-
}
26-
27-
/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
28-
#[cfg(target_family = "unix")]
29-
pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
30-
if link.as_ref().exists() {
31-
std::fs::remove_dir(link.as_ref()).unwrap();
32-
}
33-
std::os::unix::fs::symlink(original.as_ref(), link.as_ref()).expect(&format!(
34-
"failed to create symlink {:?} for {:?}",
35-
link.as_ref().display(),
36-
original.as_ref().display(),
37-
));
38-
}
39-
404
/// Copy a directory into another.
415
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
426
fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
@@ -50,7 +14,31 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
5014
if ty.is_dir() {
5115
copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
5216
} else if ty.is_symlink() {
53-
copy_symlink(entry.path(), dst.join(entry.file_name()))?;
17+
// Traverse symlink once to find path of target entity.
18+
let target_path = std::fs::read_link(entry.path())?;
19+
20+
let new_symlink_path = dst.join(entry.file_name());
21+
#[cfg(windows)]
22+
{
23+
use std::os::windows::fs::FileTypeExt;
24+
if ty.is_symlink_dir() {
25+
std::os::windows::fs::symlink_dir(&target_path, new_symlink_path)?;
26+
} else {
27+
// Target may be a file or another symlink, in any case we can use
28+
// `symlink_file` here.
29+
std::os::windows::fs::symlink_file(&target_path, new_symlink_path)?;
30+
}
31+
}
32+
#[cfg(unix)]
33+
{
34+
std::os::unix::fs::symlink(target_path, new_symlink_path)?;
35+
}
36+
#[cfg(not(any(windows, unix)))]
37+
{
38+
// Technically there's also wasi, but I have no clue about wasi symlink
39+
// semantics and which wasi targets / environment support symlinks.
40+
unimplemented!("unsupported target");
41+
}
5442
} else {
5543
std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
5644
}
@@ -69,12 +57,6 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
6957
}
7058
}
7159

72-
fn copy_symlink<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
73-
let target_path = std::fs::read_link(from).unwrap();
74-
create_symlink(target_path, to);
75-
Ok(())
76-
}
77-
7860
/// Helper for reading entries in a given directory.
7961
pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) {
8062
for entry in read_dir(dir) {
@@ -85,8 +67,17 @@ pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F
8567
/// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message.
8668
#[track_caller]
8769
pub fn remove_file<P: AsRef<Path>>(path: P) {
88-
std::fs::remove_file(path.as_ref())
89-
.expect(&format!("the file in path \"{}\" could not be removed", path.as_ref().display()));
70+
if let Err(e) = std::fs::remove_file(path.as_ref()) {
71+
panic!("failed to remove file at `{}`: {e}", path.as_ref().display());
72+
}
73+
}
74+
75+
/// A wrapper around [`std::fs::remove_dir`] which includes the directory path in the panic message.
76+
#[track_caller]
77+
pub fn remove_dir<P: AsRef<Path>>(path: P) {
78+
if let Err(e) = std::fs::remove_dir(path.as_ref()) {
79+
panic!("failed to remove directory at `{}`: {e}", path.as_ref().display());
80+
}
9081
}
9182

9283
/// A wrapper around [`std::fs::copy`] which includes the file path in the panic message.
@@ -165,13 +156,32 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) {
165156
));
166157
}
167158

168-
/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message.
159+
/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message. Note
160+
/// that this will traverse symlinks and will return metadata about the target file. Use
161+
/// [`symlink_metadata`] if you don't want to traverse symlinks.
162+
///
163+
/// See [`std::fs::metadata`] docs for more details.
169164
#[track_caller]
170165
pub fn metadata<P: AsRef<Path>>(path: P) -> std::fs::Metadata {
171-
std::fs::metadata(path.as_ref()).expect(&format!(
172-
"the file's metadata in path \"{}\" could not be read",
173-
path.as_ref().display()
174-
))
166+
match std::fs::metadata(path.as_ref()) {
167+
Ok(m) => m,
168+
Err(e) => panic!("failed to read file metadata at `{}`: {e}", path.as_ref().display()),
169+
}
170+
}
171+
172+
/// A wrapper around [`std::fs::symlink_metadata`] which includes the file path in the panic
173+
/// message. Note that this will not traverse symlinks and will return metadata about the filesystem
174+
/// entity itself. Use [`metadata`] if you want to traverse symlinks.
175+
///
176+
/// See [`std::fs::symlink_metadata`] docs for more details.
177+
#[track_caller]
178+
pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> std::fs::Metadata {
179+
match std::fs::symlink_metadata(path.as_ref()) {
180+
Ok(m) => m,
181+
Err(e) => {
182+
panic!("failed to read file metadata (shallow) at `{}`: {e}", path.as_ref().display())
183+
}
184+
}
175185
}
176186

177187
/// A wrapper around [`std::fs::rename`] which includes the file path in the panic message.
@@ -205,3 +215,73 @@ pub fn shallow_find_dir_entries<P: AsRef<Path>>(dir: P) -> Vec<PathBuf> {
205215
}
206216
output
207217
}
218+
219+
/// Create a new symbolic link to a directory.
220+
///
221+
/// # Removing the symlink
222+
///
223+
/// - On Windows, a symlink-to-directory needs to be removed with a corresponding [`fs::remove_dir`]
224+
/// and not [`fs::remove_file`].
225+
/// - On Unix, remove the symlink with [`fs::remove_file`].
226+
///
227+
/// [`fs::remove_dir`]: crate::fs::remove_dir
228+
/// [`fs::remove_file`]: crate::fs::remove_file
229+
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
230+
#[cfg(unix)]
231+
{
232+
if let Err(e) = std::os::unix::fs::symlink(original.as_ref(), link.as_ref()) {
233+
panic!(
234+
"failed to create symlink: original=`{}`, link=`{}`: {e}",
235+
original.as_ref().display(),
236+
link.as_ref().display()
237+
);
238+
}
239+
}
240+
#[cfg(windows)]
241+
{
242+
if let Err(e) = std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()) {
243+
panic!(
244+
"failed to create symlink-to-directory: original=`{}`, link=`{}`: {e}",
245+
original.as_ref().display(),
246+
link.as_ref().display()
247+
);
248+
}
249+
}
250+
#[cfg(not(any(windows, unix)))]
251+
{
252+
unimplemented!("target family not currently supported")
253+
}
254+
}
255+
256+
/// Create a new symbolic link to a file.
257+
///
258+
/// # Removing the symlink
259+
///
260+
/// On both Windows and Unix, a symlink-to-file needs to be removed with a corresponding
261+
/// [`fs::remove_file`](crate::fs::remove_file) and not [`fs::remove_dir`](crate::fs::remove_dir).
262+
pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
263+
#[cfg(unix)]
264+
{
265+
if let Err(e) = std::os::unix::fs::symlink(original.as_ref(), link.as_ref()) {
266+
panic!(
267+
"failed to create symlink: original=`{}`, link=`{}`: {e}",
268+
original.as_ref().display(),
269+
link.as_ref().display()
270+
);
271+
}
272+
}
273+
#[cfg(windows)]
274+
{
275+
if let Err(e) = std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()) {
276+
panic!(
277+
"failed to create symlink-to-file: original=`{}`, link=`{}`: {e}",
278+
original.as_ref().display(),
279+
link.as_ref().display()
280+
);
281+
}
282+
}
283+
#[cfg(not(any(windows, unix)))]
284+
{
285+
unimplemented!("target family not currently supported")
286+
}
287+
}

‎tests/run-make/invalid-symlink-search-path/rmake.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
// In this test, the symlink created is invalid (valid relative to the root, but not
2-
// relatively to where it is located), and used to cause an internal
3-
// compiler error (ICE) when passed as a library search path. This was fixed in #26044,
4-
// and this test checks that the invalid symlink is instead simply ignored.
1+
// In this test, the symlink created is invalid (valid relative to the root, but not relatively to
2+
// where it is located), and used to cause an internal compiler error (ICE) when passed as a library
3+
// search path. This was fixed in #26044, and this test checks that the invalid symlink is instead
4+
// simply ignored.
5+
//
56
// See https://github.com/rust-lang/rust/issues/26006
67

78
//@ needs-symlink
89
//Reason: symlink requires elevated permission in Windows
910

10-
use run_make_support::{rfs, rustc};
11+
use run_make_support::{path, rfs, rustc};
1112

1213
fn main() {
1314
// We create two libs: `bar` which depends on `foo`. We need to compile `foo` first.
@@ -20,9 +21,9 @@ fn main() {
2021
.metadata("foo")
2122
.output("out/foo/libfoo.rlib")
2223
.run();
23-
rfs::create_dir("out/bar");
24-
rfs::create_dir("out/bar/deps");
25-
rfs::create_symlink("out/foo/libfoo.rlib", "out/bar/deps/libfoo.rlib");
24+
rfs::create_dir_all("out/bar/deps");
25+
rfs::symlink_file(path("out/foo/libfoo.rlib"), path("out/bar/deps/libfoo.rlib"));
26+
2627
// Check that the invalid symlink does not cause an ICE
2728
rustc()
2829
.input("in/bar/lib.rs")
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
// Crates that are resolved normally have their path canonicalized and all
2-
// symlinks resolved. This did not happen for paths specified
3-
// using the --extern option to rustc, which could lead to rustc thinking
4-
// that it encountered two different versions of a crate, when it's
5-
// actually the same version found through different paths.
6-
// See https://github.com/rust-lang/rust/pull/16505
7-
8-
// This test checks that --extern and symlinks together
9-
// can result in successful compilation.
1+
// Crates that are resolved normally have their path canonicalized and all symlinks resolved. This
2+
// did not happen for paths specified using the `--extern` option to rustc, which could lead to
3+
// rustc thinking that it encountered two different versions of a crate, when it's actually the same
4+
// version found through different paths.
5+
//
6+
// This test checks that `--extern` and symlinks together can result in successful compilation.
7+
//
8+
// See <https://github.com/rust-lang/rust/pull/16505>.
109

1110
//@ ignore-cross-compile
1211
//@ needs-symlink
1312

14-
use run_make_support::{cwd, rfs, rustc};
13+
use run_make_support::{cwd, path, rfs, rustc};
1514

1615
fn main() {
1716
rustc().input("foo.rs").run();
1817
rfs::create_dir_all("other");
19-
rfs::create_symlink("libfoo.rlib", "other");
18+
rfs::symlink_file(path("libfoo.rlib"), path("other").join("libfoo.rlib"));
19+
2020
rustc().input("bar.rs").library_search_path(cwd()).run();
21-
rustc().input("baz.rs").extern_("foo", "other").library_search_path(cwd()).run();
21+
rustc().input("baz.rs").extern_("foo", "other/libfoo.rlib").library_search_path(cwd()).run();
2222
}
Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
// When a directory and a symlink simultaneously exist with the same name,
2-
// setting that name as the library search path should not cause rustc
3-
// to avoid looking in the symlink and cause an error. This test creates
4-
// a directory and a symlink named "other", and places the library in the symlink.
5-
// If it succeeds, the library was successfully found.
6-
// See https://github.com/rust-lang/rust/issues/12459
1+
// Avoid erroring on symlinks pointing to the same file that are present in the library search path.
2+
//
3+
// See <https://github.com/rust-lang/rust/issues/12459>.
74

85
//@ ignore-cross-compile
96
//@ needs-symlink
107

11-
use run_make_support::{dynamic_lib_name, rfs, rustc};
8+
use run_make_support::{cwd, dynamic_lib_name, path, rfs, rustc};
129

1310
fn main() {
1411
rustc().input("foo.rs").arg("-Cprefer-dynamic").run();
1512
rfs::create_dir_all("other");
16-
rfs::create_symlink(dynamic_lib_name("foo"), "other");
17-
rustc().input("bar.rs").library_search_path("other").run();
13+
rfs::symlink_file(dynamic_lib_name("foo"), path("other").join(dynamic_lib_name("foo")));
14+
rustc().input("bar.rs").library_search_path(cwd()).library_search_path("other").run();
1815
}

‎tests/run-make/symlinked-rlib/rmake.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ use run_make_support::{cwd, rfs, rustc};
1212

1313
fn main() {
1414
rustc().input("foo.rs").crate_type("rlib").output("foo.xxx").run();
15-
rfs::create_symlink("foo.xxx", "libfoo.rlib");
15+
rfs::symlink_file("foo.xxx", "libfoo.rlib");
1616
rustc().input("bar.rs").library_search_path(cwd()).run();
1717
}

0 commit comments

Comments
 (0)
Please sign in to comment.