parent
e8cd6cc237
commit
4f840a683a
13 changed files with 149 additions and 137 deletions
|
|
@ -36,6 +36,7 @@ use syntax::codemap::{self, Spanned};
|
|||
use syntax::abi::Abi;
|
||||
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
|
||||
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
|
||||
use syntax::attr::InlineAttr;
|
||||
use syntax::ext::hygiene::SyntaxContext;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{Symbol, keywords};
|
||||
|
|
@ -2214,6 +2215,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
#[derive(Clone, RustcEncodable, RustcDecodable, Hash)]
|
||||
pub struct TransFnAttrs {
|
||||
pub flags: TransFnAttrFlags,
|
||||
pub inline: InlineAttr,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
|
@ -2231,6 +2233,15 @@ impl TransFnAttrs {
|
|||
pub fn new() -> TransFnAttrs {
|
||||
TransFnAttrs {
|
||||
flags: TransFnAttrFlags::empty(),
|
||||
inline: InlineAttr::None,
|
||||
}
|
||||
}
|
||||
|
||||
/// True if `#[inline]` or `#[inline(always)]` is present.
|
||||
pub fn requests_inline(&self) -> bool {
|
||||
match self.inline {
|
||||
InlineAttr::Hint | InlineAttr::Always => true,
|
||||
InlineAttr::None | InlineAttr::Never => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
|
|||
StableHasher, StableHasherResult};
|
||||
use std::mem;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for DefId {
|
||||
#[inline]
|
||||
|
|
@ -1145,9 +1146,11 @@ impl<'hir> HashStable<StableHashingContext<'hir>> for hir::TransFnAttrs
|
|||
hasher: &mut StableHasher<W>) {
|
||||
let hir::TransFnAttrs {
|
||||
flags,
|
||||
inline,
|
||||
} = *self;
|
||||
|
||||
flags.hash_stable(hcx, hasher);
|
||||
inline.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1160,6 +1163,14 @@ impl<'hir> HashStable<StableHashingContext<'hir>> for hir::TransFnAttrFlags
|
|||
}
|
||||
}
|
||||
|
||||
impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InlineAttr {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'hir>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct hir::Freevar {
|
||||
def,
|
||||
span
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
// makes all other generics or inline functions that it references
|
||||
// reachable as well.
|
||||
|
||||
use hir::TransFnAttrs;
|
||||
use hir::map as hir_map;
|
||||
use hir::def::Def;
|
||||
use hir::def_id::{DefId, CrateNum};
|
||||
|
|
@ -43,8 +44,8 @@ fn generics_require_inlining(generics: &hir::Generics) -> bool {
|
|||
// Returns true if the given item must be inlined because it may be
|
||||
// monomorphized or it was marked with `#[inline]`. This will only return
|
||||
// true for functions.
|
||||
fn item_might_be_inlined(item: &hir::Item) -> bool {
|
||||
if attr::requests_inline(&item.attrs) {
|
||||
fn item_might_be_inlined(item: &hir::Item, attrs: TransFnAttrs) -> bool {
|
||||
if attrs.requests_inline() {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -60,14 +61,15 @@ fn item_might_be_inlined(item: &hir::Item) -> bool {
|
|||
fn method_might_be_inlined<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
impl_item: &hir::ImplItem,
|
||||
impl_src: DefId) -> bool {
|
||||
if attr::requests_inline(&impl_item.attrs) ||
|
||||
let trans_fn_attrs = tcx.trans_fn_attrs(impl_item.hir_id.owner_def_id());
|
||||
if trans_fn_attrs.requests_inline() ||
|
||||
generics_require_inlining(&impl_item.generics) {
|
||||
return true
|
||||
}
|
||||
if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_src) {
|
||||
match tcx.hir.find(impl_node_id) {
|
||||
Some(hir_map::NodeItem(item)) =>
|
||||
item_might_be_inlined(&item),
|
||||
item_might_be_inlined(&item, trans_fn_attrs),
|
||||
Some(..) | None =>
|
||||
span_bug!(impl_item.span, "impl did is not an item")
|
||||
}
|
||||
|
|
@ -160,7 +162,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
|||
match self.tcx.hir.find(node_id) {
|
||||
Some(hir_map::NodeItem(item)) => {
|
||||
match item.node {
|
||||
hir::ItemFn(..) => item_might_be_inlined(&item),
|
||||
hir::ItemFn(..) =>
|
||||
item_might_be_inlined(&item, self.tcx.trans_fn_attrs(def_id)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -176,8 +179,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
|||
match impl_item.node {
|
||||
hir::ImplItemKind::Const(..) => true,
|
||||
hir::ImplItemKind::Method(..) => {
|
||||
let attrs = self.tcx.trans_fn_attrs(def_id);
|
||||
if generics_require_inlining(&impl_item.generics) ||
|
||||
attr::requests_inline(&impl_item.attrs) {
|
||||
attrs.requests_inline() {
|
||||
true
|
||||
} else {
|
||||
let impl_did = self.tcx
|
||||
|
|
@ -246,7 +250,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
|||
hir_map::NodeItem(item) => {
|
||||
match item.node {
|
||||
hir::ItemFn(.., body) => {
|
||||
if item_might_be_inlined(&item) {
|
||||
let def_id = self.tcx.hir.local_def_id(item.id);
|
||||
if item_might_be_inlined(&item, self.tcx.trans_fn_attrs(def_id)) {
|
||||
self.visit_nested_body(body);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ impl<'tcx> InstanceDef<'tcx> {
|
|||
&self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>
|
||||
) -> bool {
|
||||
use syntax::attr::requests_inline;
|
||||
if self.is_inline(tcx) {
|
||||
return true
|
||||
}
|
||||
|
|
@ -106,8 +105,8 @@ impl<'tcx> InstanceDef<'tcx> {
|
|||
// available to normal end-users.
|
||||
return true
|
||||
}
|
||||
requests_inline(&self.attrs(tcx)[..]) ||
|
||||
tcx.is_const_fn(self.def_id())
|
||||
let trans_fn_attrs = tcx.trans_fn_attrs(self.def_id());
|
||||
trans_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -832,7 +832,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
|||
} else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let types = generics.parent_types as usize + generics.types.len();
|
||||
let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs);
|
||||
let needs_inline = types > 0 || tcx.trans_fn_attrs(def_id).requests_inline();
|
||||
let is_const_fn = sig.constness == hir::Constness::Const;
|
||||
let ast = if is_const_fn { Some(body) } else { None };
|
||||
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
|
||||
|
|
@ -1123,7 +1123,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
|||
hir::ItemConst(..) => self.encode_optimized_mir(def_id),
|
||||
hir::ItemFn(_, _, constness, _, ref generics, _) => {
|
||||
let has_tps = generics.ty_params().next().is_some();
|
||||
let needs_inline = has_tps || attr::requests_inline(&item.attrs);
|
||||
let needs_inline = has_tps || tcx.trans_fn_attrs(def_id).requests_inline();
|
||||
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
|
||||
if needs_inline || constness == hir::Constness::Const || always_encode_mir {
|
||||
self.encode_optimized_mir(def_id)
|
||||
|
|
|
|||
|
|
@ -141,8 +141,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
|
|||
// creating one copy of this `#[inline]` function which may
|
||||
// conflict with upstream crates as it could be an exported
|
||||
// symbol.
|
||||
let attrs = instance.def.attrs(tcx);
|
||||
match attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs) {
|
||||
match tcx.trans_fn_attrs(instance.def_id()).inline {
|
||||
InlineAttr::Always => InstantiationMode::LocalCopy,
|
||||
_ => {
|
||||
InstantiationMode::GloballyShared { may_conflict: true }
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let attrs = tcx.get_attrs(callsite.callee);
|
||||
let hint = attr::find_inline_attr(None, &attrs[..]);
|
||||
let hint = tcx.trans_fn_attrs(callsite.callee).inline;
|
||||
|
||||
let hinted = match hint {
|
||||
// Just treat inline(always) as a hint for now,
|
||||
|
|
|
|||
|
|
@ -103,15 +103,13 @@ pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) {
|
|||
/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
|
||||
/// attributes.
|
||||
pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) {
|
||||
use syntax::attr::*;
|
||||
let attrs = cx.tcx.get_attrs(id);
|
||||
inline(llfn, find_inline_attr(Some(cx.sess().diagnostic()), &attrs));
|
||||
let trans_fn_attrs = cx.tcx.trans_fn_attrs(id);
|
||||
|
||||
inline(llfn, trans_fn_attrs.inline);
|
||||
|
||||
set_frame_pointer_elimination(cx, llfn);
|
||||
set_probestack(cx, llfn);
|
||||
|
||||
let trans_fn_attrs = cx.tcx.trans_fn_attrs(id);
|
||||
|
||||
if trans_fn_attrs.flags.contains(TransFnAttrFlags::COLD) {
|
||||
Attribute::Cold.apply_llfn(Function, llfn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,9 +236,7 @@ impl TransCrate for MetadataOnlyTransCrate {
|
|||
let _ = tcx.export_name(def_id);
|
||||
let _ = tcx.contains_extern_indicator(def_id);
|
||||
let _ = inst.def.is_inline(tcx);
|
||||
let attrs = inst.def.attrs(tcx);
|
||||
let _ =
|
||||
::syntax::attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs);
|
||||
let _ = tcx.trans_fn_attrs(def_id);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ use util::nodemap::FxHashMap;
|
|||
use rustc_const_math::ConstInt;
|
||||
|
||||
use syntax::{abi, ast};
|
||||
use syntax::ast::MetaItemKind;
|
||||
use syntax::attr::{InlineAttr, list_contains_name, mark_used};
|
||||
use syntax::codemap::Spanned;
|
||||
use syntax::symbol::{Symbol, keywords};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
|
@ -1742,6 +1744,39 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt
|
|||
} else if attr.check_name("naked") {
|
||||
trans_fn_attrs.flags |= TransFnAttrFlags::NAKED;
|
||||
} else if attr.check_name("inline") {
|
||||
trans_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
|
||||
if attr.path != "inline" {
|
||||
return ia;
|
||||
}
|
||||
let meta = match attr.meta() {
|
||||
Some(meta) => meta.node,
|
||||
None => return ia,
|
||||
};
|
||||
match meta {
|
||||
MetaItemKind::Word => {
|
||||
mark_used(attr);
|
||||
InlineAttr::Hint
|
||||
}
|
||||
MetaItemKind::List(ref items) => {
|
||||
mark_used(attr);
|
||||
if items.len() != 1 {
|
||||
span_err!(tcx.sess.diagnostic(), attr.span, E0534,
|
||||
"expected one argument");
|
||||
InlineAttr::None
|
||||
} else if list_contains_name(&items[..], "always") {
|
||||
InlineAttr::Always
|
||||
} else if list_contains_name(&items[..], "never") {
|
||||
InlineAttr::Never
|
||||
} else {
|
||||
span_err!(tcx.sess.diagnostic(), items[0].span, E0535,
|
||||
"invalid argument");
|
||||
|
||||
InlineAttr::None
|
||||
}
|
||||
}
|
||||
_ => ia,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3705,6 +3705,75 @@ match r {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0534: r##"
|
||||
The `inline` attribute was malformed.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```ignore (compile_fail not working here; see Issue #43707)
|
||||
#[inline()] // error: expected one argument
|
||||
pub fn something() {}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
The parenthesized `inline` attribute requires the parameter to be specified:
|
||||
|
||||
```
|
||||
#[inline(always)]
|
||||
fn something() {}
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```
|
||||
#[inline(never)]
|
||||
fn something() {}
|
||||
```
|
||||
|
||||
Alternatively, a paren-less version of the attribute may be used to hint the
|
||||
compiler about inlining opportunity:
|
||||
|
||||
```
|
||||
#[inline]
|
||||
fn something() {}
|
||||
```
|
||||
|
||||
For more information about the inline attribute, read:
|
||||
https://doc.rust-lang.org/reference.html#inline-attributes
|
||||
"##,
|
||||
|
||||
E0535: r##"
|
||||
An unknown argument was given to the `inline` attribute.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```ignore (compile_fail not working here; see Issue #43707)
|
||||
#[inline(unknown)] // error: invalid argument
|
||||
pub fn something() {}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
The `inline` attribute only supports two arguments:
|
||||
|
||||
* always
|
||||
* never
|
||||
|
||||
All other arguments given to the `inline` attribute will return this error.
|
||||
Example:
|
||||
|
||||
```
|
||||
#[inline(never)] // ok!
|
||||
pub fn something() {}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
For more information about the inline attribute, https:
|
||||
read://doc.rust-lang.org/reference.html#inline-attributes
|
||||
"##,
|
||||
|
||||
E0559: r##"
|
||||
An unknown field was specified into an enum's structure variant.
|
||||
|
||||
|
|
|
|||
|
|
@ -520,7 +520,7 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
|
|||
first_attr_value_str_by_name(attrs, "crate_name")
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum InlineAttr {
|
||||
None,
|
||||
Hint,
|
||||
|
|
@ -528,43 +528,6 @@ pub enum InlineAttr {
|
|||
Never,
|
||||
}
|
||||
|
||||
/// Determine what `#[inline]` attribute is present in `attrs`, if any.
|
||||
pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> InlineAttr {
|
||||
attrs.iter().fold(InlineAttr::None, |ia, attr| {
|
||||
if attr.path != "inline" {
|
||||
return ia;
|
||||
}
|
||||
let meta = match attr.meta() {
|
||||
Some(meta) => meta.node,
|
||||
None => return ia,
|
||||
};
|
||||
match meta {
|
||||
MetaItemKind::Word => {
|
||||
mark_used(attr);
|
||||
InlineAttr::Hint
|
||||
}
|
||||
MetaItemKind::List(ref items) => {
|
||||
mark_used(attr);
|
||||
if items.len() != 1 {
|
||||
diagnostic.map(|d|{ span_err!(d, attr.span, E0534, "expected one argument"); });
|
||||
InlineAttr::None
|
||||
} else if list_contains_name(&items[..], "always") {
|
||||
InlineAttr::Always
|
||||
} else if list_contains_name(&items[..], "never") {
|
||||
InlineAttr::Never
|
||||
} else {
|
||||
diagnostic.map(|d| {
|
||||
span_err!(d, items[0].span, E0535, "invalid argument");
|
||||
});
|
||||
|
||||
InlineAttr::None
|
||||
}
|
||||
}
|
||||
_ => ia,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum UnwindAttr {
|
||||
Allowed,
|
||||
|
|
@ -610,13 +573,6 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
|
|||
})
|
||||
}
|
||||
|
||||
/// True if `#[inline]` or `#[inline(always)]` is present in `attrs`.
|
||||
pub fn requests_inline(attrs: &[Attribute]) -> bool {
|
||||
match find_inline_attr(None, attrs) {
|
||||
InlineAttr::Hint | InlineAttr::Always => true,
|
||||
InlineAttr::None | InlineAttr::Never => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests if a cfg-pattern matches the cfg set
|
||||
pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool {
|
||||
|
|
|
|||
|
|
@ -37,75 +37,6 @@ More details can be found in [RFC 438].
|
|||
[RFC 438]: https://github.com/rust-lang/rfcs/pull/438
|
||||
"##,
|
||||
|
||||
E0534: r##"
|
||||
The `inline` attribute was malformed.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```ignore (compile_fail not working here; see Issue #43707)
|
||||
#[inline()] // error: expected one argument
|
||||
pub fn something() {}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
The parenthesized `inline` attribute requires the parameter to be specified:
|
||||
|
||||
```
|
||||
#[inline(always)]
|
||||
fn something() {}
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```
|
||||
#[inline(never)]
|
||||
fn something() {}
|
||||
```
|
||||
|
||||
Alternatively, a paren-less version of the attribute may be used to hint the
|
||||
compiler about inlining opportunity:
|
||||
|
||||
```
|
||||
#[inline]
|
||||
fn something() {}
|
||||
```
|
||||
|
||||
For more information about the inline attribute, read:
|
||||
https://doc.rust-lang.org/reference.html#inline-attributes
|
||||
"##,
|
||||
|
||||
E0535: r##"
|
||||
An unknown argument was given to the `inline` attribute.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```ignore (compile_fail not working here; see Issue #43707)
|
||||
#[inline(unknown)] // error: invalid argument
|
||||
pub fn something() {}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
The `inline` attribute only supports two arguments:
|
||||
|
||||
* always
|
||||
* never
|
||||
|
||||
All other arguments given to the `inline` attribute will return this error.
|
||||
Example:
|
||||
|
||||
```
|
||||
#[inline(never)] // ok!
|
||||
pub fn something() {}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
For more information about the inline attribute, https:
|
||||
read://doc.rust-lang.org/reference.html#inline-attributes
|
||||
"##,
|
||||
|
||||
E0536: r##"
|
||||
The `not` cfg-predicate was malformed.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue