Skip to content

Commit b55e20a

Browse files
committed
Auto merge of #151842 - eggyal:skip-deducing-parameter-attrs-during-ctfe, r=RalfJung
Do not deduce parameter attributes during CTFE *[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/151842)* Ever since #103172, `fn_abi_of_instance` might look at a function's body to deduce certain codegen optimization attributes for its indirectly-passed parameters beyond what can be determined purely from its signature (namely today `ArgAttribute::ReadOnly` and `ArgAttribute::CapturesNone`). Since #130201, looking at a function's body in this way entails generating, for any coroutine-closures, additional by-move MIR bodies (which aren't represented in the HIR)—but this requires knowing the types of their context and consequently cycles can ensue if such bodies are generated before typeck is complete (such as during CTFE). Since they have no bearing on the evaluation result, this patch breaks a subquery out from `fn_abi_of_instance`, `fn_abi_of_instance_no_deduced_attrs`, which returns the ABI before such parameter attributes are deduced; and that new subquery is used in CTFE instead (however, since parameter attributes are only deduced in optimized builds, as a performance optimization we avoid calling the original query unless we are performing such a build). Fixes #151748 Fixes #152497
2 parents b90dc1e + f460bb1 commit b55e20a

8 files changed

Lines changed: 262 additions & 84 deletions

File tree

compiler/rustc_const_eval/src/interpret/call.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
361361
} else {
362362
ty::List::empty()
363363
};
364-
let callee_fn_abi = self.fn_abi_of_instance(instance, extra_tys)?;
364+
let callee_fn_abi = self.fn_abi_of_instance_no_deduced_attrs(instance, extra_tys)?;
365365

366366
if caller_fn_abi.conv != callee_fn_abi.conv {
367367
throw_ub_custom!(
@@ -899,7 +899,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
899899
enter_trace_span!(M, resolve::resolve_drop_in_place, ty = ?place.layout.ty);
900900
ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty)
901901
};
902-
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
902+
let fn_abi = self.fn_abi_of_instance_no_deduced_attrs(instance, ty::List::empty())?;
903903

904904
let arg = self.mplace_to_ref(&place)?;
905905
let ret = MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?);

compiler/rustc_const_eval/src/interpret/eval_context.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,16 +153,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
153153
}
154154

155155
/// This inherent method takes priority over the trait method with the same name in FnAbiOf,
156-
/// and allows wrapping the actual [FnAbiOf::fn_abi_of_instance] with a tracing span.
157-
/// See [FnAbiOf::fn_abi_of_instance] for the original documentation.
156+
/// and allows wrapping the actual [FnAbiOf::fn_abi_of_instance_no_deduced_attrs] with a tracing span.
157+
/// See [FnAbiOf::fn_abi_of_instance_no_deduced_attrs] for the original documentation.
158158
#[inline(always)]
159-
pub fn fn_abi_of_instance(
159+
pub fn fn_abi_of_instance_no_deduced_attrs(
160160
&self,
161161
instance: ty::Instance<'tcx>,
162162
extra_args: &'tcx ty::List<Ty<'tcx>>,
163163
) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult {
164164
let _trace = enter_trace_span!(M, layouting::fn_abi_of_instance, ?instance, ?extra_args);
165-
FnAbiOf::fn_abi_of_instance(self, instance, extra_args)
165+
FnAbiOf::fn_abi_of_instance_no_deduced_attrs(self, instance, extra_args)
166166
}
167167
}
168168

compiler/rustc_const_eval/src/interpret/step.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
470470
let instance = self.resolve(def_id, args)?;
471471
(
472472
FnVal::Instance(instance),
473-
self.fn_abi_of_instance(instance, extra_args)?,
473+
self.fn_abi_of_instance_no_deduced_attrs(instance, extra_args)?,
474474
instance.def.requires_caller_location(*self.tcx),
475475
)
476476
}

compiler/rustc_middle/src/queries.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,12 +1801,38 @@ rustc_queries! {
18011801
desc { "computing call ABI of `{}` function pointers", key.value.0 }
18021802
}
18031803

