1
Fork 0

mir_transform: implement forced inlining

Adds `#[rustc_force_inline]` which is similar to always inlining but
reports an error if the inlining was not possible, and which always
attempts to inline annotated items, regardless of optimisation levels.
It can only be applied to free functions to guarantee that the MIR
inliner will be able to resolve calls.
This commit is contained in:
David Wood 2024-09-23 18:46:23 +01:00
parent 336209eef1
commit f86169a58f
No known key found for this signature in database
47 changed files with 2130 additions and 709 deletions

View file

@ -656,6 +656,14 @@ passes_rustc_allow_const_fn_unstable =
passes_rustc_dirty_clean =
attribute requires -Z query-dep-graph to be enabled
passes_rustc_force_inline =
attribute should be applied to a function
.label = not a function definition
passes_rustc_force_inline_coro =
attribute cannot be applied to a `async`, `gen` or `async gen` function
.label = `async`, `gen` or `async gen` function
passes_rustc_layout_scalar_valid_range_arg =
expected exactly one integer literal argument

View file

@ -247,7 +247,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.check_coroutine(attr, target);
}
[sym::linkage, ..] => self.check_linkage(attr, span, target),
[sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent( attr.span, span, attrs),
[sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span, span, attrs),
[
// ok
sym::allow
@ -332,6 +332,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.check_repr(attrs, span, target, item, hir_id);
self.check_used(attrs, target, span);
self.check_rustc_force_inline(hir_id, attrs, span, target);
}
fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
@ -2480,6 +2481,45 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
fn check_rustc_force_inline(
&self,
hir_id: HirId,
attrs: &[Attribute],
span: Span,
target: Target,
) {
let force_inline_attr = attrs.iter().find(|attr| attr.has_name(sym::rustc_force_inline));
match (target, force_inline_attr) {
(Target::Closure, None) => {
let is_coro = matches!(
self.tcx.hir().expect_expr(hir_id).kind,
hir::ExprKind::Closure(hir::Closure {
kind: hir::ClosureKind::Coroutine(..)
| hir::ClosureKind::CoroutineClosure(..),
..
})
);
let parent_did = self.tcx.hir().get_parent_item(hir_id).to_def_id();
let parent_span = self.tcx.def_span(parent_did);
let parent_force_inline_attr =
self.tcx.get_attr(parent_did, sym::rustc_force_inline);
if let Some(attr) = parent_force_inline_attr
&& is_coro
{
self.dcx().emit_err(errors::RustcForceInlineCoro {
attr_span: attr.span,
span: parent_span,
});
}
}
(Target::Fn, _) => (),
(_, Some(attr)) => {
self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span, span });
}
(_, None) => (),
}
}
/// Checks if `#[autodiff]` is applied to an item other than a function item.
fn check_autodiff(&self, _hir_id: HirId, _attr: &Attribute, span: Span, target: Target) {
debug!("check_autodiff");

View file

@ -688,6 +688,24 @@ pub(crate) struct RustcPubTransparent {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_rustc_force_inline)]
pub(crate) struct RustcForceInline {
#[primary_span]
pub attr_span: Span,
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_rustc_force_inline_coro)]
pub(crate) struct RustcForceInlineCoro {
#[primary_span]
pub attr_span: Span,
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_link_ordinal)]
pub(crate) struct LinkOrdinal {