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

@ -11,6 +11,22 @@ pub enum InlineAttr {
Hint,
Always,
Never,
/// `#[rustc_force_inline]` forces inlining to happen in the MIR inliner - it reports an error
/// if the inlining cannot happen. It is limited to only free functions so that the calls
/// can always be resolved.
Force {
attr_span: Span,
reason: Option<Symbol>,
},
}
impl InlineAttr {
pub fn always(&self) -> bool {
match self {
InlineAttr::Always | InlineAttr::Force { .. } => true,
InlineAttr::None | InlineAttr::Hint | InlineAttr::Never => false,
}
}
}
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)]

View file

@ -20,7 +20,7 @@ fn inline_attr<'gcc, 'tcx>(
) -> Option<FnAttribute<'gcc>> {
match inline {
InlineAttr::Hint => Some(FnAttribute::Inline),
InlineAttr::Always => Some(FnAttribute::AlwaysInline),
InlineAttr::Always | InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline),
InlineAttr::Never => {
if cx.sess().target.arch != "amdgpu" {
Some(FnAttribute::NoInline)

View file

@ -37,7 +37,9 @@ fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll
}
match inline {
InlineAttr::Hint => Some(AttributeKind::InlineHint.create_attr(cx.llcx)),
InlineAttr::Always => Some(AttributeKind::AlwaysInline.create_attr(cx.llcx)),
InlineAttr::Always | InlineAttr::Force { .. } => {
Some(AttributeKind::AlwaysInline.create_attr(cx.llcx))
}
InlineAttr::Never => {
if cx.sess().target.arch != "amdgpu" {
Some(AttributeKind::NoInline.create_attr(cx.llcx))

View file

@ -18,6 +18,7 @@ use rustc_session::parse::feature_err;
use rustc_session::{Session, lint};
use rustc_span::{Ident, Span, sym};
use rustc_target::spec::{SanitizerSet, abi};
use tracing::debug;
use crate::errors;
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr};
@ -522,9 +523,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx);
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
if !attr.has_name(sym::inline) {
return ia;
}
if attr.has_name(sym::inline) {
if attr.is_word() {
InlineAttr::Hint
} else if let Some(ref items) = attr.meta_item_list() {
@ -546,6 +545,18 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
} else {
ia
}
} else if attr.has_name(sym::rustc_force_inline) && tcx.features().rustc_attrs() {
if attr.is_word() {
InlineAttr::Force { attr_span: attr.span, reason: None }
} else if let Some(val) = attr.value_str() {
InlineAttr::Force { attr_span: attr.span, reason: Some(val) }
} else {
debug!("`rustc_force_inline` not checked by attribute validation");
ia
}
} else {
ia
}
});
// naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
@ -596,7 +607,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
// is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
if tcx.features().target_feature_11()
&& tcx.is_closure_like(did.to_def_id())
&& codegen_fn_attrs.inline != InlineAttr::Always
&& !codegen_fn_attrs.inline.always()
{
let owner_id = tcx.parent(did.to_def_id());
if tcx.def_kind(owner_id).has_codegen_attrs() {
@ -606,11 +617,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
// If a function uses #[target_feature] it can't be inlined into general
// If a function uses `#[target_feature]` it can't be inlined into general
// purpose functions as they wouldn't have the right target features
// enabled. For that reason we also forbid #[inline(always)] as it can't be
// enabled. For that reason we also forbid `#[inline(always)]` as it can't be
// respected.
if !codegen_fn_attrs.target_features.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always
//
// `#[rustc_force_inline]` doesn't need to be prohibited here, that
// is implemented entirely in rustc can attempt to inline and error if it cannot.
if !codegen_fn_attrs.target_features.is_empty()
&& matches!(codegen_fn_attrs.inline, InlineAttr::Always)
{
if let Some(span) = inline_span {
tcx.dcx().span_err(
@ -621,7 +636,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always {
if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline.always() {
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
let hir_id = tcx.local_def_id_to_hir_id(did);
tcx.node_span_lint(

View file

@ -1019,6 +1019,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
"#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
),
rustc_attr!(
rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
"#![rustc_force_inline] forces a free function to be inlined"
),
// ==========================================================================
// Internal attributes, Testing:

View file

@ -38,6 +38,7 @@
use std::ops::Deref;
use rustc_abi::ExternAbi;
use rustc_attr_parsing::InlineAttr;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, struct_span_code_err};
use rustc_hir as hir;
@ -926,8 +927,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
return Err(TypeError::IntrinsicCast);
}
// Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
if matches!(fn_attrs.inline, InlineAttr::Force { .. }) {
return Err(TypeError::ForceInlineCast);
}
// Safe `#[target_feature]` functions are not assignable to safe fn pointers
// (RFC 2396).
if b_hdr.safety.is_safe()
&& !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
{
@ -1197,6 +1203,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Ok(prev_ty);
}
let is_force_inline = |ty: Ty<'tcx>| {
if let ty::FnDef(did, _) = ty.kind() {
matches!(self.tcx.codegen_fn_attrs(did).inline, InlineAttr::Force { .. })
} else {
false
}
};
if is_force_inline(prev_ty) || is_force_inline(new_ty) {
return Err(TypeError::ForceInlineCast);
}
// Special-case that coercion alone cannot handle:
// Function items or non-capturing closures of differing IDs or GenericArgs.
let (a_sig, b_sig) = {

View file

@ -132,9 +132,10 @@ impl<'tcx> MonoItem<'tcx> {
// creating one copy of this `#[inline]` function which may
// conflict with upstream crates as it could be an exported
// symbol.
match tcx.codegen_fn_attrs(instance.def_id()).inline {
InlineAttr::Always => InstantiationMode::LocalCopy,
_ => InstantiationMode::GloballyShared { may_conflict: true },
if tcx.codegen_fn_attrs(instance.def_id()).inline.always() {
InstantiationMode::LocalCopy
} else {
InstantiationMode::GloballyShared { may_conflict: true }
}
}
MonoItem::Static(..) | MonoItem::GlobalAsm(..) => {

View file

@ -109,6 +109,9 @@ impl<'tcx> TypeError<'tcx> {
TypeError::ConstMismatch(ref values) => {
format!("expected `{}`, found `{}`", values.expected, values.found).into()
}
TypeError::ForceInlineCast => {
"cannot coerce functions which must be inlined to function pointers".into()
}
TypeError::IntrinsicCast => "cannot coerce intrinsics to function pointers".into(),
TypeError::TargetFeatureCast(_) => {
"cannot coerce functions with `#[target_feature]` to safe function pointers".into()

View file

@ -19,6 +19,17 @@ mir_transform_ffi_unwind_call = call to {$foreign ->
mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
.suggestion = cast `{$ident}` to obtain a function pointer
mir_transform_force_inline =
`{$callee}` could not be inlined into `{$caller}` but is required to be inlined
.call = ...`{$callee}` called here
.attr = inlining due to this annotation
.caller = within `{$caller}`...
.callee = `{$callee}` defined here
.note = could not be inlined due to: {$reason}
mir_transform_force_inline_justification =
`{$callee}` is required to be inlined to: {$sym}
mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
.label = the value is held across this suspend point
.note = {$reason}

View file

@ -46,7 +46,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
// #[inline(never)] to force code generation.
match codegen_fn_attrs.inline {
InlineAttr::Never => return false,
InlineAttr::Hint | InlineAttr::Always => return true,
InlineAttr::Hint | InlineAttr::Always | InlineAttr::Force { .. } => return true,
_ => {}
}
@ -69,8 +69,9 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
// Don't do any inference if codegen optimizations are disabled and also MIR inlining is not
// enabled. This ensures that we do inference even if someone only passes -Zinline-mir,
// which is less confusing than having to also enable -Copt-level=1.
if matches!(tcx.sess.opts.optimize, OptLevel::No) && !pm::should_run_pass(tcx, &inline::Inline)
{
let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline)
|| inline::ForceInline::should_run_pass_for_callee(tcx, def_id.to_def_id());
if matches!(tcx.sess.opts.optimize, OptLevel::No) && !inliner_will_run {
return false;
}

View file

@ -4,8 +4,8 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::mir::AssertKind;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::{self, Lint};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_span::{Span, Symbol};
use crate::fluent_generated as fluent;
@ -142,3 +142,29 @@ pub(crate) struct MustNotSuspendReason {
#[note(mir_transform_note2)]
#[help]
pub(crate) struct UndefinedTransmute;
#[derive(Diagnostic)]
#[diag(mir_transform_force_inline)]
#[note]
pub(crate) struct ForceInlineFailure {
#[label(mir_transform_caller)]
pub caller_span: Span,
#[label(mir_transform_callee)]
pub callee_span: Span,
#[label(mir_transform_attr)]
pub attr_span: Span,
#[primary_span]
#[label(mir_transform_call)]
pub call_span: Span,
pub callee: String,
pub caller: String,
pub reason: &'static str,
#[subdiagnostic]
pub justification: Option<ForceInlineJustification>,
}
#[derive(Subdiagnostic)]
#[note(mir_transform_force_inline_justification)]
pub(crate) struct ForceInlineJustification {
pub sym: Symbol,
}

File diff suppressed because it is too large Load diff

View file

@ -141,7 +141,7 @@ declare_passes! {
mod gvn : GVN;
// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden
// by custom rustc drivers, running all the steps by themselves. See #114628.
pub mod inline : Inline;
pub mod inline : Inline, ForceInline;
mod instsimplify : InstSimplify { BeforeInline, AfterSimplifyCfg };
mod jump_threading : JumpThreading;
mod known_panics_lint : KnownPanicsLint;
@ -488,7 +488,9 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
let is_fn_like = tcx.def_kind(def).is_fn_like();
if is_fn_like {
// Do not compute the mir call graph without said call graph actually being used.
if pm::should_run_pass(tcx, &inline::Inline) {
if pm::should_run_pass(tcx, &inline::Inline)
|| inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id())
{
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
}
}
@ -664,6 +666,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// Perform instsimplify before inline to eliminate some trivial calls (like clone
// shims).
&instsimplify::InstSimplify::BeforeInline,
// Perform inlining of `#[rustc_force_inline]`-annotated callees.
&inline::ForceInline,
// Perform inlining, which may add a lot of code.
&inline::Inline,
// Code from other crates may have storage markers, so this needs to happen after

View file

@ -79,6 +79,12 @@ pub(super) trait MirPass<'tcx> {
true
}
/// Returns `true` if this pass can be overridden by `-Zenable-mir-passes`. This should be
/// true for basically every pass other than those that are necessary for correctness.
fn can_be_overridden(&self) -> bool {
true
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
fn is_mir_dump_enabled(&self) -> bool {
@ -176,6 +182,10 @@ where
{
let name = pass.name();
if !pass.can_be_overridden() {
return pass.is_enabled(tcx.sess);
}
let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
let overridden =
overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| {

View file

@ -1,6 +1,7 @@
//! Validates the MIR to ensure that invariants are upheld.
use rustc_abi::{ExternAbi, FIRST_VARIANT, Size};
use rustc_attr_parsing::InlineAttr;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::LangItem;
use rustc_index::IndexVec;
@ -79,7 +80,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
cfg_checker.fail(location, msg);
}
if let MirPhase::Runtime(_) = body.phase {
if let MirPhase::Runtime(phase) = body.phase {
if let ty::InstanceKind::Item(_) = body.source.instance {
if body.has_free_regions() {
cfg_checker.fail(
@ -88,6 +89,27 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
);
}
}
if phase >= RuntimePhase::Optimized
&& body
.basic_blocks
.iter()
.filter_map(|bb| match &bb.terminator().kind {
TerminatorKind::Call { func, .. }
| TerminatorKind::TailCall { func, .. } => Some(func),
_ => None,
})
.filter_map(|func| match func.ty(&body.local_decls, tcx).kind() {
ty::FnDef(did, ..) => Some(did),
_ => None,
})
.any(|did| matches!(tcx.codegen_fn_attrs(did).inline, InlineAttr::Force { .. }))
{
cfg_checker.fail(
Location::START,
"`#[rustc_force_inline]`-annotated function not inlined",
);
}
}
}
}

View file

@ -207,6 +207,7 @@
use std::path::PathBuf;
use rustc_attr_parsing::InlineAttr;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in};
use rustc_data_structures::unord::{UnordMap, UnordSet};
@ -959,6 +960,14 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
return false;
}
if tcx.def_kind(def_id).has_codegen_attrs()
&& matches!(tcx.codegen_fn_attrs(def_id).inline, InlineAttr::Force { .. })
{
// `#[rustc_force_inline]` items should never be codegened. This should be caught by
// the MIR validator.
return false;
}
if def_id.is_local() {
// Local items cannot be referred to locally without monomorphizing them locally.
return true;

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 {

View file

@ -1731,6 +1731,7 @@ symbols! {
rustc_error,
rustc_evaluate_where_clauses,
rustc_expected_cgu_reuse,
rustc_force_inline,
rustc_has_incoherent_inherent_impls,
rustc_hidden_type_of_opaques,
rustc_if_this_changed,

View file

@ -251,7 +251,9 @@ trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a
trait_selection_nothing = {""}
trait_selection_oc_cant_coerce = cannot coerce intrinsics to function pointers
trait_selection_oc_cant_coerce_force_inline =
cannot coerce functions which must be inlined to function pointers
trait_selection_oc_cant_coerce_intrinsic = cannot coerce intrinsics to function pointers
trait_selection_oc_closure_selfref = closure/coroutine type that references itself
trait_selection_oc_const_compat = const not compatible with trait
trait_selection_oc_fn_lang_correct_type = {$lang_item_name ->

View file

@ -2294,7 +2294,7 @@ impl<'tcx> ObligationCause<'tcx> {
{
FailureCode::Error0644
}
TypeError::IntrinsicCast => FailureCode::Error0308,
TypeError::IntrinsicCast | TypeError::ForceInlineCast => FailureCode::Error0308,
_ => FailureCode::Error0308,
},
}
@ -2360,8 +2360,11 @@ impl<'tcx> ObligationCause<'tcx> {
{
ObligationCauseFailureCode::ClosureSelfref { span }
}
TypeError::ForceInlineCast => {
ObligationCauseFailureCode::CantCoerceForceInline { span, subdiags }
}
TypeError::IntrinsicCast => {
ObligationCauseFailureCode::CantCoerce { span, subdiags }
ObligationCauseFailureCode::CantCoerceIntrinsic { span, subdiags }
}
_ => ObligationCauseFailureCode::Generic { span, subdiags },
},

View file

@ -1729,8 +1729,15 @@ pub enum ObligationCauseFailureCode {
#[primary_span]
span: Span,
},
#[diag(trait_selection_oc_cant_coerce, code = E0308)]
CantCoerce {
#[diag(trait_selection_oc_cant_coerce_force_inline, code = E0308)]
CantCoerceForceInline {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<TypeErrorAdditionalDiags>,
},
#[diag(trait_selection_oc_cant_coerce_intrinsic, code = E0308)]
CantCoerceIntrinsic {
#[primary_span]
span: Span,
#[subdiagnostic]

View file

@ -51,6 +51,9 @@ pub enum TypeError<I: Interner> {
ConstMismatch(ExpectedFound<I::Const>),
IntrinsicCast,
/// `#[rustc_force_inline]` functions must be inlined and must not be codegened independently,
/// so casting to a function pointer must be prohibited.
ForceInlineCast,
/// Safe `#[target_feature]` functions are not assignable to safe function pointers.
TargetFeatureCast(I::DefId),
}
@ -83,6 +86,7 @@ impl<I: Interner> TypeError<I> {
| ProjectionMismatched(_)
| ExistentialMismatch(_)
| ConstMismatch(_)
| ForceInlineCast
| IntrinsicCast => true,
}
}

View file

@ -0,0 +1,21 @@
- // MIR for `caller` before ForceInline
+ // MIR for `caller` after ForceInline
fn caller() -> () {
let mut _0: ();
let _1: ();
+ scope 1 (inlined callee_forced) {
+ }
bb0: {
StorageLive(_1);
- _1 = callee_forced() -> [return: bb1, unwind unreachable];
- }
-
- bb1: {
StorageDead(_1);
_0 = const ();
return;
}
}

View file

@ -0,0 +1,21 @@
- // MIR for `caller` before ForceInline
+ // MIR for `caller` after ForceInline
fn caller() -> () {
let mut _0: ();
let _1: ();
+ scope 1 (inlined callee_forced) {
+ }
bb0: {
StorageLive(_1);
- _1 = callee_forced() -> [return: bb1, unwind continue];
- }
-
- bb1: {
StorageDead(_1);
_0 = const ();
return;
}
}

View file

@ -0,0 +1,13 @@
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//@ compile-flags: -Copt-level=0 --crate-type=lib
#![feature(rustc_attrs)]
#[rustc_force_inline]
pub fn callee_forced() {}
// EMIT_MIR forced.caller.ForceInline.diff
pub fn caller() {
callee_forced();
// CHECK-LABEL: fn caller(
// CHECK: (inlined callee_forced)
}

View file

@ -0,0 +1,12 @@
- // MIR for `caller` before ForceInline
+ // MIR for `caller` after ForceInline
fn caller() -> {async fn body of caller()} {
let mut _0: {async fn body of caller()};
bb0: {
_0 = {coroutine@$DIR/forced_async.rs:10:19: 14:2 (#0)};
return;
}
}

View file

@ -0,0 +1,12 @@
- // MIR for `caller` before ForceInline
+ // MIR for `caller` after ForceInline
fn caller() -> {async fn body of caller()} {
let mut _0: {async fn body of caller()};
bb0: {
_0 = {coroutine@$DIR/forced_async.rs:10:19: 14:2 (#0)};
return;
}
}

View file

@ -0,0 +1,14 @@
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//@ compile-flags: -Copt-level=0 --crate-type=lib
//@ edition: 2021
#![feature(rustc_attrs)]
#[rustc_force_inline]
pub fn callee_forced() {}
// EMIT_MIR forced_async.caller.ForceInline.diff
async fn caller() {
callee_forced();
// CHECK-LABEL: fn caller(
// CHECK: (inlined callee_forced)
}

View file

@ -0,0 +1,21 @@
- // MIR for `caller::{closure#0}` before ForceInline
+ // MIR for `caller::{closure#0}` after ForceInline
fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure.rs:10:6: 10:8}) -> () {
let mut _0: ();
let _2: ();
+ scope 1 (inlined callee_forced) {
+ }
bb0: {
StorageLive(_2);
- _2 = callee_forced() -> [return: bb1, unwind unreachable];
- }
-
- bb1: {
StorageDead(_2);
_0 = const ();
return;
}
}

View file

@ -0,0 +1,21 @@
- // MIR for `caller::{closure#0}` before ForceInline
+ // MIR for `caller::{closure#0}` after ForceInline
fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure.rs:10:6: 10:8}) -> () {
let mut _0: ();
let _2: ();
+ scope 1 (inlined callee_forced) {
+ }
bb0: {
StorageLive(_2);
- _2 = callee_forced() -> [return: bb1, unwind continue];
- }
-
- bb1: {
StorageDead(_2);
_0 = const ();
return;
}
}

View file

@ -0,0 +1,15 @@
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//@ compile-flags: -Copt-level=0 --crate-type=lib
#![feature(rustc_attrs)]
#[rustc_force_inline]
pub fn callee_forced() {}
// EMIT_MIR forced_closure.caller-{closure#0}.ForceInline.diff
pub fn caller() {
(|| {
callee_forced();
// CHECK-LABEL: fn caller::{closure#0}(
// CHECK: (inlined callee_forced)
})();
}

View file

@ -0,0 +1,10 @@
//@ compile-flags: --crate-type=lib
#![feature(rustc_attrs)]
#[rustc_force_inline = "the test requires it"]
pub fn forced_with_reason() {
}
#[rustc_force_inline]
pub fn forced() {
}

View file

@ -0,0 +1,25 @@
//@ check-fail
//@ compile-flags: --crate-type=lib
#![allow(internal_features)]
#![feature(rustc_attrs)]
#[rustc_force_inline]
pub fn callee(x: isize) -> usize { unimplemented!() }
fn a() {
let _: fn(isize) -> usize = callee;
//~^ ERROR cannot coerce functions which must be inlined to function pointers
}
fn b() {
let _ = callee as fn(isize) -> usize;
//~^ ERROR non-primitive cast
}
fn c() {
let _: [fn(isize) -> usize; 2] = [
callee,
//~^ ERROR cannot coerce functions which must be inlined to function pointers
callee,
];
}

View file

@ -0,0 +1,40 @@
error[E0308]: cannot coerce functions which must be inlined to function pointers
--> $DIR/cast.rs:10:33
|
LL | let _: fn(isize) -> usize = callee;
| ------------------ ^^^^^^ cannot coerce functions which must be inlined to function pointers
| |
| expected due to this
|
= note: expected fn pointer `fn(_) -> _`
found fn item `fn(_) -> _ {callee}`
= note: fn items are distinct from fn pointers
help: consider casting to a fn pointer
|
LL | let _: fn(isize) -> usize = callee as fn(isize) -> usize;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0605]: non-primitive cast: `fn(isize) -> usize {callee}` as `fn(isize) -> usize`
--> $DIR/cast.rs:15:13
|
LL | let _ = callee as fn(isize) -> usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
error[E0308]: cannot coerce functions which must be inlined to function pointers
--> $DIR/cast.rs:21:9
|
LL | callee,
| ^^^^^^ cannot coerce functions which must be inlined to function pointers
|
= note: expected fn pointer `fn(_) -> _`
found fn item `fn(_) -> _ {callee}`
= note: fn items are distinct from fn pointers
help: consider casting to a fn pointer
|
LL | callee as fn(isize) -> usize,
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0605.
For more information about an error, try `rustc --explain E0308`.

View file

@ -0,0 +1,13 @@
//@ aux-build:callees.rs
//@ build-pass
//@ compile-flags: --crate-type=lib
extern crate callees;
// Test that forced inlining across crates works as expected.
pub fn caller() {
callees::forced();
callees::forced_with_reason();
}

View file

@ -0,0 +1,25 @@
//@ check-fail
//@ compile-flags: --crate-type=lib
//@ edition: 2021
#![allow(internal_features)]
#![feature(rustc_attrs)]
// Test that forced inlining into async functions w/ errors works as expected.
#[rustc_no_mir_inline]
#[rustc_force_inline]
pub fn callee() {
}
#[rustc_no_mir_inline]
#[rustc_force_inline = "the test requires it"]
pub fn callee_justified() {
}
async fn async_caller() {
callee();
//~^ ERROR `callee` could not be inlined into `async_caller::{closure#0}` but is required to be inlined
callee_justified();
//~^ ERROR `callee_justified` could not be inlined into `async_caller::{closure#0}` but is required to be inlined
}

View file

@ -0,0 +1,19 @@
error: `callee` could not be inlined into `async_caller::{closure#0}` but is required to be inlined
--> $DIR/deny-async.rs:20:5
|
LL | callee();
| ^^^^^^^^ ...`callee` called here
|
= note: could not be inlined due to: #[rustc_no_mir_inline]
error: `callee_justified` could not be inlined into `async_caller::{closure#0}` but is required to be inlined
--> $DIR/deny-async.rs:23:5
|
LL | callee_justified();
| ^^^^^^^^^^^^^^^^^^ ...`callee_justified` called here
|
= note: could not be inlined due to: #[rustc_no_mir_inline]
= note: `callee_justified` is required to be inlined to: the test requires it
error: aborting due to 2 previous errors

View file

@ -0,0 +1,26 @@
//@ build-fail
//@ compile-flags: --crate-type=lib
#![allow(internal_features)]
#![feature(rustc_attrs)]
// Test that forced inlining into closures w/ errors works as expected.
#[rustc_no_mir_inline]
#[rustc_force_inline]
pub fn callee() {
}
#[rustc_no_mir_inline]
#[rustc_force_inline = "the test requires it"]
pub fn callee_justified() {
}
pub fn caller() {
(|| {
callee();
//~^ ERROR `callee` could not be inlined into `caller::{closure#0}` but is required to be inlined
callee_justified();
//~^ ERROR `callee_justified` could not be inlined into `caller::{closure#0}` but is required to be inlined
})();
}

View file

@ -0,0 +1,28 @@
error: `callee` could not be inlined into `caller::{closure#0}` but is required to be inlined
--> $DIR/deny-closure.rs:20:9
|
LL | callee();
| ^^^^^^^^ ...`callee` called here
|
= note: could not be inlined due to: #[rustc_no_mir_inline]
error: `callee_justified` could not be inlined into `caller::{closure#0}` but is required to be inlined
--> $DIR/deny-closure.rs:23:9
|
LL | callee_justified();
| ^^^^^^^^^^^^^^^^^^ ...`callee_justified` called here
|
= note: could not be inlined due to: #[rustc_no_mir_inline]
= note: `callee_justified` is required to be inlined to: the test requires it
note: the above error was encountered while instantiating `fn caller::{closure#0}`
--> $DIR/deny-closure.rs:19:5
|
LL | / (|| {
LL | | callee();
... |
LL | | })();
| |________^
error: aborting due to 2 previous errors

View file

@ -0,0 +1,24 @@
//@ build-fail
//@ compile-flags: --crate-type=lib
#![allow(internal_features)]
#![feature(rustc_attrs)]
// Test that forced inlining w/ errors works as expected.
#[rustc_no_mir_inline]
#[rustc_force_inline]
pub fn callee() {
}
#[rustc_no_mir_inline]
#[rustc_force_inline = "the test requires it"]
pub fn callee_justified() {
}
pub fn caller() {
callee();
//~^ ERROR `callee` could not be inlined into `caller` but is required to be inlined
callee_justified();
//~^ ERROR `callee_justified` could not be inlined into `caller` but is required to be inlined
}

View file

@ -0,0 +1,19 @@
error: `callee` could not be inlined into `caller` but is required to be inlined
--> $DIR/deny.rs:19:5
|
LL | callee();
| ^^^^^^^^ ...`callee` called here
|
= note: could not be inlined due to: #[rustc_no_mir_inline]
error: `callee_justified` could not be inlined into `caller` but is required to be inlined
--> $DIR/deny.rs:22:5
|
LL | callee_justified();
| ^^^^^^^^^^^^^^^^^^ ...`callee_justified` called here
|
= note: could not be inlined due to: #[rustc_no_mir_inline]
= note: `callee_justified` is required to be inlined to: the test requires it
error: aborting due to 2 previous errors

View file

@ -0,0 +1,12 @@
//@ compile-flags: --crate-type=lib
#![allow(internal_features)]
#[rustc_force_inline]
//~^ ERROR #![rustc_force_inline] forces a free function to be inlined
pub fn bare() {
}
#[rustc_force_inline = "the test requires it"]
//~^ ERROR #![rustc_force_inline] forces a free function to be inlined
pub fn justified() {
}

View file

@ -0,0 +1,21 @@
error[E0658]: #![rustc_force_inline] forces a free function to be inlined
--> $DIR/gate.rs:4:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: #![rustc_force_inline] forces a free function to be inlined
--> $DIR/gate.rs:9:1
|
LL | #[rustc_force_inline = "the test requires it"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,164 @@
//@ edition: 2024
#![allow(internal_features, unused_imports, unused_macros)]
#![feature(extern_types)]
#![feature(gen_blocks)]
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
#![feature(trait_alias)]
// Test that invalid force inlining attributes error as expected.
#[rustc_force_inline("foo")]
//~^ ERROR malformed `rustc_force_inline` attribute input
pub fn forced1() {
}
#[rustc_force_inline(bar, baz)]
//~^ ERROR malformed `rustc_force_inline` attribute input
pub fn forced2() {
}
#[rustc_force_inline(2)]
//~^ ERROR malformed `rustc_force_inline` attribute input
pub fn forced3() {
}
#[rustc_force_inline = 2]
//~^ ERROR malformed `rustc_force_inline` attribute input
pub fn forced4() {
}
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
extern crate std as other_std;
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
use std::collections::HashMap;
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
static _FOO: &'static str = "FOO";
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
const _BAR: u32 = 3;
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
mod foo { }
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
unsafe extern "C" {
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
static X: &'static u32;
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
type Y;
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
fn foo();
}
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
type Foo = u32;
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
enum Bar<#[rustc_force_inline] T> {
//~^ ERROR attribute should be applied to a function
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
Baz(std::marker::PhantomData<T>),
}
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
struct Qux {
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
field: u32,
}
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
union FooBar {
x: u32,
y: u32,
}
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
trait FooBaz {
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
type Foo;
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
const Bar: i32;
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
fn foo() {}
}
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
trait FooQux = FooBaz;
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
impl<T> Bar<T> {
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
fn foo() {}
}
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
impl<T> FooBaz for Bar<T> {
type Foo = u32;
const Bar: i32 = 3;
}
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
macro_rules! barqux { ($foo:tt) => { $foo }; }
fn barqux(#[rustc_force_inline] _x: u32) {}
//~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
//~^^ ERROR attribute should be applied to a function
#[rustc_force_inline]
//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function
async fn async_foo() {}
#[rustc_force_inline]
//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function
gen fn gen_foo() {}
#[rustc_force_inline]
//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function
async gen fn async_gen_foo() {}
fn main() {
let _x = #[rustc_force_inline] || { };
//~^ ERROR attribute should be applied to a function
let _y = #[rustc_force_inline] 3 + 4;
//~^ ERROR attribute should be applied to a function
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
let _z = 3;
match _z {
#[rustc_force_inline]
//~^ ERROR attribute should be applied to a function
1 => (),
_ => (),
}
}

View file

@ -0,0 +1,377 @@
error: malformed `rustc_force_inline` attribute input
--> $DIR/invalid.rs:11:1
|
LL | #[rustc_force_inline("foo")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: the following are the possible correct uses
|
LL | #[rustc_force_inline = "reason"]
|
LL | #[rustc_force_inline]
|
error: malformed `rustc_force_inline` attribute input
--> $DIR/invalid.rs:16:1
|
LL | #[rustc_force_inline(bar, baz)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: the following are the possible correct uses
|
LL | #[rustc_force_inline = "reason"]
|
LL | #[rustc_force_inline]
|
error: malformed `rustc_force_inline` attribute input
--> $DIR/invalid.rs:21:1
|
LL | #[rustc_force_inline(2)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
help: the following are the possible correct uses
|
LL | #[rustc_force_inline = "reason"]
|
LL | #[rustc_force_inline]
|
error: malformed `rustc_force_inline` attribute input
--> $DIR/invalid.rs:26:1
|
LL | #[rustc_force_inline = 2]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: the following are the possible correct uses
|
LL | #[rustc_force_inline = "reason"]
|
LL | #[rustc_force_inline]
|
error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/invalid.rs:133:11
|
LL | fn barqux(#[rustc_force_inline] _x: u32) {}
| ^^^^^^^^^^^^^^^^^^^^^
error: attribute should be applied to a function
--> $DIR/invalid.rs:31:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | extern crate std as other_std;
| ------------------------------ not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:35:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | use std::collections::HashMap;
| ------------------------------ not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:39:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | static _FOO: &'static str = "FOO";
| ---------------------------------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:43:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | const _BAR: u32 = 3;
| -------------------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:47:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | mod foo { }
| ----------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:51:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | / unsafe extern "C" {
LL | | #[rustc_force_inline]
LL | |
LL | | static X: &'static u32;
... |
LL | | fn foo();
LL | | }
| |_- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:67:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | type Foo = u32;
| --------------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:71:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | / enum Bar<#[rustc_force_inline] T> {
LL | |
LL | | #[rustc_force_inline]
... |
LL | | }
| |_- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:73:10
|
LL | enum Bar<#[rustc_force_inline] T> {
| ^^^^^^^^^^^^^^^^^^^^^ - not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:75:5
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | Baz(std::marker::PhantomData<T>),
| -------------------------------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:80:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | / struct Qux {
LL | | #[rustc_force_inline]
LL | |
LL | | field: u32,
LL | | }
| |_- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:83:5
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | field: u32,
| ---------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:88:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | / union FooBar {
LL | | x: u32,
LL | | y: u32,
LL | | }
| |_- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:95:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | / trait FooBaz {
LL | | #[rustc_force_inline]
LL | |
LL | | type Foo;
... |
LL | | fn foo() {}
LL | | }
| |_- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:110:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | trait FooQux = FooBaz;
| ---------------------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:114:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | / impl<T> Bar<T> {
LL | | #[rustc_force_inline]
LL | |
LL | | fn foo() {}
LL | | }
| |_- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:122:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | / impl<T> FooBaz for Bar<T> {
LL | | type Foo = u32;
LL | | const Bar: i32 = 3;
LL | | }
| |_- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:129:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | macro_rules! barqux { ($foo:tt) => { $foo }; }
| ---------------------------------------------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:133:11
|
LL | fn barqux(#[rustc_force_inline] _x: u32) {}
| ^^^^^^^^^^^^^^^^^^^^^--------
| |
| not a function definition
error: attribute cannot be applied to a `async`, `gen` or `async gen` function
--> $DIR/invalid.rs:137:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | async fn async_foo() {}
| -------------------- `async`, `gen` or `async gen` function
error: attribute cannot be applied to a `async`, `gen` or `async gen` function
--> $DIR/invalid.rs:141:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | gen fn gen_foo() {}
| ---------------- `async`, `gen` or `async gen` function
error: attribute cannot be applied to a `async`, `gen` or `async gen` function
--> $DIR/invalid.rs:145:1
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | async gen fn async_gen_foo() {}
| ---------------------------- `async`, `gen` or `async gen` function
error: attribute should be applied to a function
--> $DIR/invalid.rs:150:14
|
LL | let _x = #[rustc_force_inline] || { };
| ^^^^^^^^^^^^^^^^^^^^^ ------ not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:152:14
|
LL | let _y = #[rustc_force_inline] 3 + 4;
| ^^^^^^^^^^^^^^^^^^^^^ - not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:154:5
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | let _z = 3;
| ----------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:159:9
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | 1 => (),
| ------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:98:5
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | type Foo;
| --------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:101:5
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | const Bar: i32;
| --------------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:105:5
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | fn foo() {}
| ----------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:117:5
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | fn foo() {}
| ----------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:54:5
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | static X: &'static u32;
| ----------------------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:58:5
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | type Y;
| ------- not a function definition
error: attribute should be applied to a function
--> $DIR/invalid.rs:62:5
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | fn foo();
| --------- not a function definition
error: aborting due to 38 previous errors