1804-
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
1805-
/// direct calls to an `fn`.
1804+
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for direct calls*
1805+
/// to an `fn`. Indirectly-passed parameters in the returned ABI might not include all possible
1806+
/// codegen optimization attributes (such as `ReadOnly` or `CapturesNone`), as deducing these
1807+
/// requires inspection of function bodies that can lead to cycles when performed during typeck.
1808+
/// Post typeck, you should prefer the optimized ABI returned by `TyCtxt::fn_abi_of_instance`.
1809+
///
1810+
/// NB: the ABI returned by this query must not differ from that returned by
1811+
/// `fn_abi_of_instance_raw` in any other way.
1812+
///
1813+
/// * that includes virtual calls, which are represented by "direct calls" to an
1814+
/// `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1815+
query fn_abi_of_instance_no_deduced_attrs(
1816+
key: ty::PseudoCanonicalInput<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
1817+
) -> Result<&'tcx rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> {
1818+
desc { "computing unadjusted call ABI of `{}`", key.value.0 }
1819+
}
1820+
1821+
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for direct calls*
1822+
/// to an `fn`. Indirectly-passed parameters in the returned ABI will include applicable
1823+
/// codegen optimization attributes, including `ReadOnly` and `CapturesNone` -- deduction of
1824+
/// which requires inspection of function bodies that can lead to cycles when performed during
1825+
/// typeck. During typeck, you should therefore use instead the unoptimized ABI returned by
1826+
/// `fn_abi_of_instance_no_deduced_attrs`.
1827+
///
1828+
/// For performance reasons, you should prefer to call the inherent `TyCtxt::fn_abi_of_instance`
1829+
/// method rather than invoke this query: it delegates to this query if necessary, but where
1830+
/// possible delegates instead to the `fn_abi_of_instance_no_deduced_attrs` query (thus avoiding
1831+
/// unnecessary query system overhead).
18061832
///
1807-
/// NB: that includes virtual calls, which are represented by "direct calls"
1808-
/// to an `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1809-
query fn_abi_of_instance(
1833+
/// * that includes virtual calls, which are represented by "direct calls" to an
1834+
/// `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1835+
query fn_abi_of_instance_raw(
18101836
key: ty::PseudoCanonicalInput<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
18111837
) -> Result<&'tcx rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> {
18121838
desc { "computing call ABI of `{}`", key.value.0 }

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,11 +1369,56 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
13691369
)
13701370
}
13711371

