Skip to content

Commit

Permalink
rustc: Forbid #[inline(always)] with #[target_feature]
Browse files Browse the repository at this point in the history
Once a target feature is enabled for a function that means that it in general
can't be inlined into other functions which don't have that target feature
enabled. This can cause both safety and LLVM issues if we were to actually
inline it, so `#[inline(always)]` both can't be respected and would be an error
if we did so!

Today LLVM doesn't inline functions with different `#[target_feature]`
annotations, but it turns out that if one is tagged with `#[inline(always)]`
it'll override this and cause scary LLVM error to arise!

This commit fixes this issue by forbidding these two attributes to be used in
conjunction with one another.

cc rust-lang/stdarch#404
  • Loading branch information
alexcrichton committed Mar 27, 2018
1 parent 9c9424d commit 38d48ef
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 1 deletion.
15 changes: 15 additions & 0 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1769,6 +1769,7 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt

let whitelist = tcx.target_features_whitelist(LOCAL_CRATE);

let mut inline_span = None;
for attr in attrs.iter() {
if attr.check_name("cold") {
trans_fn_attrs.flags |= TransFnAttrFlags::COLD;
Expand Down Expand Up @@ -1800,6 +1801,7 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt
}
MetaItemKind::List(ref items) => {
mark_used(attr);
inline_span = Some(attr.span);
if items.len() != 1 {
span_err!(tcx.sess.diagnostic(), attr.span, E0534,
"expected one argument");
Expand Down Expand Up @@ -1855,5 +1857,18 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt
}
}

// 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
// respected.
if trans_fn_attrs.target_features.len() > 0 {
if trans_fn_attrs.inline == InlineAttr::Always {
if let Some(span) = inline_span {
tcx.sess.span_err(span, "cannot use #[inline(always)] with \
#[target_feature]");
}
}
}

trans_fn_attrs
}
5 changes: 5 additions & 0 deletions src/test/ui/target-feature-wrong.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ fn bar() {}
//~^ ERROR: should be applied to a function
mod another {}

#[inline(always)]
//~^ ERROR: cannot use #[inline(always)]
#[target_feature(enable = "sse2")]
unsafe fn test() {}

fn main() {
unsafe {
foo();
Expand Down
8 changes: 7 additions & 1 deletion src/test/ui/target-feature-wrong.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,11 @@ LL | //~^ ERROR: should be applied to a function
LL | mod another {}
| -------------- not a function

error: aborting due to 5 previous errors
error: cannot use #[inline(always)] with #[target_feature]
--> $DIR/target-feature-wrong.rs:36:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^

error: aborting due to 6 previous errors

0 comments on commit 38d48ef

Please sign in to comment.