Skip to content

Commit f17cf74

Browse files
committed
Auto merge of #135095 - matthiaskrgr:rollup-tmgxckq, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #133964 (core: implement `bool::select_unpredictable`) - #135001 (Allow using self-contained LLD in bootstrap) - #135055 (Report impl method has stricter requirements even when RPITIT inference gets in the way) - #135064 (const-in-pattern: test that the PartialEq impl does not need to be const) - #135066 (bootstrap: support `./x check run-make-support`) - #135069 (remove unused function params) - #135084 (Update carrying_mul_add test to tolerate `nuw`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 49761b0 + 75e412b commit f17cf74

25 files changed

+270
-86
lines changed

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+20
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,26 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
529529
let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
530530
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
531531

532+
// Check that the where clauses of the impl are satisfied by the hybrid param env.
533+
// You might ask -- what does this have to do with RPITIT inference? Nothing.
534+
// We check these because if the where clauses of the signatures do not match
535+
// up, then we don't want to give spurious other errors that point at the RPITITs.
536+
// They're not necessary to check, though, because we already check them in
537+
// `compare_method_predicate_entailment`.
538+
let impl_m_own_bounds = tcx.predicates_of(impl_m_def_id).instantiate_own_identity();
539+
for (predicate, span) in impl_m_own_bounds {
540+
let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
541+
let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
542+
543+
let cause =
544+
ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem {
545+
impl_item_def_id: impl_m_def_id,
546+
trait_item_def_id: trait_m.def_id,
547+
kind: impl_m.kind,
548+
});
549+
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
550+
}
551+
532552
// Normalize the impl signature with fresh variables for lifetime inference.
533553
let misc_cause = ObligationCause::misc(return_span, impl_m_def_id);
534554
let impl_sig = ocx.normalize(

compiler/rustc_middle/src/ty/diagnostics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ impl<'tcx> Ty<'tcx> {
6969
/// description in error messages. This is used in the primary span label. Beyond what
7070
/// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
7171
/// ADTs with no type arguments.
72-
pub fn is_simple_text(self, tcx: TyCtxt<'tcx>) -> bool {
72+
pub fn is_simple_text(self) -> bool {
7373
match self.kind() {
7474
Adt(_, args) => args.non_erasable_generics().next().is_none(),
75-
Ref(_, ty, _) => ty.is_simple_text(tcx),
75+
Ref(_, ty, _) => ty.is_simple_text(),
7676
_ => self.is_simple_ty(),
7777
}
7878
}

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

+4
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,10 @@ fn type_has_partial_eq_impl<'tcx>(
491491
// `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem
492492
// we'll need to leave some sort of trace of this requirement in the MIR so that borrowck
493493
// can ensure that the type really implements `PartialEq`.
494+
// We also do *not* require `const PartialEq`, not even in `const fn`. This violates the model
495+
// that patterns can only do things that the code could also do without patterns, but it is
496+
// needed for backwards compatibility. The actual pattern matching compares primitive values,
497+
// `PartialEq::eq` never gets invoked, so there's no risk of us running non-const code.
494498
(
495499
infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation),
496500
automatically_derived,

compiler/rustc_mir_transform/src/coroutine.rs

+9-19
Original file line numberDiff line numberDiff line change
@@ -1822,9 +1822,6 @@ impl<'tcx> Visitor<'tcx> for EnsureCoroutineFieldAssignmentsNeverAlias<'_> {
18221822
fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &CoroutineLayout<'tcx>, body: &Body<'tcx>) {
18231823
let mut linted_tys = FxHashSet::default();
18241824

1825-
// We want a user-facing param-env.
1826-
let param_env = tcx.param_env(body.source.def_id());
1827-
18281825
for (variant, yield_source_info) in
18291826
layout.variant_fields.iter().zip(&layout.variant_source_info)
18301827
{
@@ -1838,7 +1835,7 @@ fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &CoroutineLayout<'tcx>, bo
18381835
continue;
18391836
};
18401837

1841-
check_must_not_suspend_ty(tcx, decl.ty, hir_id, param_env, SuspendCheckData {
1838+
check_must_not_suspend_ty(tcx, decl.ty, hir_id, SuspendCheckData {
18421839
source_span: decl.source_info.span,
18431840
yield_span: yield_source_info.span,
18441841
plural_len: 1,
@@ -1868,7 +1865,6 @@ fn check_must_not_suspend_ty<'tcx>(
18681865
tcx: TyCtxt<'tcx>,
18691866
ty: Ty<'tcx>,
18701867
hir_id: hir::HirId,
1871-
param_env: ty::ParamEnv<'tcx>,
18721868
data: SuspendCheckData<'_>,
18731869
) -> bool {
18741870
if ty.is_unit() {
@@ -1883,16 +1879,13 @@ fn check_must_not_suspend_ty<'tcx>(
18831879
ty::Adt(_, args) if ty.is_box() => {
18841880
let boxed_ty = args.type_at(0);
18851881
let allocator_ty = args.type_at(1);
1886-
check_must_not_suspend_ty(tcx, boxed_ty, hir_id, param_env, SuspendCheckData {
1882+
check_must_not_suspend_ty(tcx, boxed_ty, hir_id, SuspendCheckData {
18871883
descr_pre: &format!("{}boxed ", data.descr_pre),
18881884
..data
1889-
}) || check_must_not_suspend_ty(
1890-
tcx,
1891-
allocator_ty,
1892-
hir_id,
1893-
param_env,
1894-
SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data },
1895-
)
1885+
}) || check_must_not_suspend_ty(tcx, allocator_ty, hir_id, SuspendCheckData {
1886+
descr_pre: &format!("{}allocator ", data.descr_pre),
1887+
..data
1888+
})
18961889
}
18971890
ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data),
18981891
// FIXME: support adding the attribute to TAITs
@@ -1937,7 +1930,7 @@ fn check_must_not_suspend_ty<'tcx>(
19371930
let mut has_emitted = false;
19381931
for (i, ty) in fields.iter().enumerate() {
19391932
let descr_post = &format!(" in tuple element {i}");
1940-
if check_must_not_suspend_ty(tcx, ty, hir_id, param_env, SuspendCheckData {
1933+
if check_must_not_suspend_ty(tcx, ty, hir_id, SuspendCheckData {
19411934
descr_post,
19421935
..data
19431936
}) {
@@ -1948,7 +1941,7 @@ fn check_must_not_suspend_ty<'tcx>(
19481941
}
19491942
ty::Array(ty, len) => {
19501943
let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix);
1951-
check_must_not_suspend_ty(tcx, ty, hir_id, param_env, SuspendCheckData {
1944+
check_must_not_suspend_ty(tcx, ty, hir_id, SuspendCheckData {
19521945
descr_pre,
19531946
// FIXME(must_not_suspend): This is wrong. We should handle printing unevaluated consts.
19541947
plural_len: len.try_to_target_usize(tcx).unwrap_or(0) as usize + 1,
@@ -1959,10 +1952,7 @@ fn check_must_not_suspend_ty<'tcx>(
19591952
// may not be considered live across the await point.
19601953
ty::Ref(_region, ty, _mutability) => {
19611954
let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix);
1962-
check_must_not_suspend_ty(tcx, ty, hir_id, param_env, SuspendCheckData {
1963-
descr_pre,
1964-
..data
1965-
})
1955+
check_must_not_suspend_ty(tcx, ty, hir_id, SuspendCheckData { descr_pre, ..data })
19661956
}
19671957
_ => false,
19681958
}

compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1496,8 +1496,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
14961496
ValuePairs::Terms(ExpectedFound { expected, found }) => {
14971497
match (expected.unpack(), found.unpack()) {
14981498
(ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
1499-
let is_simple_err = expected.is_simple_text(self.tcx)
1500-
&& found.is_simple_text(self.tcx);
1499+
let is_simple_err =
1500+
expected.is_simple_text() && found.is_simple_text();
15011501
OpaqueTypesVisitor::visit_expected_found(
15021502
self.tcx, expected, found, span,
15031503
)
@@ -1736,8 +1736,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
17361736
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
17371737
(false, _) => "".to_string(),
17381738
};
1739-
if !(values.expected.is_simple_text(self.tcx)
1740-
&& values.found.is_simple_text(self.tcx))
1739+
if !(values.expected.is_simple_text() && values.found.is_simple_text())
17411740
|| (exp_found.is_some_and(|ef| {
17421741
// This happens when the type error is a subset of the expectation,
17431742
// like when you have two references but one is `usize` and the other

library/core/src/bool.rs

+48
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,52 @@ impl bool {
6161
pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
6262
if self { Some(f()) } else { None }
6363
}
64+
65+
/// Returns either `true_val` or `false_val` depending on the value of
66+
/// `self`, with a hint to the compiler that `self` is unlikely
67+
/// to be correctly predicted by a CPU’s branch predictor.
68+
///
69+
/// This method is functionally equivalent to
70+
/// ```ignore (this is just for illustrative purposes)
71+
/// fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
72+
/// if b { true_val } else { false_val }
73+
/// }
74+
/// ```
75+
/// but might generate different assembly. In particular, on platforms with
76+
/// a conditional move or select instruction (like `cmov` on x86 or `csel`
77+
/// on ARM) the optimizer might use these instructions to avoid branches,
78+
/// which can benefit performance if the branch predictor is struggling
79+
/// with predicting `condition`, such as in an implementation of binary
80+
/// search.
81+
///
82+
/// Note however that this lowering is not guaranteed (on any platform) and
83+
/// should not be relied upon when trying to write constant-time code. Also
84+
/// be aware that this lowering might *decrease* performance if `condition`
85+
/// is well-predictable. It is advisable to perform benchmarks to tell if
86+
/// this function is useful.
87+
///
88+
/// # Examples
89+
///
90+
/// Distribute values evenly between two buckets:
91+
/// ```
92+
/// #![feature(select_unpredictable)]
93+
///
94+
/// use std::hash::BuildHasher;
95+
///
96+
/// fn append<H: BuildHasher>(hasher: &H, v: i32, bucket_one: &mut Vec<i32>, bucket_two: &mut Vec<i32>) {
97+
/// let hash = hasher.hash_one(&v);
98+
/// let bucket = (hash % 2 == 0).select_unpredictable(bucket_one, bucket_two);
99+
/// bucket.push(v);
100+
/// }
101+
/// # let hasher = std::collections::hash_map::RandomState::new();
102+
/// # let mut bucket_one = Vec::new();
103+
/// # let mut bucket_two = Vec::new();
104+
/// # append(&hasher, 42, &mut bucket_one, &mut bucket_two);
105+
/// # assert_eq!(bucket_one.len() + bucket_two.len(), 1);
106+
/// ```
107+
#[inline(always)]
108+
#[unstable(feature = "select_unpredictable", issue = "133962")]
109+
pub fn select_unpredictable<T>(self, true_val: T, false_val: T) -> T {
110+
crate::intrinsics::select_unpredictable(self, true_val, false_val)
111+
}
64112
}

library/core/src/intrinsics/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1545,7 +1545,7 @@ pub const fn unlikely(b: bool) -> bool {
15451545
/// Therefore, implementations must not require the user to uphold
15461546
/// any safety invariants.
15471547
///
1548-
/// This intrinsic does not have a stable counterpart.
1548+
/// The public form of this instrinsic is [`bool::select_unpredictable`].
15491549
#[unstable(feature = "core_intrinsics", issue = "none")]
15501550
#[rustc_intrinsic]
15511551
#[rustc_nounwind]

library/core/src/slice/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#![stable(feature = "rust1", since = "1.0.0")]
88

99
use crate::cmp::Ordering::{self, Equal, Greater, Less};
10-
use crate::intrinsics::{exact_div, select_unpredictable, unchecked_sub};
10+
use crate::intrinsics::{exact_div, unchecked_sub};
1111
use crate::mem::{self, SizedTypeProperties};
1212
use crate::num::NonZero;
1313
use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive};
@@ -2835,7 +2835,7 @@ impl<T> [T] {
28352835
// Binary search interacts poorly with branch prediction, so force
28362836
// the compiler to use conditional moves if supported by the target
28372837
// architecture.
2838-
base = select_unpredictable(cmp == Greater, base, mid);
2838+
base = (cmp == Greater).select_unpredictable(base, mid);
28392839

28402840
// This is imprecise in the case where `size` is odd and the
28412841
// comparison returns Greater: the mid element still gets included

src/bootstrap/src/core/build_steps/check.rs

+5
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,11 @@ tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools" });
491491
tool_check_step!(TestFloatParse { path: "src/etc/test-float-parse" });
492492

493493
tool_check_step!(Bootstrap { path: "src/bootstrap", default: false });
494+
495+
// `run-make-support` will be built as part of suitable run-make compiletest test steps, but support
496+
// check to make it easier to work on.
497+
tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false });
498+
494499
// Compiletest is implicitly "checked" when it gets built in order to run tests,
495500
// so this is mainly for people working on compiletest to run locally.
496501
tool_check_step!(Compiletest { path: "src/tools/compiletest", default: false });

src/bootstrap/src/core/build_steps/test.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1893,7 +1893,6 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
18931893

18941894
let mut targetflags = flags;
18951895
targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
1896-
targetflags.extend(linker_flags(builder, compiler.host, LldThreads::No));
18971896
for flag in targetflags {
18981897
cmd.arg("--target-rustcflags").arg(flag);
18991898
}

src/bootstrap/src/core/builder/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,7 @@ impl<'a> Builder<'a> {
935935
check::RustAnalyzer,
936936
check::TestFloatParse,
937937
check::Bootstrap,
938+
check::RunMakeSupport,
938939
check::Compiletest,
939940
),
940941
Kind::Test => describe!(

src/bootstrap/src/utils/helpers.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,20 @@ pub fn linker_flags(
481481
) -> Vec<String> {
482482
let mut args = vec![];
483483
if !builder.is_lld_direct_linker(target) && builder.config.lld_mode.is_used() {
484-
args.push(String::from("-Clink-arg=-fuse-ld=lld"));
484+
match builder.config.lld_mode {
485+
LldMode::External => {
486+
args.push("-Clinker-flavor=gnu-lld-cc".to_string());
487+
// FIXME(kobzol): remove this flag once MCP510 gets stabilized
488+
args.push("-Zunstable-options".to_string());
489+
}
490+
LldMode::SelfContained => {
491+
args.push("-Clinker-flavor=gnu-lld-cc".to_string());
492+
args.push("-Clink-self-contained=+linker".to_string());
493+
// FIXME(kobzol): remove this flag once MCP510 gets stabilized
494+
args.push("-Zunstable-options".to_string());
495+
}
496+
LldMode::Unused => unreachable!(),
497+
};
485498

486499
if matches!(lld_threads, LldThreads::No) {
487500
args.push(format!(
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@ compile-flags: -O
2+
3+
#![feature(select_unpredictable)]
4+
#![crate_type = "lib"]
5+
6+
#[no_mangle]
7+
pub fn test_int(p: bool, a: u64, b: u64) -> u64 {
8+
// CHECK-LABEL: define{{.*}} @test_int
9+
// CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable
10+
p.select_unpredictable(a, b)
11+
}
12+
13+
#[no_mangle]
14+
pub fn test_pair(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) {
15+
// CHECK-LABEL: define{{.*}} @test_pair
16+
// CHECK: select i1 %p, {{.*}}, !unpredictable
17+
p.select_unpredictable(a, b)
18+
}
19+
20+
struct Large {
21+
e: [u64; 100],
22+
}
23+
24+
#[no_mangle]
25+
pub fn test_struct(p: bool, a: Large, b: Large) -> Large {
26+
// CHECK-LABEL: define{{.*}} @test_struct
27+
// CHECK: select i1 %p, {{.*}}, !unpredictable
28+
p.select_unpredictable(a, b)
29+
}
30+
31+
#[no_mangle]
32+
pub fn test_zst(p: bool, a: (), b: ()) -> () {
33+
// CHECK-LABEL: define{{.*}} @test_zst
34+
p.select_unpredictable(a, b)
35+
}

tests/codegen/intrinsics/carrying_mul_add.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub unsafe fn cma_u128(a: u128, b: u128, c: u128, d: u128) -> (u128, u128) {
8484
// RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0
8585
// RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1
8686
// OPT: store i128 [[LOW]], ptr %_0
87-
// OPT: [[P1:%.+]] = getelementptr inbounds i8, ptr %_0, {{i32|i64}} 16
87+
// OPT: [[P1:%.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %_0, {{i32|i64}} 16
8888
// OPT: store i128 [[HIGH]], ptr [[P1]]
8989
// CHECK: ret void
9090
carrying_mul_add(a, b, c, d)
@@ -111,7 +111,7 @@ pub unsafe fn cma_i128(a: i128, b: i128, c: i128, d: i128) -> (u128, i128) {
111111
// RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0
112112
// RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1
113113
// OPT: store i128 [[LOW]], ptr %_0
114-
// OPT: [[P1:%.+]] = getelementptr inbounds i8, ptr %_0, {{i32|i64}} 16
114+
// OPT: [[P1:%.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %_0, {{i32|i64}} 16
115115
// OPT: store i128 [[HIGH]], ptr [[P1]]
116116
// CHECK: ret void
117117
carrying_mul_add(a, b, c, d)

tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ struct Baz {}
1111

1212
impl Foo for Baz {
1313
async fn bar<F>(&mut self, _func: F) -> ()
14-
//~^ ERROR `F` cannot be sent between threads safely
1514
where
1615
F: FnMut() + Send,
16+
//~^ impl has stricter requirements than trait
1717
{
1818
()
1919
}
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
1-
error[E0277]: `F` cannot be sent between threads safely
2-
--> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:13:5
1+
error[E0276]: impl has stricter requirements than trait
2+
--> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:15:22
33
|
4-
LL | / async fn bar<F>(&mut self, _func: F) -> ()
5-
LL | |
4+
LL | / fn bar<F>(&mut self, func: F) -> impl std::future::Future<Output = ()> + Send
65
LL | | where
7-
LL | | F: FnMut() + Send,
8-
| |__________________________^ `F` cannot be sent between threads safely
9-
|
10-
note: required by a bound in `<Baz as Foo>::bar`
11-
--> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:16:22
12-
|
13-
LL | async fn bar<F>(&mut self, _func: F) -> ()
14-
| --- required by a bound in this associated function
6+
LL | | F: FnMut();
7+
| |___________________- definition of `bar` from trait
158
...
16-
LL | F: FnMut() + Send,
17-
| ^^^^ required by this bound in `<Baz as Foo>::bar`
9+
LL | F: FnMut() + Send,
10+
| ^^^^ impl has extra requirement `F: Send`
1811

1912
error: aborting due to 1 previous error
2013

21-
For more information about this error, try `rustc --explain E0277`.
14+
For more information about this error, try `rustc --explain E0276`.

0 commit comments

Comments
 (0)