Auto merge of #131547 - matthiaskrgr:rollup-ui4p744, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #129079 (Create `_imp__` symbols also when doing ThinLTO) - #131208 (ABI: Pass aggregates by value on AIX) - #131394 (fix(rustdoc): add space between struct fields and their descriptions) - #131519 (Use Default visibility for rustc-generated C symbol declarations) - #131541 (compiletest: Extract auxiliary-crate properties to their own module/struct) - #131542 (next-solver: remove outdated FIXMEs) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
01e2fff90c
@ -84,10 +84,9 @@ pub(crate) fn declare_cfn(
|
||||
unnamed: llvm::UnnamedAddr,
|
||||
fn_type: &'ll Type,
|
||||
) -> &'ll Value {
|
||||
// Declare C ABI functions with the visibility used by C by default.
|
||||
let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
|
||||
|
||||
declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type)
|
||||
// Visibility should always be default for declarations, otherwise the linker may report an
|
||||
// error.
|
||||
declare_raw_fn(self, name, llvm::CCallConv, unnamed, Visibility::Default, fn_type)
|
||||
}
|
||||
|
||||
/// Declare an entry Function
|
||||
|
@ -2164,8 +2164,14 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
|
||||
&& tcx.sess.opts.cg.prefer_dynamic)
|
||||
);
|
||||
|
||||
// We need to generate _imp__ symbol if we are generating an rlib or we include one
|
||||
// indirectly from ThinLTO. In theory these are not needed as ThinLTO could resolve
|
||||
// these, but it currently does not do so.
|
||||
let can_have_static_objects =
|
||||
tcx.sess.lto() == Lto::Thin || tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib);
|
||||
|
||||
tcx.sess.target.is_like_windows &&
|
||||
tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
|
||||
can_have_static_objects &&
|
||||
// ThinLTO can't handle this workaround in all cases, so we don't
|
||||
// emit the `__imp_` symbols. Instead we make them unnecessary by disallowing
|
||||
// dynamic linking when linker plugin LTO is enabled.
|
||||
|
@ -444,7 +444,6 @@ pub fn instantiate_canonical_state<D, I, T: TypeFoldable<I>>(
|
||||
for &arg in &state.value.var_values.var_values.as_slice()
|
||||
[orig_values.len()..state.value.var_values.len()]
|
||||
{
|
||||
// FIXME: This is so ugly.
|
||||
let unconstrained = delegate.fresh_var_for_kind_with_span(arg, span);
|
||||
orig_values.push(unconstrained);
|
||||
}
|
||||
|
@ -92,7 +92,6 @@ pub struct EvalCtxt<'a, D, I = <D as SolverDelegate>::Interner>
|
||||
#[derive_where(Clone, Debug, Default; I: Interner)]
|
||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||
// FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate.
|
||||
struct NestedGoals<I: Interner> {
|
||||
/// These normalizes-to goals are treated specially during the evaluation
|
||||
/// loop. In each iteration we take the RHS of the projection, replace it with
|
||||
@ -421,6 +420,7 @@ pub(super) fn evaluate_goal_raw(
|
||||
let (normalization_nested_goals, certainty) =
|
||||
self.instantiate_and_apply_query_response(goal.param_env, orig_values, response);
|
||||
self.inspect.goal_evaluation(goal_evaluation);
|
||||
|
||||
// FIXME: We previously had an assert here that checked that recomputing
|
||||
// a goal after applying its constraints did not change its response.
|
||||
//
|
||||
|
@ -10,9 +10,6 @@
|
||||
//!
|
||||
//! For a high-level overview of how this solver works, check out the relevant
|
||||
//! section of the rustc-dev-guide.
|
||||
//!
|
||||
//! FIXME(@lcnr): Write that section. If you read this before then ask me
|
||||
//! about it on zulip.
|
||||
|
||||
mod alias_relate;
|
||||
mod assembly;
|
||||
|
@ -899,7 +899,7 @@ fn consider_builtin_effects_intersection_candidate(
|
||||
for ty in types.iter() {
|
||||
// We can't find the intersection if the types used are generic.
|
||||
//
|
||||
// FIXME(effects) do we want to look at where clauses to get some
|
||||
// FIXME(effects): do we want to look at where clauses to get some
|
||||
// clue for the case where generic types are being used?
|
||||
let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else {
|
||||
return Err(NoSolution);
|
||||
|
@ -108,7 +108,6 @@ fn consider_error_guaranteed_candidate(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
_guar: I::ErrorGuaranteed,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
// FIXME: don't need to enter a probe here.
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
@ -463,7 +462,6 @@ fn consider_builtin_future_candidate(
|
||||
// Async coroutine unconditionally implement `Future`
|
||||
// Technically, we need to check that the future output type is Sized,
|
||||
// but that's already proven by the coroutine being WF.
|
||||
// FIXME: use `consider_implied`
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
@ -489,7 +487,6 @@ fn consider_builtin_iterator_candidate(
|
||||
// Gen coroutines unconditionally implement `Iterator`
|
||||
// Technically, we need to check that the iterator output type is Sized,
|
||||
// but that's already proven by the coroutines being WF.
|
||||
// FIXME: use `consider_implied`
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
@ -512,8 +509,7 @@ fn consider_builtin_fused_iterator_candidate(
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// Gen coroutines unconditionally implement `FusedIterator`
|
||||
// FIXME: use `consider_implied`
|
||||
// Gen coroutines unconditionally implement `FusedIterator`.
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
@ -539,7 +535,6 @@ fn consider_builtin_async_iterator_candidate(
|
||||
// Gen coroutines unconditionally implement `Iterator`
|
||||
// Technically, we need to check that the iterator output type is Sized,
|
||||
// but that's already proven by the coroutines being WF.
|
||||
// FIXME: use `consider_implied`
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
@ -610,7 +605,7 @@ fn consider_builtin_destruct_candidate(
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// FIXME(-Znext-solver): Implement this when we get const working in the new solver
|
||||
// FIXME(effects): Implement this when we get const working in the new solver
|
||||
|
||||
// `Destruct` is automatically implemented for every type in
|
||||
// non-const environments.
|
||||
@ -631,8 +626,6 @@ fn consider_builtin_transmute_candidate(
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// FIXME: This actually should destructure the `Result` we get from transmutability and
|
||||
// register candidates. We probably need to register >1 since we may have an OR of ANDs.
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
let certainty = ecx.is_transmutable(
|
||||
goal.param_env,
|
||||
|
@ -10,6 +10,7 @@
|
||||
enum ABI {
|
||||
ELFv1, // original ABI used for powerpc64 (big-endian)
|
||||
ELFv2, // newer ABI used for powerpc64le and musl (both endians)
|
||||
AIX, // used by AIX OS, big-endian only
|
||||
}
|
||||
use ABI::*;
|
||||
|
||||
@ -23,9 +24,9 @@ fn is_homogeneous_aggregate<'a, Ty, C>(
|
||||
C: HasDataLayout,
|
||||
{
|
||||
arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
|
||||
// ELFv1 only passes one-member aggregates transparently.
|
||||
// ELFv1 and AIX only passes one-member aggregates transparently.
|
||||
// ELFv2 passes up to eight uniquely addressable members.
|
||||
if (abi == ELFv1 && arg.layout.size > unit.size)
|
||||
if ((abi == ELFv1 || abi == AIX) && arg.layout.size > unit.size)
|
||||
|| arg.layout.size > unit.size.checked_mul(8, cx).unwrap()
|
||||
{
|
||||
return None;
|
||||
@ -55,8 +56,15 @@ fn classify<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI, is_ret: bool)
|
||||
return;
|
||||
}
|
||||
|
||||
// The AIX ABI expect byval for aggregates
|
||||
// See https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/Targets/PPC.cpp.
|
||||
if !is_ret && abi == AIX {
|
||||
arg.pass_by_stack_offset(None);
|
||||
return;
|
||||
}
|
||||
|
||||
// The ELFv1 ABI doesn't return aggregates in registers
|
||||
if is_ret && abi == ELFv1 {
|
||||
if is_ret && (abi == ELFv1 || abi == AIX) {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
@ -93,6 +101,8 @@ pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
{
|
||||
let abi = if cx.target_spec().env == "musl" {
|
||||
ELFv2
|
||||
} else if cx.target_spec().os == "aix" {
|
||||
AIX
|
||||
} else {
|
||||
match cx.data_layout().endian {
|
||||
Endian::Big => ELFv1,
|
||||
|
@ -223,6 +223,8 @@ fn fetch_eligible_assoc_item(
|
||||
if eligible { Ok(Some(node_item.item.def_id)) } else { Ok(None) }
|
||||
}
|
||||
|
||||
// FIXME: This actually should destructure the `Result` we get from transmutability and
|
||||
// register candidates. We probably need to register >1 since we may have an OR of ANDs.
|
||||
fn is_transmutable(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
@ -230,6 +230,9 @@ h4.code-header {
|
||||
padding: 0;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.structfield {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
#crate-search,
|
||||
h1, h2, h3, h4, h5, h6,
|
||||
|
@ -9,11 +9,13 @@
|
||||
use tracing::*;
|
||||
|
||||
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
|
||||
use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
|
||||
use crate::header::cfg::{MatchOutcome, parse_cfg_name_directive};
|
||||
use crate::header::needs::CachedNeedsConditions;
|
||||
use crate::util::static_regex;
|
||||
use crate::{extract_cdb_version, extract_gdb_version};
|
||||
|
||||
pub(crate) mod auxiliary;
|
||||
mod cfg;
|
||||
mod needs;
|
||||
#[cfg(test)]
|
||||
@ -33,9 +35,10 @@ pub fn load(config: &Config) -> Self {
|
||||
/// the test.
|
||||
#[derive(Default)]
|
||||
pub struct EarlyProps {
|
||||
pub aux: Vec<String>,
|
||||
pub aux_bin: Vec<String>,
|
||||
pub aux_crate: Vec<(String, String)>,
|
||||
/// Auxiliary crates that should be built and made available to this test.
|
||||
/// Included in [`EarlyProps`] so that the indicated files can participate
|
||||
/// in up-to-date checking. Building happens via [`TestProps::aux`] instead.
|
||||
pub(crate) aux: AuxProps,
|
||||
pub revisions: Vec<String>,
|
||||
}
|
||||
|
||||
@ -55,21 +58,7 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
|
||||
testfile,
|
||||
rdr,
|
||||
&mut |HeaderLine { directive: ln, .. }| {
|
||||
config.push_name_value_directive(ln, directives::AUX_BUILD, &mut props.aux, |r| {
|
||||
r.trim().to_string()
|
||||
});
|
||||
config.push_name_value_directive(
|
||||
ln,
|
||||
directives::AUX_BIN,
|
||||
&mut props.aux_bin,
|
||||
|r| r.trim().to_string(),
|
||||
);
|
||||
config.push_name_value_directive(
|
||||
ln,
|
||||
directives::AUX_CRATE,
|
||||
&mut props.aux_crate,
|
||||
Config::parse_aux_crate,
|
||||
);
|
||||
parse_and_update_aux(config, ln, &mut props.aux);
|
||||
config.parse_and_update_revisions(ln, &mut props.revisions);
|
||||
},
|
||||
);
|
||||
@ -98,18 +87,8 @@ pub struct TestProps {
|
||||
// If present, the name of a file that this test should match when
|
||||
// pretty-printed
|
||||
pub pp_exact: Option<PathBuf>,
|
||||
// Other crates that should be compiled (typically from the same
|
||||
// directory as the test, but for backwards compatibility reasons
|
||||
// we also check the auxiliary directory)
|
||||
pub aux_builds: Vec<String>,
|
||||
// Auxiliary crates that should be compiled as `#![crate_type = "bin"]`.
|
||||
pub aux_bins: Vec<String>,
|
||||
// Similar to `aux_builds`, but a list of NAME=somelib.rs of dependencies
|
||||
// to build and pass with the `--extern` flag.
|
||||
pub aux_crates: Vec<(String, String)>,
|
||||
/// Similar to `aux_builds`, but also passes the resulting dylib path to
|
||||
/// `-Zcodegen-backend`.
|
||||
pub aux_codegen_backend: Option<String>,
|
||||
/// Auxiliary crates that should be built and made available to this test.
|
||||
pub(crate) aux: AuxProps,
|
||||
// Environment settings to use for compiling
|
||||
pub rustc_env: Vec<(String, String)>,
|
||||
// Environment variables to unset prior to compiling.
|
||||
@ -276,10 +255,7 @@ pub fn new() -> Self {
|
||||
run_flags: vec![],
|
||||
doc_flags: vec![],
|
||||
pp_exact: None,
|
||||
aux_builds: vec![],
|
||||
aux_bins: vec![],
|
||||
aux_crates: vec![],
|
||||
aux_codegen_backend: None,
|
||||
aux: Default::default(),
|
||||
revisions: vec![],
|
||||
rustc_env: vec![
|
||||
("RUSTC_ICE".to_string(), "0".to_string()),
|
||||
@ -454,21 +430,10 @@ fn split_flags(flags: &str) -> Vec<String> {
|
||||
PRETTY_COMPARE_ONLY,
|
||||
&mut self.pretty_compare_only,
|
||||
);
|
||||
config.push_name_value_directive(ln, AUX_BUILD, &mut self.aux_builds, |r| {
|
||||
r.trim().to_string()
|
||||
});
|
||||
config.push_name_value_directive(ln, AUX_BIN, &mut self.aux_bins, |r| {
|
||||
r.trim().to_string()
|
||||
});
|
||||
config.push_name_value_directive(
|
||||
ln,
|
||||
AUX_CRATE,
|
||||
&mut self.aux_crates,
|
||||
Config::parse_aux_crate,
|
||||
);
|
||||
if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) {
|
||||
self.aux_codegen_backend = Some(r.trim().to_owned());
|
||||
}
|
||||
|
||||
// Call a helper method to deal with aux-related directives.
|
||||
parse_and_update_aux(config, ln, &mut self.aux);
|
||||
|
||||
config.push_name_value_directive(
|
||||
ln,
|
||||
EXEC_ENV,
|
||||
@ -942,14 +907,6 @@ fn iter_header(
|
||||
}
|
||||
|
||||
impl Config {
|
||||
fn parse_aux_crate(r: String) -> (String, String) {
|
||||
let mut parts = r.trim().splitn(2, '=');
|
||||
(
|
||||
parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(),
|
||||
parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_and_update_revisions(&self, line: &str, existing: &mut Vec<String>) {
|
||||
if let Some(raw) = self.parse_name_value_directive(line, "revisions") {
|
||||
let mut duplicates: HashSet<_> = existing.iter().cloned().collect();
|
||||
|
60
src/tools/compiletest/src/header/auxiliary.rs
Normal file
60
src/tools/compiletest/src/header/auxiliary.rs
Normal file
@ -0,0 +1,60 @@
|
||||
//! Code for dealing with test directives that request an "auxiliary" crate to
|
||||
//! be built and made available to the test in some way.
|
||||
|
||||
use std::iter;
|
||||
|
||||
use crate::common::Config;
|
||||
use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE};
|
||||
|
||||
/// Properties parsed from `aux-*` test directives.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub(crate) struct AuxProps {
|
||||
/// Other crates that should be built and made available to this test.
|
||||
/// These are filenames relative to `./auxiliary/` in the test's directory.
|
||||
pub(crate) builds: Vec<String>,
|
||||
/// Auxiliary crates that should be compiled as `#![crate_type = "bin"]`.
|
||||
pub(crate) bins: Vec<String>,
|
||||
/// Similar to `builds`, but a list of NAME=somelib.rs of dependencies
|
||||
/// to build and pass with the `--extern` flag.
|
||||
pub(crate) crates: Vec<(String, String)>,
|
||||
/// Similar to `builds`, but also uses the resulting dylib as a
|
||||
/// `-Zcodegen-backend` when compiling the test file.
|
||||
pub(crate) codegen_backend: Option<String>,
|
||||
}
|
||||
|
||||
impl AuxProps {
|
||||
/// Yields all of the paths (relative to `./auxiliary/`) that have been
|
||||
/// specified in `aux-*` directives for this test.
|
||||
pub(crate) fn all_aux_path_strings(&self) -> impl Iterator<Item = &str> {
|
||||
let Self { builds, bins, crates, codegen_backend } = self;
|
||||
|
||||
iter::empty()
|
||||
.chain(builds.iter().map(String::as_str))
|
||||
.chain(bins.iter().map(String::as_str))
|
||||
.chain(crates.iter().map(|(_, path)| path.as_str()))
|
||||
.chain(codegen_backend.iter().map(String::as_str))
|
||||
}
|
||||
}
|
||||
|
||||
/// If the given test directive line contains an `aux-*` directive, parse it
|
||||
/// and update [`AuxProps`] accordingly.
|
||||
pub(super) fn parse_and_update_aux(config: &Config, ln: &str, aux: &mut AuxProps) {
|
||||
if !ln.starts_with("aux-") {
|
||||
return;
|
||||
}
|
||||
|
||||
config.push_name_value_directive(ln, AUX_BUILD, &mut aux.builds, |r| r.trim().to_string());
|
||||
config.push_name_value_directive(ln, AUX_BIN, &mut aux.bins, |r| r.trim().to_string());
|
||||
config.push_name_value_directive(ln, AUX_CRATE, &mut aux.crates, parse_aux_crate);
|
||||
if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) {
|
||||
aux.codegen_backend = Some(r.trim().to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_aux_crate(r: String) -> (String, String) {
|
||||
let mut parts = r.trim().splitn(2, '=');
|
||||
(
|
||||
parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(),
|
||||
parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(),
|
||||
)
|
||||
}
|
@ -242,7 +242,8 @@ fn aux_build() {
|
||||
//@ aux-build: b.rs
|
||||
"
|
||||
)
|
||||
.aux,
|
||||
.aux
|
||||
.builds,
|
||||
vec!["a.rs", "b.rs"],
|
||||
);
|
||||
}
|
||||
|
@ -862,7 +862,8 @@ fn files_related_to_test(
|
||||
related.push(testpaths.file.clone());
|
||||
}
|
||||
|
||||
for aux in &props.aux {
|
||||
for aux in props.aux.all_aux_path_strings() {
|
||||
// FIXME(Zalathar): Perform all `auxiliary` path resolution in one place.
|
||||
let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux);
|
||||
related.push(path);
|
||||
}
|
||||
|
@ -841,13 +841,13 @@ fn compile_test_general(
|
||||
/// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths.
|
||||
fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes {
|
||||
if self.props.build_aux_docs {
|
||||
for rel_ab in &self.props.aux_builds {
|
||||
for rel_ab in &self.props.aux.builds {
|
||||
let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab);
|
||||
let aux_props =
|
||||
let props_for_aux =
|
||||
self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
|
||||
let aux_cx = TestCx {
|
||||
config: self.config,
|
||||
props: &aux_props,
|
||||
props: &props_for_aux,
|
||||
testpaths: &aux_testpaths,
|
||||
revision: self.revision,
|
||||
};
|
||||
@ -1059,11 +1059,11 @@ fn is_vxworks_pure_dynamic(&self) -> bool {
|
||||
fn aux_output_dir(&self) -> PathBuf {
|
||||
let aux_dir = self.aux_output_dir_name();
|
||||
|
||||
if !self.props.aux_builds.is_empty() {
|
||||
if !self.props.aux.builds.is_empty() {
|
||||
remove_and_create_dir_all(&aux_dir);
|
||||
}
|
||||
|
||||
if !self.props.aux_bins.is_empty() {
|
||||
if !self.props.aux.bins.is_empty() {
|
||||
let aux_bin_dir = self.aux_bin_output_dir_name();
|
||||
remove_and_create_dir_all(&aux_dir);
|
||||
remove_and_create_dir_all(&aux_bin_dir);
|
||||
@ -1073,15 +1073,15 @@ fn aux_output_dir(&self) -> PathBuf {
|
||||
}
|
||||
|
||||
fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) {
|
||||
for rel_ab in &self.props.aux_builds {
|
||||
for rel_ab in &self.props.aux.builds {
|
||||
self.build_auxiliary(of, rel_ab, &aux_dir, false /* is_bin */);
|
||||
}
|
||||
|
||||
for rel_ab in &self.props.aux_bins {
|
||||
for rel_ab in &self.props.aux.bins {
|
||||
self.build_auxiliary(of, rel_ab, &aux_dir, true /* is_bin */);
|
||||
}
|
||||
|
||||
for (aux_name, aux_path) in &self.props.aux_crates {
|
||||
for (aux_name, aux_path) in &self.props.aux.crates {
|
||||
let aux_type = self.build_auxiliary(of, &aux_path, &aux_dir, false /* is_bin */);
|
||||
let lib_name =
|
||||
get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), aux_type);
|
||||
@ -1097,7 +1097,7 @@ fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Comman
|
||||
|
||||
// Build any `//@ aux-codegen-backend`, and pass the resulting library
|
||||
// to `-Zcodegen-backend` when compiling the test file.
|
||||
if let Some(aux_file) = &self.props.aux_codegen_backend {
|
||||
if let Some(aux_file) = &self.props.aux.codegen_backend {
|
||||
let aux_type = self.build_auxiliary(of, aux_file, aux_dir, false);
|
||||
if let Some(lib_name) = get_lib_name(aux_file.trim_end_matches(".rs"), aux_type) {
|
||||
let lib_path = aux_dir.join(&lib_name);
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ revisions: elfv1-be elfv2-be elfv2-le
|
||||
//@ revisions: elfv1-be elfv2-be elfv2-le aix
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O
|
||||
//@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu
|
||||
@ -7,8 +7,13 @@
|
||||
//@[elfv2-be] needs-llvm-components: powerpc
|
||||
//@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu
|
||||
//@[elfv2-le] needs-llvm-components: powerpc
|
||||
//@[aix] compile-flags: --target powerpc64-ibm-aix
|
||||
//@[aix] needs-llvm-components: powerpc
|
||||
//@[elfv1-be] filecheck-flags: --check-prefix be
|
||||
//@[elfv2-be] filecheck-flags: --check-prefix be
|
||||
//@[elfv1-be] filecheck-flags: --check-prefix elf
|
||||
//@[elfv2-be] filecheck-flags: --check-prefix elf
|
||||
//@[elfv2-le] filecheck-flags: --check-prefix elf
|
||||
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_std]
|
||||
@ -44,6 +49,10 @@ impl Copy for ThreeU8s {}
|
||||
struct ThreeU8s(u8, u8, u8);
|
||||
|
||||
// CHECK-LABEL: read_large
|
||||
// aix: lwz [[REG1:.*]], 16(4)
|
||||
// aix-NEXT: lxvd2x 0, 0, 4
|
||||
// aix-NEXT: stw [[REG1]], 16(3)
|
||||
// aix-NEXT: stxvd2x 0, 0, 3
|
||||
// be: lwz [[REG1:.*]], 16(4)
|
||||
// be-NEXT: stw [[REG1]], 16(3)
|
||||
// be-NEXT: ld [[REG2:.*]], 8(4)
|
||||
@ -61,6 +70,10 @@ extern "C" fn read_large(x: &FiveU32s) -> FiveU32s {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: read_medium
|
||||
// aix: lhz [[REG1:.*]], 8(4)
|
||||
// aix-NEXT: ld [[REG2:.*]], 0(4)
|
||||
// aix-NEXT: sth [[REG1]], 8(3)
|
||||
// aix-NEXT: std [[REG2]], 0(3)
|
||||
// elfv1-be: lhz [[REG1:.*]], 8(4)
|
||||
// elfv1-be-NEXT: ld [[REG2:.*]], 0(4)
|
||||
// elfv1-be-NEXT: sth [[REG1]], 8(3)
|
||||
@ -78,6 +91,10 @@ extern "C" fn read_medium(x: &FiveU16s) -> FiveU16s {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: read_small
|
||||
// aix: lbz [[REG1:.*]], 2(4)
|
||||
// aix-NEXT: lhz [[REG2:.*]], 0(4)
|
||||
// aix-NEXT: stb [[REG1]], 2(3)
|
||||
// aix-NEXT: sth [[REG2]], 0(3)
|
||||
// elfv1-be: lbz [[REG1:.*]], 2(4)
|
||||
// elfv1-be-NEXT: lhz [[REG2:.*]], 0(4)
|
||||
// elfv1-be-NEXT: stb [[REG1]], 2(3)
|
||||
@ -95,9 +112,17 @@ extern "C" fn read_small(x: &ThreeU8s) -> ThreeU8s {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: write_large
|
||||
// CHECK: std 3, 0(6)
|
||||
// aix: std 3, 48(1)
|
||||
// aix-NEXT: rldicl [[REG1:.*]], 5, 32, 32
|
||||
// aix-NEXT: std 5, 64(1)
|
||||
// aix-NEXT: std 4, 56(1)
|
||||
// aix-NEXT: stw [[REG1]], 16(6)
|
||||
// aix-NEXT: addi [[REG2:.*]], 1, 48
|
||||
// aix-NEXT: lxvd2x 0, 0, [[REG2]]
|
||||
// aix-NEXT: stxvd2x 0, 0, 6
|
||||
// elf: std 3, 0(6)
|
||||
// be-NEXT: rldicl [[REG1:.*]], 5, 32, 32
|
||||
// CHECK-NEXT: std 4, 8(6)
|
||||
// elf-NEXT: std 4, 8(6)
|
||||
// be-NEXT: stw [[REG1]], 16(6)
|
||||
// elfv2-le-NEXT: stw 5, 16(6)
|
||||
// CHECK-NEXT: blr
|
||||
@ -107,7 +132,12 @@ extern "C" fn write_large(x: FiveU32s, dest: &mut FiveU32s) {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: write_medium
|
||||
// CHECK: std 3, 0(5)
|
||||
// aix: std 4, 56(1)
|
||||
// aix-NEXT: rldicl [[REG1:.*]], 4, 16, 48
|
||||
// aix-NEXT: std 3, 48(1)
|
||||
// aix-NEXT: std 3, 0(5)
|
||||
// aix-NEXT: sth [[REG1]], 8(5)
|
||||
// elf: std 3, 0(5)
|
||||
// be-NEXT: rldicl [[REG1:.*]], 4, 16, 48
|
||||
// be-NEXT: sth [[REG1]], 8(5)
|
||||
// elfv2-le-NEXT: sth 4, 8(5)
|
||||
@ -118,6 +148,11 @@ extern "C" fn write_medium(x: FiveU16s, dest: &mut FiveU16s) {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: write_small
|
||||
// aix: std 3, 48(1)
|
||||
// aix-NEXT: rldicl [[REG1:.*]], 3, 16, 48
|
||||
// aix-NEXT: sth 3, 0(4)
|
||||
// aix-NEXT: lbz 3, 50(1)
|
||||
// aix-NEXT: stb [[REG1]], 2(4)
|
||||
// be: stb 3, 2(4)
|
||||
// be-NEXT: srwi [[REG1:.*]], 3, 8
|
||||
// be-NEXT: sth [[REG1]], 0(4)
|
||||
|
@ -31,3 +31,19 @@
|
||||
// PROTECTED: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = protected constant
|
||||
// INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
|
||||
// DEFAULT: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
|
||||
|
||||
pub fn do_memcmp(left: &[u8], right: &[u8]) -> i32 {
|
||||
left.cmp(right) as i32
|
||||
}
|
||||
|
||||
// CHECK: define {{.*}} @{{.*}}do_memcmp{{.*}} {
|
||||
// CHECK: }
|
||||
|
||||
// `do_memcmp` should invoke core::intrinsic::compare_bytes which emits a call
|
||||
// to the C symbol `memcmp` (at least on x86_64-unknown-linux-gnu). This symbol
|
||||
// should *not* be declared hidden or protected.
|
||||
|
||||
// HIDDEN: declare i32 @memcmp
|
||||
// PROTECTED: declare i32 @memcmp
|
||||
// INTERPOSABLE: declare i32 @memcmp
|
||||
// DEFAULT: declare i32 @memcmp
|
||||
|
13
tests/run-make/msvc-lld-thinlto-imp-symbols/issue_81408.rs
Normal file
13
tests/run-make/msvc-lld-thinlto-imp-symbols/issue_81408.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
|
||||
#[inline(always)]
|
||||
pub fn memrchr() {
|
||||
fn detect() {}
|
||||
|
||||
static CROSS_CRATE_STATIC_ITEM: AtomicPtr<()> = AtomicPtr::new(detect as *mut ());
|
||||
|
||||
unsafe {
|
||||
let fun = CROSS_CRATE_STATIC_ITEM.load(Ordering::SeqCst);
|
||||
std::mem::transmute::<*mut (), fn()>(fun)()
|
||||
}
|
||||
}
|
5
tests/run-make/msvc-lld-thinlto-imp-symbols/main.rs
Normal file
5
tests/run-make/msvc-lld-thinlto-imp-symbols/main.rs
Normal file
@ -0,0 +1,5 @@
|
||||
extern crate issue_81408;
|
||||
|
||||
fn main() {
|
||||
issue_81408::memrchr();
|
||||
}
|
33
tests/run-make/msvc-lld-thinlto-imp-symbols/rmake.rs
Normal file
33
tests/run-make/msvc-lld-thinlto-imp-symbols/rmake.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// This is a non-regression test for issue #81408 involving an lld bug and ThinLTO, on windows.
|
||||
// MSVC's link.exe doesn't need any workarounds in rustc, but lld does, so we'll check that the
|
||||
// binary runs successfully instead of using a codegen test.
|
||||
|
||||
//@ only-x86_64-pc-windows-msvc
|
||||
//@ needs-rust-lld
|
||||
//@ ignore-cross-compile: the built binary is executed
|
||||
|
||||
use run_make_support::{run, rustc};
|
||||
|
||||
fn test_with_linker(linker: &str) {
|
||||
rustc().input("issue_81408.rs").crate_name("issue_81408").crate_type("lib").opt().run();
|
||||
rustc()
|
||||
.input("main.rs")
|
||||
.crate_type("bin")
|
||||
.arg("-Clto=thin")
|
||||
.opt()
|
||||
.arg(&format!("-Clinker={linker}"))
|
||||
.extern_("issue_81408", "libissue_81408.rlib")
|
||||
.run();
|
||||
|
||||
// To make possible failures clearer, print an intro that will only be shown if the test does
|
||||
// fail when running the binary.
|
||||
eprint!("Running binary linked with {linker}... ");
|
||||
run("main");
|
||||
eprintln!("ok");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// We want the reproducer to work when linked with both linkers.
|
||||
test_with_linker("link");
|
||||
test_with_linker("rust-lld");
|
||||
}
|
Loading…
Reference in New Issue
Block a user