| author | bors <bors@rust-lang.org> 2024-10-11 16:27:23 UTC |
| committer | bors <bors@rust-lang.org> 2024-10-11 16:27:23 UTC |
| log | 01e2fff90c7ed19e1d9fb828ebc012e7b9732297 |
| tree | 49b5869e859d2415e6f0a6b02f5bb1dbf1581d8d |
| parent | f4966590d8edd5f493a1aab04016b94a75494329 |
| parent | b18e1aa612d75114ee67091f3af82ea04a08ef36 |
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: rollup20 files changed, 225 insertions(+), 95 deletions(-)
compiler/rustc_codegen_llvm/src/declare.rs+3-4| ... | ... | @@ -84,10 +84,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { |
| 84 | 84 | unnamed: llvm::UnnamedAddr, |
| 85 | 85 | fn_type: &'ll Type, |
| 86 | 86 | ) -> &'ll Value { |
| 87 | // Declare C ABI functions with the visibility used by C by default. | |
| 88 | let visibility = Visibility::from_generic(self.tcx.sess.default_visibility()); | |
| 89 | ||
| 90 | declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type) | |
| 87 | // Visibility should always be default for declarations, otherwise the linker may report an | |
| 88 | // error. | |
| 89 | declare_raw_fn(self, name, llvm::CCallConv, unnamed, Visibility::Default, fn_type) | |
| 91 | 90 | } |
| 92 | 91 | |
| 93 | 92 | /// Declare an entry Function |
compiler/rustc_codegen_ssa/src/back/write.rs+7-1| ... | ... | @@ -2164,8 +2164,14 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool { |
| 2164 | 2164 | && tcx.sess.opts.cg.prefer_dynamic) |
| 2165 | 2165 | ); |
| 2166 | 2166 | |
| 2167 | // We need to generate _imp__ symbol if we are generating an rlib or we include one | |
| 2168 | // indirectly from ThinLTO. In theory these are not needed as ThinLTO could resolve | |
| 2169 | // these, but it currently does not do so. | |
| 2170 | let can_have_static_objects = | |
| 2171 | tcx.sess.lto() == Lto::Thin || tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib); | |
| 2172 | ||
| 2167 | 2173 | tcx.sess.target.is_like_windows && |
| 2168 | tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib) && | |
| 2174 | can_have_static_objects && | |
| 2169 | 2175 | // ThinLTO can't handle this workaround in all cases, so we don't |
| 2170 | 2176 | // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing |
| 2171 | 2177 | // dynamic linking when linker plugin LTO is enabled. |
compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs-1| ... | ... | @@ -444,7 +444,6 @@ where |
| 444 | 444 | for &arg in &state.value.var_values.var_values.as_slice() |
| 445 | 445 | [orig_values.len()..state.value.var_values.len()] |
| 446 | 446 | { |
| 447 | // FIXME: This is so ugly. | |
| 448 | 447 | let unconstrained = delegate.fresh_var_for_kind_with_span(arg, span); |
| 449 | 448 | orig_values.push(unconstrained); |
| 450 | 449 | } |
compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs+1-1| ... | ... | @@ -92,7 +92,6 @@ where |
| 92 | 92 | #[derive_where(Clone, Debug, Default; I: Interner)] |
| 93 | 93 | #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] |
| 94 | 94 | #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] |
| 95 | // FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate. | |
| 96 | 95 | struct NestedGoals<I: Interner> { |
| 97 | 96 | /// These normalizes-to goals are treated specially during the evaluation |
| 98 | 97 | /// loop. In each iteration we take the RHS of the projection, replace it with |
| ... | ... | @@ -421,6 +420,7 @@ where |
| 421 | 420 | let (normalization_nested_goals, certainty) = |
| 422 | 421 | self.instantiate_and_apply_query_response(goal.param_env, orig_values, response); |
| 423 | 422 | self.inspect.goal_evaluation(goal_evaluation); |
| 423 | ||
| 424 | 424 | // FIXME: We previously had an assert here that checked that recomputing |
| 425 | 425 | // a goal after applying its constraints did not change its response. |
| 426 | 426 | // |
compiler/rustc_next_trait_solver/src/solve/mod.rs-3| ... | ... | @@ -10,9 +10,6 @@ |
| 10 | 10 | //! |
| 11 | 11 | //! For a high-level overview of how this solver works, check out the relevant |
| 12 | 12 | //! section of the rustc-dev-guide. |
| 13 | //! | |
| 14 | //! FIXME(@lcnr): Write that section. If you read this before then ask me | |
| 15 | //! about it on zulip. | |
| 16 | 13 | |
| 17 | 14 | mod alias_relate; |
| 18 | 15 | mod assembly; |
compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs+1-1| ... | ... | @@ -899,7 +899,7 @@ where |
| 899 | 899 | for ty in types.iter() { |
| 900 | 900 | // We can't find the intersection if the types used are generic. |
| 901 | 901 | // |
| 902 | // FIXME(effects) do we want to look at where clauses to get some | |
| 902 | // FIXME(effects): do we want to look at where clauses to get some | |
| 903 | 903 | // clue for the case where generic types are being used? |
| 904 | 904 | let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else { |
| 905 | 905 | return Err(NoSolution); |
compiler/rustc_next_trait_solver/src/solve/trait_goals.rs+2-9| ... | ... | @@ -108,7 +108,6 @@ where |
| 108 | 108 | ecx: &mut EvalCtxt<'_, D>, |
| 109 | 109 | _guar: I::ErrorGuaranteed, |
| 110 | 110 | ) -> Result<Candidate<I>, NoSolution> { |
| 111 | // FIXME: don't need to enter a probe here. | |
| 112 | 111 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 113 | 112 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| 114 | 113 | } |
| ... | ... | @@ -463,7 +462,6 @@ where |
| 463 | 462 | // Async coroutine unconditionally implement `Future` |
| 464 | 463 | // Technically, we need to check that the future output type is Sized, |
| 465 | 464 | // but that's already proven by the coroutine being WF. |
| 466 | // FIXME: use `consider_implied` | |
| 467 | 465 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 468 | 466 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| 469 | 467 | } |
| ... | ... | @@ -489,7 +487,6 @@ where |
| 489 | 487 | // Gen coroutines unconditionally implement `Iterator` |
| 490 | 488 | // Technically, we need to check that the iterator output type is Sized, |
| 491 | 489 | // but that's already proven by the coroutines being WF. |
| 492 | // FIXME: use `consider_implied` | |
| 493 | 490 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 494 | 491 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| 495 | 492 | } |
| ... | ... | @@ -512,8 +509,7 @@ where |
| 512 | 509 | return Err(NoSolution); |
| 513 | 510 | } |
| 514 | 511 | |
| 515 | // Gen coroutines unconditionally implement `FusedIterator` | |
| 516 | // FIXME: use `consider_implied` | |
| 512 | // Gen coroutines unconditionally implement `FusedIterator`. | |
| 517 | 513 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 518 | 514 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| 519 | 515 | } |
| ... | ... | @@ -539,7 +535,6 @@ where |
| 539 | 535 | // Gen coroutines unconditionally implement `Iterator` |
| 540 | 536 | // Technically, we need to check that the iterator output type is Sized, |
| 541 | 537 | // but that's already proven by the coroutines being WF. |
| 542 | // FIXME: use `consider_implied` | |
| 543 | 538 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 544 | 539 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| 545 | 540 | } |
| ... | ... | @@ -610,7 +605,7 @@ where |
| 610 | 605 | return Err(NoSolution); |
| 611 | 606 | } |
| 612 | 607 | |
| 613 | // FIXME(-Znext-solver): Implement this when we get const working in the new solver | |
| 608 | // FIXME(effects): Implement this when we get const working in the new solver | |
| 614 | 609 | |
| 615 | 610 | // `Destruct` is automatically implemented for every type in |
| 616 | 611 | // non-const environments. |
| ... | ... | @@ -631,8 +626,6 @@ where |
| 631 | 626 | return Err(NoSolution); |
| 632 | 627 | } |
| 633 | 628 | |
| 634 | // FIXME: This actually should destructure the `Result` we get from transmutability and | |
| 635 | // register candidates. We probably need to register >1 since we may have an OR of ANDs. | |
| 636 | 629 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { |
| 637 | 630 | let certainty = ecx.is_transmutable( |
| 638 | 631 | goal.param_env, |
compiler/rustc_target/src/abi/call/powerpc64.rs+13-3| ... | ... | @@ -10,6 +10,7 @@ use crate::spec::HasTargetSpec; |
| 10 | 10 | enum ABI { |
| 11 | 11 | ELFv1, // original ABI used for powerpc64 (big-endian) |
| 12 | 12 | ELFv2, // newer ABI used for powerpc64le and musl (both endians) |
| 13 | AIX, // used by AIX OS, big-endian only | |
| 13 | 14 | } |
| 14 | 15 | use ABI::*; |
| 15 | 16 | |
| ... | ... | @@ -23,9 +24,9 @@ where |
| 23 | 24 | C: HasDataLayout, |
| 24 | 25 | { |
| 25 | 26 | arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| { |
| 26 | // ELFv1 only passes one-member aggregates transparently. | |
| 27 | // ELFv1 and AIX only passes one-member aggregates transparently. | |
| 27 | 28 | // ELFv2 passes up to eight uniquely addressable members. |
| 28 | if (abi == ELFv1 && arg.layout.size > unit.size) | |
| 29 | if ((abi == ELFv1 || abi == AIX) && arg.layout.size > unit.size) | |
| 29 | 30 | || arg.layout.size > unit.size.checked_mul(8, cx).unwrap() |
| 30 | 31 | { |
| 31 | 32 | return None; |
| ... | ... | @@ -55,8 +56,15 @@ where |
| 55 | 56 | return; |
| 56 | 57 | } |
| 57 | 58 | |
| 59 | // The AIX ABI expect byval for aggregates | |
| 60 | // See https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/Targets/PPC.cpp. | |
| 61 | if !is_ret && abi == AIX { | |
| 62 | arg.pass_by_stack_offset(None); | |
| 63 | return; | |
| 64 | } | |
| 65 | ||
| 58 | 66 | // The ELFv1 ABI doesn't return aggregates in registers |
| 59 | if is_ret && abi == ELFv1 { | |
| 67 | if is_ret && (abi == ELFv1 || abi == AIX) { | |
| 60 | 68 | arg.make_indirect(); |
| 61 | 69 | return; |
| 62 | 70 | } |
| ... | ... | @@ -93,6 +101,8 @@ where |
| 93 | 101 | { |
| 94 | 102 | let abi = if cx.target_spec().env == "musl" { |
| 95 | 103 | ELFv2 |
| 104 | } else if cx.target_spec().os == "aix" { | |
| 105 | AIX | |
| 96 | 106 | } else { |
| 97 | 107 | match cx.data_layout().endian { |
| 98 | 108 | Endian::Big => ELFv1, |
compiler/rustc_trait_selection/src/solve/delegate.rs+2| ... | ... | @@ -223,6 +223,8 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< |
| 223 | 223 | if eligible { Ok(Some(node_item.item.def_id)) } else { Ok(None) } |
| 224 | 224 | } |
| 225 | 225 | |
| 226 | // FIXME: This actually should destructure the `Result` we get from transmutability and | |
| 227 | // register candidates. We probably need to register >1 since we may have an OR of ANDs. | |
| 226 | 228 | fn is_transmutable( |
| 227 | 229 | &self, |
| 228 | 230 | param_env: ty::ParamEnv<'tcx>, |
src/librustdoc/html/static/css/rustdoc.css+3| ... | ... | @@ -230,6 +230,9 @@ h4.code-header { |
| 230 | 230 | 	padding: 0; |
| 231 | 231 | 	white-space: pre-wrap; |
| 232 | 232 | } |
| 233 | .structfield { | |
| 234 | 	margin: 0.6em 0; | |
| 235 | } | |
| 233 | 236 | |
| 234 | 237 | #crate-search, |
| 235 | 238 | h1, h2, h3, h4, h5, h6, |
src/tools/compiletest/src/header.rs+14-57| ... | ... | @@ -9,11 +9,13 @@ use std::process::Command; |
| 9 | 9 | use tracing::*; |
| 10 | 10 | |
| 11 | 11 | use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; |
| 12 | use crate::header::auxiliary::{AuxProps, parse_and_update_aux}; | |
| 12 | 13 | use crate::header::cfg::{MatchOutcome, parse_cfg_name_directive}; |
| 13 | 14 | use crate::header::needs::CachedNeedsConditions; |
| 14 | 15 | use crate::util::static_regex; |
| 15 | 16 | use crate::{extract_cdb_version, extract_gdb_version}; |
| 16 | 17 | |
| 18 | pub(crate) mod auxiliary; | |
| 17 | 19 | mod cfg; |
| 18 | 20 | mod needs; |
| 19 | 21 | #[cfg(test)] |
| ... | ... | @@ -33,9 +35,10 @@ impl HeadersCache { |
| 33 | 35 | /// the test. |
| 34 | 36 | #[derive(Default)] |
| 35 | 37 | pub struct EarlyProps { |
| 36 | pub aux: Vec<String>, | |
| 37 | pub aux_bin: Vec<String>, | |
| 38 | pub aux_crate: Vec<(String, String)>, | |
| 38 | /// Auxiliary crates that should be built and made available to this test. | |
| 39 | /// Included in [`EarlyProps`] so that the indicated files can participate | |
| 40 | /// in up-to-date checking. Building happens via [`TestProps::aux`] instead. | |
| 41 | pub(crate) aux: AuxProps, | |
| 39 | 42 | pub revisions: Vec<String>, |
| 40 | 43 | } |
| 41 | 44 | |
| ... | ... | @@ -55,21 +58,7 @@ impl EarlyProps { |
| 55 | 58 | testfile, |
| 56 | 59 | rdr, |
| 57 | 60 | &mut |HeaderLine { directive: ln, .. }| { |
| 58 | config.push_name_value_directive(ln, directives::AUX_BUILD, &mut props.aux, |r| { | |
| 59 | r.trim().to_string() | |
| 60 | }); | |
| 61 | config.push_name_value_directive( | |
| 62 | ln, | |
| 63 | directives::AUX_BIN, | |
| 64 | &mut props.aux_bin, | |
| 65 | |r| r.trim().to_string(), | |
| 66 | ); | |
| 67 | config.push_name_value_directive( | |
| 68 | ln, | |
| 69 | directives::AUX_CRATE, | |
| 70 | &mut props.aux_crate, | |
| 71 | Config::parse_aux_crate, | |
| 72 | ); | |
| 61 | parse_and_update_aux(config, ln, &mut props.aux); | |
| 73 | 62 | config.parse_and_update_revisions(ln, &mut props.revisions); |
| 74 | 63 | }, |
| 75 | 64 | ); |
| ... | ... | @@ -98,18 +87,8 @@ pub struct TestProps { |
| 98 | 87 | // If present, the name of a file that this test should match when |
| 99 | 88 | // pretty-printed |
| 100 | 89 | pub pp_exact: Option<PathBuf>, |
| 101 | // Other crates that should be compiled (typically from the same | |
| 102 | // directory as the test, but for backwards compatibility reasons | |
| 103 | // we also check the auxiliary directory) | |
| 104 | pub aux_builds: Vec<String>, | |
| 105 | // Auxiliary crates that should be compiled as `#![crate_type = "bin"]`. | |
| 106 | pub aux_bins: Vec<String>, | |
| 107 | // Similar to `aux_builds`, but a list of NAME=somelib.rs of dependencies | |
| 108 | // to build and pass with the `--extern` flag. | |
| 109 | pub aux_crates: Vec<(String, String)>, | |
| 110 | /// Similar to `aux_builds`, but also passes the resulting dylib path to | |
| 111 | /// `-Zcodegen-backend`. | |
| 112 | pub aux_codegen_backend: Option<String>, | |
| 90 | /// Auxiliary crates that should be built and made available to this test. | |
| 91 | pub(crate) aux: AuxProps, | |
| 113 | 92 | // Environment settings to use for compiling |
| 114 | 93 | pub rustc_env: Vec<(String, String)>, |
| 115 | 94 | // Environment variables to unset prior to compiling. |
| ... | ... | @@ -276,10 +255,7 @@ impl TestProps { |
| 276 | 255 | run_flags: vec![], |
| 277 | 256 | doc_flags: vec![], |
| 278 | 257 | pp_exact: None, |
| 279 | aux_builds: vec![], | |
| 280 | aux_bins: vec![], | |
| 281 | aux_crates: vec![], | |
| 282 | aux_codegen_backend: None, | |
| 258 | aux: Default::default(), | |
| 283 | 259 | revisions: vec![], |
| 284 | 260 | rustc_env: vec![ |
| 285 | 261 | ("RUSTC_ICE".to_string(), "0".to_string()), |
| ... | ... | @@ -454,21 +430,10 @@ impl TestProps { |
| 454 | 430 | PRETTY_COMPARE_ONLY, |
| 455 | 431 | &mut self.pretty_compare_only, |
| 456 | 432 | ); |
| 457 | config.push_name_value_directive(ln, AUX_BUILD, &mut self.aux_builds, |r| { | |
| 458 | r.trim().to_string() | |
| 459 | }); | |
| 460 | config.push_name_value_directive(ln, AUX_BIN, &mut self.aux_bins, |r| { | |
| 461 | r.trim().to_string() | |
| 462 | }); | |
| 463 | config.push_name_value_directive( | |
| 464 | ln, | |
| 465 | AUX_CRATE, | |
| 466 | &mut self.aux_crates, | |
| 467 | Config::parse_aux_crate, | |
| 468 | ); | |
| 469 | if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) { | |
| 470 | self.aux_codegen_backend = Some(r.trim().to_owned()); | |
| 471 | } | |
| 433 | ||
| 434 | // Call a helper method to deal with aux-related directives. | |
| 435 | parse_and_update_aux(config, ln, &mut self.aux); | |
| 436 | ||
| 472 | 437 | config.push_name_value_directive( |
| 473 | 438 | ln, |
| 474 | 439 | EXEC_ENV, |
| ... | ... | @@ -942,14 +907,6 @@ fn iter_header( |
| 942 | 907 | } |
| 943 | 908 | |
| 944 | 909 | impl Config { |
| 945 | fn parse_aux_crate(r: String) -> (String, String) { | |
| 946 | let mut parts = r.trim().splitn(2, '='); | |
| 947 | ( | |
| 948 | parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(), | |
| 949 | parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(), | |
| 950 | ) | |
| 951 | } | |
| 952 | ||
| 953 | 910 | fn parse_and_update_revisions(&self, line: &str, existing: &mut Vec<String>) { |
| 954 | 911 | if let Some(raw) = self.parse_name_value_directive(line, "revisions") { |
| 955 | 912 | let mut duplicates: HashSet<_> = existing.iter().cloned().collect(); |
src/tools/compiletest/src/header/auxiliary.rs created+60| ... | ... | @@ -0,0 +1,60 @@ |
| 1 | //! Code for dealing with test directives that request an "auxiliary" crate to | |
| 2 | //! be built and made available to the test in some way. | |
| 3 | ||
| 4 | use std::iter; | |
| 5 | ||
| 6 | use crate::common::Config; | |
| 7 | use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE}; | |
| 8 | ||
| 9 | /// Properties parsed from `aux-*` test directives. | |
| 10 | #[derive(Clone, Debug, Default)] | |
| 11 | pub(crate) struct AuxProps { | |
| 12 | /// Other crates that should be built and made available to this test. | |
| 13 | /// These are filenames relative to `./auxiliary/` in the test's directory. | |
| 14 | pub(crate) builds: Vec<String>, | |
| 15 | /// Auxiliary crates that should be compiled as `#![crate_type = "bin"]`. | |
| 16 | pub(crate) bins: Vec<String>, | |
| 17 | /// Similar to `builds`, but a list of NAME=somelib.rs of dependencies | |
| 18 | /// to build and pass with the `--extern` flag. | |
| 19 | pub(crate) crates: Vec<(String, String)>, | |
| 20 | /// Similar to `builds`, but also uses the resulting dylib as a | |
| 21 | /// `-Zcodegen-backend` when compiling the test file. | |
| 22 | pub(crate) codegen_backend: Option<String>, | |
| 23 | } | |
| 24 | ||
| 25 | impl AuxProps { | |
| 26 | /// Yields all of the paths (relative to `./auxiliary/`) that have been | |
| 27 | /// specified in `aux-*` directives for this test. | |
| 28 | pub(crate) fn all_aux_path_strings(&self) -> impl Iterator<Item = &str> { | |
| 29 | let Self { builds, bins, crates, codegen_backend } = self; | |
| 30 | ||
| 31 | iter::empty() | |
| 32 | .chain(builds.iter().map(String::as_str)) | |
| 33 | .chain(bins.iter().map(String::as_str)) | |
| 34 | .chain(crates.iter().map(|(_, path)| path.as_str())) | |
| 35 | .chain(codegen_backend.iter().map(String::as_str)) | |
| 36 | } | |
| 37 | } | |
| 38 | ||
| 39 | /// If the given test directive line contains an `aux-*` directive, parse it | |
| 40 | /// and update [`AuxProps`] accordingly. | |
| 41 | pub(super) fn parse_and_update_aux(config: &Config, ln: &str, aux: &mut AuxProps) { | |
| 42 | if !ln.starts_with("aux-") { | |
| 43 | return; | |
| 44 | } | |
| 45 | ||
| 46 | config.push_name_value_directive(ln, AUX_BUILD, &mut aux.builds, |r| r.trim().to_string()); | |
| 47 | config.push_name_value_directive(ln, AUX_BIN, &mut aux.bins, |r| r.trim().to_string()); | |
| 48 | config.push_name_value_directive(ln, AUX_CRATE, &mut aux.crates, parse_aux_crate); | |
| 49 | if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) { | |
| 50 | aux.codegen_backend = Some(r.trim().to_owned()); | |
| 51 | } | |
| 52 | } | |
| 53 | ||
| 54 | fn parse_aux_crate(r: String) -> (String, String) { | |
| 55 | let mut parts = r.trim().splitn(2, '='); | |
| 56 | ( | |
| 57 | parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(), | |
| 58 | parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(), | |
| 59 | ) | |
| 60 | } |
src/tools/compiletest/src/header/tests.rs+2-1| ... | ... | @@ -242,7 +242,8 @@ fn aux_build() { |
| 242 | 242 | //@ aux-build: b.rs |
| 243 | 243 | " |
| 244 | 244 | ) |
| 245 | .aux, | |
| 245 | .aux | |
| 246 | .builds, | |
| 246 | 247 | vec!["a.rs", "b.rs"], |
| 247 | 248 | ); |
| 248 | 249 | } |
src/tools/compiletest/src/lib.rs+2-1| ... | ... | @@ -862,7 +862,8 @@ fn files_related_to_test( |
| 862 | 862 | related.push(testpaths.file.clone()); |
| 863 | 863 | } |
| 864 | 864 | |
| 865 | for aux in &props.aux { | |
| 865 | for aux in props.aux.all_aux_path_strings() { | |
| 866 | // FIXME(Zalathar): Perform all `auxiliary` path resolution in one place. | |
| 866 | 867 | let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux); |
| 867 | 868 | related.push(path); |
| 868 | 869 | } |
src/tools/compiletest/src/runtest.rs+9-9| ... | ... | @@ -841,13 +841,13 @@ impl<'test> TestCx<'test> { |
| 841 | 841 | /// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths. |
| 842 | 842 | fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes { |
| 843 | 843 | if self.props.build_aux_docs { |
| 844 | for rel_ab in &self.props.aux_builds { | |
| 844 | for rel_ab in &self.props.aux.builds { | |
| 845 | 845 | let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab); |
| 846 | let aux_props = | |
| 846 | let props_for_aux = | |
| 847 | 847 | self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config); |
| 848 | 848 | let aux_cx = TestCx { |
| 849 | 849 | config: self.config, |
| 850 | props: &aux_props, | |
| 850 | props: &props_for_aux, | |
| 851 | 851 | testpaths: &aux_testpaths, |
| 852 | 852 | revision: self.revision, |
| 853 | 853 | }; |
| ... | ... | @@ -1059,11 +1059,11 @@ impl<'test> TestCx<'test> { |
| 1059 | 1059 | fn aux_output_dir(&self) -> PathBuf { |
| 1060 | 1060 | let aux_dir = self.aux_output_dir_name(); |
| 1061 | 1061 | |
| 1062 | if !self.props.aux_builds.is_empty() { | |
| 1062 | if !self.props.aux.builds.is_empty() { | |
| 1063 | 1063 | remove_and_create_dir_all(&aux_dir); |
| 1064 | 1064 | } |
| 1065 | 1065 | |
| 1066 | if !self.props.aux_bins.is_empty() { | |
| 1066 | if !self.props.aux.bins.is_empty() { | |
| 1067 | 1067 | let aux_bin_dir = self.aux_bin_output_dir_name(); |
| 1068 | 1068 | remove_and_create_dir_all(&aux_dir); |
| 1069 | 1069 | remove_and_create_dir_all(&aux_bin_dir); |
| ... | ... | @@ -1073,15 +1073,15 @@ impl<'test> TestCx<'test> { |
| 1073 | 1073 | } |
| 1074 | 1074 | |
| 1075 | 1075 | fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) { |
| 1076 | for rel_ab in &self.props.aux_builds { | |
| 1076 | for rel_ab in &self.props.aux.builds { | |
| 1077 | 1077 | self.build_auxiliary(of, rel_ab, &aux_dir, false /* is_bin */); |
| 1078 | 1078 | } |
| 1079 | 1079 | |
| 1080 | for rel_ab in &self.props.aux_bins { | |
| 1080 | for rel_ab in &self.props.aux.bins { | |
| 1081 | 1081 | self.build_auxiliary(of, rel_ab, &aux_dir, true /* is_bin */); |
| 1082 | 1082 | } |
| 1083 | 1083 | |
| 1084 | for (aux_name, aux_path) in &self.props.aux_crates { | |
| 1084 | for (aux_name, aux_path) in &self.props.aux.crates { | |
| 1085 | 1085 | let aux_type = self.build_auxiliary(of, &aux_path, &aux_dir, false /* is_bin */); |
| 1086 | 1086 | let lib_name = |
| 1087 | 1087 | get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), aux_type); |
| ... | ... | @@ -1097,7 +1097,7 @@ impl<'test> TestCx<'test> { |
| 1097 | 1097 | |
| 1098 | 1098 | // Build any `//@ aux-codegen-backend`, and pass the resulting library |
| 1099 | 1099 | // to `-Zcodegen-backend` when compiling the test file. |
| 1100 | if let Some(aux_file) = &self.props.aux_codegen_backend { | |
| 1100 | if let Some(aux_file) = &self.props.aux.codegen_backend { | |
| 1101 | 1101 | let aux_type = self.build_auxiliary(of, aux_file, aux_dir, false); |
| 1102 | 1102 | if let Some(lib_name) = get_lib_name(aux_file.trim_end_matches(".rs"), aux_type) { |
| 1103 | 1103 | let lib_path = aux_dir.join(&lib_name); |
tests/assembly/powerpc64-struct-abi.rs+39-4| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ revisions: elfv1-be elfv2-be elfv2-le | |
| 1 | //@ revisions: elfv1-be elfv2-be elfv2-le aix | |
| 2 | 2 | //@ assembly-output: emit-asm |
| 3 | 3 | //@ compile-flags: -O |
| 4 | 4 | //@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu |
| ... | ... | @@ -7,8 +7,13 @@ |
| 7 | 7 | //@[elfv2-be] needs-llvm-components: powerpc |
| 8 | 8 | //@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu |
| 9 | 9 | //@[elfv2-le] needs-llvm-components: powerpc |
| 10 | //@[aix] compile-flags: --target powerpc64-ibm-aix | |
| 11 | //@[aix] needs-llvm-components: powerpc | |
| 10 | 12 | //@[elfv1-be] filecheck-flags: --check-prefix be |
| 11 | 13 | //@[elfv2-be] filecheck-flags: --check-prefix be |
| 14 | //@[elfv1-be] filecheck-flags: --check-prefix elf | |
| 15 | //@[elfv2-be] filecheck-flags: --check-prefix elf | |
| 16 | //@[elfv2-le] filecheck-flags: --check-prefix elf | |
| 12 | 17 | |
| 13 | 18 | #![feature(no_core, lang_items)] |
| 14 | 19 | #![no_std] |
| ... | ... | @@ -44,6 +49,10 @@ struct FiveU16s(u16, u16, u16, u16, u16); |
| 44 | 49 | struct ThreeU8s(u8, u8, u8); |
| 45 | 50 | |
| 46 | 51 | // CHECK-LABEL: read_large |
| 52 | // aix: lwz [[REG1:.*]], 16(4) | |
| 53 | // aix-NEXT: lxvd2x 0, 0, 4 | |
| 54 | // aix-NEXT: stw [[REG1]], 16(3) | |
| 55 | // aix-NEXT: stxvd2x 0, 0, 3 | |
| 47 | 56 | // be: lwz [[REG1:.*]], 16(4) |
| 48 | 57 | // be-NEXT: stw [[REG1]], 16(3) |
| 49 | 58 | // be-NEXT: ld [[REG2:.*]], 8(4) |
| ... | ... | @@ -61,6 +70,10 @@ extern "C" fn read_large(x: &FiveU32s) -> FiveU32s { |
| 61 | 70 | } |
| 62 | 71 | |
| 63 | 72 | // CHECK-LABEL: read_medium |
| 73 | // aix: lhz [[REG1:.*]], 8(4) | |
| 74 | // aix-NEXT: ld [[REG2:.*]], 0(4) | |
| 75 | // aix-NEXT: sth [[REG1]], 8(3) | |
| 76 | // aix-NEXT: std [[REG2]], 0(3) | |
| 64 | 77 | // elfv1-be: lhz [[REG1:.*]], 8(4) |
| 65 | 78 | // elfv1-be-NEXT: ld [[REG2:.*]], 0(4) |
| 66 | 79 | // elfv1-be-NEXT: sth [[REG1]], 8(3) |
| ... | ... | @@ -78,6 +91,10 @@ extern "C" fn read_medium(x: &FiveU16s) -> FiveU16s { |
| 78 | 91 | } |
| 79 | 92 | |
| 80 | 93 | // CHECK-LABEL: read_small |
| 94 | // aix: lbz [[REG1:.*]], 2(4) | |
| 95 | // aix-NEXT: lhz [[REG2:.*]], 0(4) | |
| 96 | // aix-NEXT: stb [[REG1]], 2(3) | |
| 97 | // aix-NEXT: sth [[REG2]], 0(3) | |
| 81 | 98 | // elfv1-be: lbz [[REG1:.*]], 2(4) |
| 82 | 99 | // elfv1-be-NEXT: lhz [[REG2:.*]], 0(4) |
| 83 | 100 | // elfv1-be-NEXT: stb [[REG1]], 2(3) |
| ... | ... | @@ -95,9 +112,17 @@ extern "C" fn read_small(x: &ThreeU8s) -> ThreeU8s { |
| 95 | 112 | } |
| 96 | 113 | |
| 97 | 114 | // CHECK-LABEL: write_large |
| 98 | // CHECK: std 3, 0(6) | |
| 115 | // aix: std 3, 48(1) | |
| 116 | // aix-NEXT: rldicl [[REG1:.*]], 5, 32, 32 | |
| 117 | // aix-NEXT: std 5, 64(1) | |
| 118 | // aix-NEXT: std 4, 56(1) | |
| 119 | // aix-NEXT: stw [[REG1]], 16(6) | |
| 120 | // aix-NEXT: addi [[REG2:.*]], 1, 48 | |
| 121 | // aix-NEXT: lxvd2x 0, 0, [[REG2]] | |
| 122 | // aix-NEXT: stxvd2x 0, 0, 6 | |
| 123 | // elf: std 3, 0(6) | |
| 99 | 124 | // be-NEXT: rldicl [[REG1:.*]], 5, 32, 32 |
| 100 | // CHECK-NEXT: std 4, 8(6) | |
| 125 | // elf-NEXT: std 4, 8(6) | |
| 101 | 126 | // be-NEXT: stw [[REG1]], 16(6) |
| 102 | 127 | // elfv2-le-NEXT: stw 5, 16(6) |
| 103 | 128 | // CHECK-NEXT: blr |
| ... | ... | @@ -107,7 +132,12 @@ extern "C" fn write_large(x: FiveU32s, dest: &mut FiveU32s) { |
| 107 | 132 | } |
| 108 | 133 | |
| 109 | 134 | // CHECK-LABEL: write_medium |
| 110 | // CHECK: std 3, 0(5) | |
| 135 | // aix: std 4, 56(1) | |
| 136 | // aix-NEXT: rldicl [[REG1:.*]], 4, 16, 48 | |
| 137 | // aix-NEXT: std 3, 48(1) | |
| 138 | // aix-NEXT: std 3, 0(5) | |
| 139 | // aix-NEXT: sth [[REG1]], 8(5) | |
| 140 | // elf: std 3, 0(5) | |
| 111 | 141 | // be-NEXT: rldicl [[REG1:.*]], 4, 16, 48 |
| 112 | 142 | // be-NEXT: sth [[REG1]], 8(5) |
| 113 | 143 | // elfv2-le-NEXT: sth 4, 8(5) |
| ... | ... | @@ -118,6 +148,11 @@ extern "C" fn write_medium(x: FiveU16s, dest: &mut FiveU16s) { |
| 118 | 148 | } |
| 119 | 149 | |
| 120 | 150 | // CHECK-LABEL: write_small |
| 151 | // aix: std 3, 48(1) | |
| 152 | // aix-NEXT: rldicl [[REG1:.*]], 3, 16, 48 | |
| 153 | // aix-NEXT: sth 3, 0(4) | |
| 154 | // aix-NEXT: lbz 3, 50(1) | |
| 155 | // aix-NEXT: stb [[REG1]], 2(4) | |
| 121 | 156 | // be: stb 3, 2(4) |
| 122 | 157 | // be-NEXT: srwi [[REG1:.*]], 3, 8 |
| 123 | 158 | // be-NEXT: sth [[REG1]], 0(4) |
tests/codegen/default-visibility.rs+16| ... | ... | @@ -31,3 +31,19 @@ pub static tested_symbol: [u8; 6] = *b"foobar"; |
| 31 | 31 | // PROTECTED: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = protected constant |
| 32 | 32 | // INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant |
| 33 | 33 | // DEFAULT: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant |
| 34 | ||
| 35 | pub fn do_memcmp(left: &[u8], right: &[u8]) -> i32 { | |
| 36 | left.cmp(right) as i32 | |
| 37 | } | |
| 38 | ||
| 39 | // CHECK: define {{.*}} @{{.*}}do_memcmp{{.*}} { | |
| 40 | // CHECK: } | |
| 41 | ||
| 42 | // `do_memcmp` should invoke core::intrinsic::compare_bytes which emits a call | |
| 43 | // to the C symbol `memcmp` (at least on x86_64-unknown-linux-gnu). This symbol | |
| 44 | // should *not* be declared hidden or protected. | |
| 45 | ||
| 46 | // HIDDEN: declare i32 @memcmp | |
| 47 | // PROTECTED: declare i32 @memcmp | |
| 48 | // INTERPOSABLE: declare i32 @memcmp | |
| 49 | // DEFAULT: declare i32 @memcmp |
tests/run-make/msvc-lld-thinlto-imp-symbols/issue_81408.rs created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | use std::sync::atomic::{AtomicPtr, Ordering}; | |
| 2 | ||
| 3 | #[inline(always)] | |
| 4 | pub fn memrchr() { | |
| 5 | fn detect() {} | |
| 6 | ||
| 7 | static CROSS_CRATE_STATIC_ITEM: AtomicPtr<()> = AtomicPtr::new(detect as *mut ()); | |
| 8 | ||
| 9 | unsafe { | |
| 10 | let fun = CROSS_CRATE_STATIC_ITEM.load(Ordering::SeqCst); | |
| 11 | std::mem::transmute::<*mut (), fn()>(fun)() | |
| 12 | } | |
| 13 | } |
tests/run-make/msvc-lld-thinlto-imp-symbols/main.rs created+5| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | extern crate issue_81408; | |
| 2 | ||
| 3 | fn main() { | |
| 4 | issue_81408::memrchr(); | |
| 5 | } |
tests/run-make/msvc-lld-thinlto-imp-symbols/rmake.rs created+33| ... | ... | @@ -0,0 +1,33 @@ |
| 1 | // This is a non-regression test for issue #81408 involving an lld bug and ThinLTO, on windows. | |
| 2 | // MSVC's link.exe doesn't need any workarounds in rustc, but lld does, so we'll check that the | |
| 3 | // binary runs successfully instead of using a codegen test. | |
| 4 | ||
| 5 | //@ only-x86_64-pc-windows-msvc | |
| 6 | //@ needs-rust-lld | |
| 7 | //@ ignore-cross-compile: the built binary is executed | |
| 8 | ||
| 9 | use run_make_support::{run, rustc}; | |
| 10 | ||
| 11 | fn test_with_linker(linker: &str) { | |
| 12 | rustc().input("issue_81408.rs").crate_name("issue_81408").crate_type("lib").opt().run(); | |
| 13 | rustc() | |
| 14 | .input("main.rs") | |
| 15 | .crate_type("bin") | |
| 16 | .arg("-Clto=thin") | |
| 17 | .opt() | |
| 18 | .arg(&format!("-Clinker={linker}")) | |
| 19 | .extern_("issue_81408", "libissue_81408.rlib") | |
| 20 | .run(); | |
| 21 | ||
| 22 | // To make possible failures clearer, print an intro that will only be shown if the test does | |
| 23 | // fail when running the binary. | |
| 24 | eprint!("Running binary linked with {linker}... "); | |
| 25 | run("main"); | |
| 26 | eprintln!("ok"); | |
| 27 | } | |
| 28 | ||
| 29 | fn main() { | |
| 30 | // We want the reproducer to work when linked with both linkers. | |
| 31 | test_with_linker("link"); | |
| 32 | test_with_linker("rust-lld"); | |
| 33 | } |