1372-
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
1373-
/// direct calls to an `fn`.
1372+
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for direct calls*
1373+
/// to an `fn`. Indirectly-passed parameters in the returned ABI might not include all possible
1374+
/// codegen optimization attributes (such as `ReadOnly` or `CapturesNone`), as deducing these
1375+
/// requires inspection of function bodies that can lead to cycles when performed during typeck.
1376+
/// Post typeck, you should prefer the optimized ABI returned by `fn_abi_of_instance`.
13741377
///
1375-
/// NB: that includes virtual calls, which are represented by "direct calls"
1376-
/// to an `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1378+
/// NB: the ABI returned by this query must not differ from that returned by
1379+
/// `fn_abi_of_instance` in any other way.
1380+
///
1381+
/// * that includes virtual calls, which are represented by "direct calls" to an
1382+
/// `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1383+
#[inline]
1384+
#[tracing::instrument(level = "debug", skip(self))]
1385+
fn fn_abi_of_instance_no_deduced_attrs(
1386+
&self,
1387+
instance: ty::Instance<'tcx>,
1388+
extra_args: &'tcx ty::List<Ty<'tcx>>,
1389+
) -> Self::FnAbiOfResult {
1390+
// FIXME(eddyb) get a better `span` here.
1391+
let span = self.layout_tcx_at_span();
1392+
let tcx = self.tcx().at(span);
1393+
1394+
MaybeResult::from(
1395+
tcx.fn_abi_of_instance_no_deduced_attrs(
1396+
self.typing_env().as_query_input((instance, extra_args)),
1397+
)
1398+
.map_err(|err| {
1399+
// HACK(eddyb) at least for definitions of/calls to `Instance`s,
1400+
// we can get some kind of span even if one wasn't provided.
1401+
// However, we don't do this early in order to avoid calling
1402+
// `def_span` unconditionally (which may have a perf penalty).
1403+
let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
1404+
self.handle_fn_abi_err(
1405+
*err,
1406+
span,
1407+
FnAbiRequest::OfInstance { instance, extra_args },
1408+
)
1409+
}),
1410+
)
1411+
}
1412+
1413+
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for direct calls*
1414+
/// to an `fn`. Indirectly-passed parameters in the returned ABI will include applicable
1415+
/// codegen optimization attributes, including `ReadOnly` and `CapturesNone` -- deduction of
1416+
/// which requires inspection of function bodies that can lead to cycles when performed during
1417+
/// typeck. During typeck, you should therefore use instead the unoptimized ABI returned by
1418+
/// `fn_abi_of_instance_no_deduced_attrs`.
1419+
///
1420+
/// * that includes virtual calls, which are represented by "direct calls" to an
1421+
/// `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`).
13771422
#[inline]
13781423
#[tracing::instrument(level = "debug", skip(self))]
13791424
fn fn_abi_of_instance(

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ use rustc_macros::{
4848
TypeVisitable, extension,
4949
};
5050
use rustc_serialize::{Decodable, Encodable};
51+
use rustc_session::config::OptLevel;
5152
pub use rustc_session::lint::RegisteredTools;
5253
use rustc_span::hygiene::MacroKind;
5354
use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol};
55+
use rustc_target::callconv::FnAbi;
5456
pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet};
5557
pub use rustc_type_ir::fast_reject::DeepRejectCtxt;
5658
#[allow(
@@ -120,7 +122,7 @@ use crate::ty;
120122
use crate::ty::codec::{TyDecoder, TyEncoder};
121123
pub use crate::ty::diagnostics::*;
122124
use crate::ty::fast_reject::SimplifiedType;
123-
use crate::ty::layout::LayoutError;
125+
use crate::ty::layout::{FnAbiError, LayoutError};
124126
use crate::ty::util::Discr;
125127
use crate::ty::walk::TypeWalker;
126128

@@ -2167,6 +2169,34 @@ impl<'tcx> TyCtxt<'tcx> {
21672169

21682170
!self.associated_types_for_impl_traits_in_associated_fn(trait_item_def_id).is_empty()
21692171
}
2172+
2173+
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for direct calls*
2174+
/// to an `fn`. Indirectly-passed parameters in the returned ABI will include applicable
2175+
/// codegen optimization attributes, including `ReadOnly` and `CapturesNone` -- deduction of
2176+
/// which requires inspection of function bodies that can lead to cycles when performed during
2177+
/// typeck. During typeck, you should therefore use instead the unoptimized ABI returned by
2178+
/// `fn_abi_of_instance_no_deduced_attrs`.
2179+
///
2180+
/// For performance reasons, you should prefer to call this inherent method rather than invoke
2181+
/// the `fn_abi_of_instance_raw` query: it delegates to that query if necessary, but where
2182+
/// possible delegates instead to the `fn_abi_of_instance_no_deduced_attrs` query (thus avoiding
2183+
/// unnecessary query system overhead).
2184+
///
2185+
/// * that includes virtual calls, which are represented by "direct calls" to an
2186+
/// `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`).
2187+
#[inline]
2188+
pub fn fn_abi_of_instance(
2189+
self,
2190+
query: ty::PseudoCanonicalInput<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
2191+
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
2192+
// Only deduce attrs in full, optimized builds. Otherwise, avoid the query system overhead
2193+
// of ever invoking the `fn_abi_of_instance_raw` query.
2194+
if self.sess.opts.optimize != OptLevel::No && self.sess.opts.incremental.is_none() {
2195+
self.fn_abi_of_instance_raw(query)
2196+
} else {
2197+
self.fn_abi_of_instance_no_deduced_attrs(query)
2198+
}
2199+
}
21702200
}
21712201

21722202
pub fn provide(providers: &mut Providers) {

0 commit comments

Comments
 (0)