Skip to content

Commit e4b325b

Browse files
authored
Unrolled build for rust-lang#129613
Rollup merge of rust-lang#129613 - RalfJung:interpret-target-feat, r=saethlin interpret: do not make const-eval query result depend on tcx.sess The check against calling functions with missing target features uses `tcx.sess` to determine which target features are available. However, this can differ between different crates in a crate graph, so the same const-eval query can come to different conclusions about whether a constant evaluates successfully or not -- which is bad, we should consistently get the same result everywhere.
2 parents ac77e88 + 7a290fc commit e4b325b

File tree

8 files changed

+70
-62
lines changed

8 files changed

+70
-62
lines changed

compiler/rustc_const_eval/messages.ftl

-3
Original file line numberDiff line numberDiff line change
@@ -402,9 +402,6 @@ const_eval_unallowed_mutable_refs =
402402
const_eval_unallowed_op_in_const_context =
403403
{$msg}
404404
405-
const_eval_unavailable_target_features_for_fn =
406-
calling a function that requires unavailable target features: {$unavailable_feats}
407-
408405
const_eval_uninhabited_enum_variant_read =
409406
read discriminant of an uninhabited enum variant
410407
const_eval_uninhabited_enum_variant_written =

compiler/rustc_const_eval/src/interpret/call.rs

+7-37
Original file line numberDiff line numberDiff line change
@@ -311,34 +311,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
311311
Ok(())
312312
}
313313

314-
fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> {
315-
// Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
316-
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
317-
if !self.tcx.sess.target.is_like_wasm
318-
&& attrs
319-
.target_features
320-
.iter()
321-
.any(|feature| !self.tcx.sess.target_features.contains(&feature.name))
322-
{
323-
throw_ub_custom!(
324-
fluent::const_eval_unavailable_target_features_for_fn,
325-
unavailable_feats = attrs
326-
.target_features
327-
.iter()
328-
.filter(|&feature| !feature.implied
329-
&& !self.tcx.sess.target_features.contains(&feature.name))
330-
.fold(String::new(), |mut s, feature| {
331-
if !s.is_empty() {
332-
s.push_str(", ");
333-
}
334-
s.push_str(feature.name.as_str());
335-
s
336-
}),
337-
);
338-
}
339-
Ok(())
340-
}
341-
342314
/// The main entry point for creating a new stack frame: performs ABI checks and initializes
343315
/// arguments.
344316
#[instrument(skip(self), level = "trace")]
@@ -360,20 +332,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
360332
throw_unsup_format!("calling a c-variadic function is not supported");
361333
}
362334

