diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-08-28 17:12:17 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-28 17:12:17 +0200 |
| commit | 39e840f8042cddf100710e802d37d9599b997f11 (patch) | |
| tree | 142f2de6b72fa39257dd4140dffa6ff8664d8d5f /compiler/rustc_const_eval/src | |
| parent | 3456b1d245f76dab9034a54701f942ed63974cf0 (diff) | |
| parent | 7a290fce907da1cda0687fe5e48372c08fe40ab8 (diff) | |
| download | rust-39e840f8042cddf100710e802d37d9599b997f11.tar.gz rust-39e840f8042cddf100710e802d37d9599b997f11.zip | |
Rollup merge of #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.
Diffstat (limited to 'compiler/rustc_const_eval/src')
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/call.rs | 44 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/machine.rs | 22 |
2 files changed, 24 insertions, 42 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index f99283c49f5..61e8007e10e 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -311,34 +311,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(()) } - fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> { - // Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988 - let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); - if !self.tcx.sess.target.is_like_wasm - && attrs - .target_features - .iter() - .any(|feature| !self.tcx.sess.target_features.contains(&feature.name)) - { - throw_ub_custom!( - fluent::const_eval_unavailable_target_features_for_fn, - unavailable_feats = attrs - .target_features - .iter() - .filter(|&feature| !feature.implied - && !self.tcx.sess.target_features.contains(&feature.name)) - .fold(String::new(), |mut s, feature| { - if !s.is_empty() { - s.push_str(", "); - } - s.push_str(feature.name.as_str()); - s - }), - ); - } - Ok(()) - } - /// The main entry point for creating a new stack frame: performs ABI checks and initializes /// arguments. #[instrument(skip(self), level = "trace")] @@ -360,20 +332,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_unsup_format!("calling a c-variadic function is not supported"); } - if M::enforce_abi(self) { - if caller_fn_abi.conv != callee_fn_abi.conv { - throw_ub_custom!( - fluent::const_eval_incompatible_calling_conventions, - callee_conv = format!("{:?}", callee_fn_abi.conv), - caller_conv = format!("{:?}", caller_fn_abi.conv), - ) - } + if caller_fn_abi.conv != callee_fn_abi.conv { + throw_ub_custom!( + fluent::const_eval_incompatible_calling_conventions, + callee_conv = format!("{:?}", callee_fn_abi.conv), + caller_conv = format!("{:?}", caller_fn_abi.conv), + ) } // Check that all target features required by the callee (i.e., from // the attribute `#[target_feature(enable = ...)]`) are enabled at // compile time. - self.check_fn_target_features(instance)?; + M::check_fn_target_features(self, instance)?; if !callee_fn_abi.can_unwind { // The callee cannot unwind, so force the `Unreachable` unwind handling. diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index d30bd6c7013..88453245b84 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -173,11 +173,6 @@ pub trait Machine<'tcx>: Sized { false } - /// Whether function calls should be [ABI](CallAbi)-checked. - fn enforce_abi(_ecx: &InterpCx<'tcx, Self>) -> bool { - true - } - /// Whether Assert(OverflowNeg) and Assert(Overflow) MIR terminators should actually /// check for overflow. fn ignore_optional_overflow_checks(_ecx: &InterpCx<'tcx, Self>) -> bool; @@ -238,6 +233,13 @@ pub trait Machine<'tcx>: Sized { unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>>; + /// Check whether the given function may be executed on the current machine, in terms of the + /// target features is requires. + fn check_fn_target_features( + _ecx: &InterpCx<'tcx, Self>, + _instance: ty::Instance<'tcx>, + ) -> InterpResult<'tcx>; + /// Called to evaluate `Assert` MIR terminators that trigger a panic. fn assert_panic( ecx: &mut InterpCx<'tcx, Self>, @@ -618,6 +620,16 @@ pub macro compile_time_machine(<$tcx: lifetime>) { } #[inline(always)] + fn check_fn_target_features( + _ecx: &InterpCx<$tcx, Self>, + _instance: ty::Instance<$tcx>, + ) -> InterpResult<$tcx> { + // For now we don't do any checking here. We can't use `tcx.sess` because that can differ + // between crates, and we need to ensure that const-eval always behaves the same. + Ok(()) + } + + #[inline(always)] fn call_extra_fn( _ecx: &mut InterpCx<$tcx, Self>, fn_val: !, |