363-
if M::enforce_abi(self) {
364-
if caller_fn_abi.conv != callee_fn_abi.conv {
365-
throw_ub_custom!(
366-
fluent::const_eval_incompatible_calling_conventions,
367-
callee_conv = format!("{:?}", callee_fn_abi.conv),
368-
caller_conv = format!("{:?}", caller_fn_abi.conv),
369-
)
370-
}
335+
if caller_fn_abi.conv != callee_fn_abi.conv {
336+
throw_ub_custom!(
337+
fluent::const_eval_incompatible_calling_conventions,
338+
callee_conv = format!("{:?}", callee_fn_abi.conv),
339+
caller_conv = format!("{:?}", caller_fn_abi.conv),
340+
)
371341
}
372342

373343
// Check that all target features required by the callee (i.e., from
374344
// the attribute `#[target_feature(enable = ...)]`) are enabled at
375345
// compile time.
376-
self.check_fn_target_features(instance)?;
346+
M::check_fn_target_features(self, instance)?;
377347

378348
if !callee_fn_abi.can_unwind {
379349
// The callee cannot unwind, so force the `Unreachable` unwind handling.

compiler/rustc_const_eval/src/interpret/machine.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,6 @@ pub trait Machine<'tcx>: Sized {
173173
false
174174
}
175175

176-
/// Whether function calls should be [ABI](CallAbi)-checked.
177-
fn enforce_abi(_ecx: &InterpCx<'tcx, Self>) -> bool {
178-
true
179-
}
180-
181176
/// Whether Assert(OverflowNeg) and Assert(Overflow) MIR terminators should actually
182177
/// check for overflow.
183178
fn ignore_optional_overflow_checks(_ecx: &InterpCx<'tcx, Self>) -> bool;
@@ -238,6 +233,13 @@ pub trait Machine<'tcx>: Sized {
238233
unwind: mir::UnwindAction,
239234
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>>;
240235

236+
/// Check whether the given function may be executed on the current machine, in terms of the
237+
/// target features is requires.
238+
fn check_fn_target_features(
239+
_ecx: &InterpCx<'tcx, Self>,
240+
_instance: ty::Instance<'tcx>,
241+
) -> InterpResult<'tcx>;
242+
241243
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
242244
fn assert_panic(
243245
ecx: &mut InterpCx<'tcx, Self>,
@@ -614,6 +616,16 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
614616
unreachable!("unwinding cannot happen during compile-time evaluation")
615617
}
616618

619+
#[inline(always)]
620+
fn check_fn_target_features(
621+
_ecx: &InterpCx<$tcx, Self>,
622+
_instance: ty::Instance<$tcx>,
623+
) -> InterpResult<$tcx> {
624+
// For now we don't do any checking here. We can't use `tcx.sess` because that can differ
625+
// between crates, and we need to ensure that const-eval always behaves the same.
626+
Ok(())
627+
}
628+
617629
#[inline(always)]
618630
fn call_extra_fn(
619631
_ecx: &mut InterpCx<$tcx, Self>,

src/tools/miri/src/machine.rs

+37-5
Original file line numberDiff line numberDiff line change
@@ -946,16 +946,48 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
946946
ecx.machine.validation == ValidationMode::Deep
947947
}
948948

949-
#[inline(always)]
950-
fn enforce_abi(_ecx: &MiriInterpCx<'tcx>) -> bool {
951-
true
952-
}
953-
954949
#[inline(always)]
955950
fn ignore_optional_overflow_checks(ecx: &MiriInterpCx<'tcx>) -> bool {
956951
!ecx.tcx.sess.overflow_checks()
957952
}
958953

954+
fn check_fn_target_features(
955+
ecx: &MiriInterpCx<'tcx>,
956+
instance: ty::Instance<'tcx>,
957+
) -> InterpResult<'tcx> {
958+
let attrs = ecx.tcx.codegen_fn_attrs(instance.def_id());
959+
if attrs
960+
.target_features
961+
.iter()
962+
.any(|feature| !ecx.tcx.sess.target_features.contains(&feature.name))
963+
{
964+
let unavailable = attrs
965+
.target_features
966+
.iter()
967+
.filter(|&feature| {
968+
!feature.implied && !ecx.tcx.sess.target_features.contains(&feature.name)
969+
})
970+
.fold(String::new(), |mut s, feature| {
971+
if !s.is_empty() {
972+
s.push_str(", ");
973+
}
974+
s.push_str(feature.name.as_str());
975+
s
976+
});
977+
let msg = format!(
978+
"calling a function that requires unavailable target features: {unavailable}"
979+
);
980+
// On WASM, this is not UB, but instead gets rejected during validation of the module
981+
// (see #84988).
982+
if ecx.tcx.sess.target.is_like_wasm {
983+
throw_machine_stop!(TerminationInfo::Abort(msg));
984+
} else {
985+
throw_ub_format!("{msg}");
986+
}
987+
}
988+
Ok(())
989+
}
990+
959991
#[inline(always)]
960992
fn find_mir_or_eval_fn(
961993
ecx: &mut MiriInterpCx<'tcx>,

src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs renamed to src/tools/miri/tests/panic/target_feature_wasm.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
//@compile-flags: -C target-feature=-simd128
33

44
fn main() {
5-
// Calling functions with `#[target_feature]` is not unsound on WASM, see #84988
5+
// Calling functions with `#[target_feature]` is not unsound on WASM, see #84988.
6+
// But if the compiler actually uses the target feature, it will lead to an error when the module is loaded.
7+
// We emulate this with an "unsupported" error.
68
assert!(!cfg!(target_feature = "simd128"));
79
simd128_fn();
810
}

tests/ui/consts/const-eval/const_fn_target_feature.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//@ only-x86_64
22
// Set the base cpu explicitly, in case the default has been changed.
33
//@ compile-flags: -C target-cpu=x86-64 -C target-feature=+ssse3
4+
//@ check-pass
45

56
#![crate_type = "lib"]
67

@@ -9,7 +10,8 @@ const A: () = unsafe { ssse3_fn() };
910

1011
// error (avx2 not enabled at compile time)
1112
const B: () = unsafe { avx2_fn() };
12-
//~^ ERROR evaluation of constant value failed
13+
// FIXME: currently we do not detect this UB, since we don't want the result of const-eval
14+
// to depend on `tcx.sess` which can differ between crates in a crate graph.
1315

1416
#[target_feature(enable = "ssse3")]
1517
const unsafe fn ssse3_fn() {}

tests/ui/consts/const-eval/const_fn_target_feature.stderr

-9
This file was deleted.

tests/ui/consts/const-eval/const_fn_target_feature_wasm.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
#[cfg(target_feature = "simd128")]
88
compile_error!("simd128 target feature should be disabled");
99

10-
// Calling functions with `#[target_feature]` is not unsound on WASM, see #84988
10+
// Calling functions with `#[target_feature]` is not unsound on WASM, see #84988.
11+
// (It can still lead to a runtime error though so we'd be in our right to abort execution,
12+
// just not to declare it UB.)
1113
const A: () = simd128_fn();
1214

1315
#[target_feature(enable = "simd128")]

0 commit comments

Comments
 (0)