fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
-> Box<MacResult + 'static> {
- static NUMERALS: &'static [(&'static str, u32)] = &[
+ static NUMERALS: &'static [(&'static str, usize)] = &[
("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
("I", 1)];
- let text = match args {
- [TokenTree::Token(_, token::Ident(s, _))] => s.to_string(),
+ if args.len() != 1 {
+ cx.span_err(
+ sp,
+ &format!("argument should be a single identifier, but got {} arguments", args.len()));
+ return DummyResult::any(sp);
+ }
+
+ let text = match args[0] {
+ TokenTree::Token(_, token::Ident(s, _)) => s.to_string(),
_ => {
cx.span_err(sp, "argument should be a single identifier");
return DummyResult::any(sp);
}
}
- MacEager::expr(cx.expr_u32(sp, total))
+ MacEager::expr(cx.expr_usize(sp, total))
}
#[plugin_registrar]
//! for all lint attributes.
use self::TargetLint::*;
-use middle::privacy::ExportedItems;
+use middle::privacy::AccessLevels;
use middle::ty::{self, Ty};
use session::{early_error, Session};
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
/// The crate being checked.
pub krate: &'a hir::Crate,
- /// Items exported from the crate being checked.
- pub exported_items: &'a ExportedItems,
+ /// Items accessible from the crate being checked.
+ pub access_levels: &'a AccessLevels,
/// The store of registered lints.
lints: LintStore,
impl<'a, 'tcx> LateContext<'a, 'tcx> {
fn new(tcx: &'a ty::ctxt<'tcx>,
krate: &'a hir::Crate,
- exported_items: &'a ExportedItems) -> LateContext<'a, 'tcx> {
+ access_levels: &'a AccessLevels) -> LateContext<'a, 'tcx> {
// We want to own the lint store, so move it out of the session.
let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
LintStore::new());
LateContext {
tcx: tcx,
krate: krate,
- exported_items: exported_items,
+ access_levels: access_levels,
lints: lint_store,
level_stack: vec![],
node_levels: RefCell::new(FnvHashMap()),
/// Perform lint checking on a crate.
///
/// Consumes the `lint_store` field of the `Session`.
-pub fn check_crate(tcx: &ty::ctxt,
- exported_items: &ExportedItems) {
+pub fn check_crate(tcx: &ty::ctxt, access_levels: &AccessLevels) {
let krate = tcx.map.krate();
- let mut cx = LateContext::new(tcx, krate, exported_items);
+ let mut cx = LateContext::new(tcx, krate, access_levels);
// Visit the whole crate.
cx.with_lint_attrs(&krate.attrs, |cx| {
};
let (
decl,
- unsafety,
- abi,
block,
constness,
) = match try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)) {
Some(ast_map::NodeItem(it)) => match it.node {
hir::ItemFn(
ref decl,
- unsafety,
+ hir::Unsafety::Normal,
constness,
- abi,
+ abi::Abi::Rust,
_, // ducktype generics? types are funky in const_eval
ref block,
- ) => (decl, unsafety, abi, block, constness),
+ ) => (decl, block, constness),
_ => signal!(e, NonConstPath),
},
_ => signal!(e, NonConstPath),
},
_ => signal!(e, NonConstPath),
};
- if let ExprTypeChecked = ty_hint {
- // no need to check for constness... either check_const
- // already forbids this or we const eval over whatever
- // we want
- } else {
- // we don't know much about the function, so we force it to be a const fn
- // so compilation will fail later in case the const fn's body is not const
- assert_eq!(constness, hir::Constness::Const)
+ match (ty_hint, constness) {
+ (ExprTypeChecked, _) => {
+ // no need to check for constness... either check_const
+ // already forbids this or we const eval over whatever
+ // we want
+ },
+ (_, hir::Constness::Const) => {
+ // we don't know much about the function, so we force it to be a const fn
+ // so compilation will fail later in case the const fn's body is not const
+ },
+ _ => signal!(e, NonConstPath),
}
assert_eq!(decl.inputs.len(), args.len());
- assert_eq!(unsafety, hir::Unsafety::Normal);
- assert_eq!(abi, abi::Abi::Rust);
let mut call_args = NodeMap();
for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) {
use middle::{def, pat_util, privacy, ty};
use middle::def_id::{DefId};
use lint;
-use util::nodemap::NodeSet;
use std::collections::HashSet;
use syntax::{ast, codemap};
}
fn create_and_seed_worklist(tcx: &ty::ctxt,
- exported_items: &privacy::ExportedItems,
- reachable_symbols: &NodeSet,
+ access_levels: &privacy::AccessLevels,
krate: &hir::Crate) -> Vec<ast::NodeId> {
let mut worklist = Vec::new();
-
- // Preferably, we would only need to seed the worklist with reachable
- // symbols. However, since the set of reachable symbols differs
- // depending on whether a crate is built as bin or lib, and we want
- // the warning to be consistent, we also seed the worklist with
- // exported symbols.
- for id in exported_items {
- worklist.push(*id);
- }
- for id in reachable_symbols {
- // Reachable variants can be dead, because we warn about
- // variants never constructed, not variants never used.
- if let Some(ast_map::NodeVariant(..)) = tcx.map.find(*id) {
- continue;
- }
+ for (id, _) in &access_levels.map {
worklist.push(*id);
}
}
fn find_live(tcx: &ty::ctxt,
- exported_items: &privacy::ExportedItems,
- reachable_symbols: &NodeSet,
+ access_levels: &privacy::AccessLevels,
krate: &hir::Crate)
-> Box<HashSet<ast::NodeId>> {
- let worklist = create_and_seed_worklist(tcx, exported_items,
- reachable_symbols, krate);
+ let worklist = create_and_seed_worklist(tcx, access_levels, krate);
let mut symbol_visitor = MarkSymbolVisitor::new(tcx, worklist);
symbol_visitor.mark_live_symbols();
symbol_visitor.live_symbols
}
}
-pub fn check_crate(tcx: &ty::ctxt,
- exported_items: &privacy::ExportedItems,
- reachable_symbols: &NodeSet) {
+pub fn check_crate(tcx: &ty::ctxt, access_levels: &privacy::AccessLevels) {
let krate = tcx.map.krate();
- let live_symbols = find_live(tcx, exported_items,
- reachable_symbols, krate);
+ let live_symbols = find_live(tcx, access_levels, krate);
let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols };
intravisit::walk_crate(&mut visitor, krate);
}
pub use self::LastPrivate::*;
use middle::def_id::DefId;
-use util::nodemap::{DefIdSet, NodeSet};
+use util::nodemap::{DefIdSet, FnvHashMap};
-/// A set of AST nodes exported by the crate.
-pub type ExportedItems = NodeSet;
+use std::hash::Hash;
+use syntax::ast::NodeId;
+
+// Accessibility levels, sorted in ascending order
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum AccessLevel {
+ // Exported items + items participating in various kinds of public interfaces,
+ // but not directly nameable. For example, if function `fn f() -> T {...}` is
+ // public, then type `T` is exported. Its values can be obtained by other crates
+ // even if the type itseld is not nameable.
+ // FIXME: Mostly unimplemented. Only `type` aliases export items currently.
+ Reachable,
+ // Public items + items accessible to other crates with help of `pub use` reexports
+ Exported,
+ // Items accessible to other crates directly, without help of reexports
+ Public,
+}
+
+// Accessibility levels for reachable HIR nodes
+#[derive(Clone)]
+pub struct AccessLevels<Id = NodeId> {
+ pub map: FnvHashMap<Id, AccessLevel>
+}
+
+impl<Id: Hash + Eq> AccessLevels<Id> {
+ pub fn is_reachable(&self, id: Id) -> bool {
+ self.map.contains_key(&id)
+ }
+ pub fn is_exported(&self, id: Id) -> bool {
+ self.map.get(&id) >= Some(&AccessLevel::Exported)
+ }
+ pub fn is_public(&self, id: Id) -> bool {
+ self.map.get(&id) >= Some(&AccessLevel::Public)
+ }
+}
+
+impl<Id: Hash + Eq> Default for AccessLevels<Id> {
+ fn default() -> Self {
+ AccessLevels { map: Default::default() }
+ }
+}
/// A set containing all exported definitions from external crates.
/// The set does not contain any entries from local crates.
pub type ExternalExports = DefIdSet;
-/// A set of AST nodes that are fully public in the crate. This map is used for
-/// documentation purposes (reexporting a private struct inlines the doc,
-/// reexporting a public struct doesn't inline the doc).
-pub type PublicItems = NodeSet;
-
#[derive(Copy, Clone, Debug)]
pub enum LastPrivate {
LastMod(PrivateDep),
// trait items are used from inlinable code through method call syntax or UFCS, or their
// trait is a lang item.
struct CollectPrivateImplItemsVisitor<'a> {
- exported_items: &'a privacy::ExportedItems,
+ access_levels: &'a privacy::AccessLevels,
worklist: &'a mut Vec<ast::NodeId>,
}
fn visit_item(&mut self, item: &hir::Item) {
// We need only trait impls here, not inherent impls, and only non-exported ones
if let hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) = item.node {
- if !self.exported_items.contains(&item.id) {
+ if !self.access_levels.is_reachable(item.id) {
for impl_item in impl_items {
self.worklist.push(impl_item.id);
}
}
pub fn find_reachable(tcx: &ty::ctxt,
- exported_items: &privacy::ExportedItems)
+ access_levels: &privacy::AccessLevels)
-> NodeSet {
let mut reachable_context = ReachableContext::new(tcx);
// If other crates link to us, they're going to expect to be able to
// use the lang items, so we need to be sure to mark them as
// exported.
- for id in exported_items {
+ for (id, _) in &access_levels.map {
reachable_context.worklist.push(*id);
}
for (_, item) in tcx.lang_items.items() {
}
{
let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
- exported_items: exported_items,
+ access_levels: access_levels,
worklist: &mut reachable_context.worklist,
};
tcx.map.krate().visit_all_items(&mut collect_private_impl_items);
use middle::def;
use middle::def_id::{CRATE_DEF_INDEX, DefId};
use middle::ty;
-use middle::privacy::PublicItems;
+use middle::privacy::AccessLevels;
use metadata::csearch;
use syntax::parse::token::InternedString;
use syntax::codemap::{Span, DUMMY_SP};
tcx: &'a ty::ctxt<'tcx>,
index: &'a mut Index<'tcx>,
parent: Option<&'tcx Stability>,
- export_map: &'a PublicItems,
+ access_levels: &'a AccessLevels,
in_trait_impl: bool,
in_enum: bool,
}
} else {
debug!("annotate: not found, parent = {:?}", self.parent);
let mut is_error = kind == AnnotationKind::Required &&
- self.export_map.contains(&id) &&
+ self.access_levels.is_reachable(id) &&
!self.tcx.sess.opts.test;
if let Some(stab) = self.parent {
if stab.level.is_unstable() {
impl<'tcx> Index<'tcx> {
/// Construct the stability index for a crate being compiled.
- pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &'tcx Crate, export_map: &PublicItems) {
+ pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &Crate, access_levels: &AccessLevels) {
let mut annotator = Annotator {
tcx: tcx,
index: self,
parent: None,
- export_map: export_map,
+ access_levels: access_levels,
in_trait_impl: false,
in_enum: false,
};
/// produced by the driver and fed to trans and later passes.
pub struct CrateAnalysis<'a> {
pub export_map: ExportMap,
- pub exported_items: middle::privacy::ExportedItems,
- pub public_items: middle::privacy::PublicItems,
+ pub access_levels: middle::privacy::AccessLevels,
pub reachable: NodeSet,
pub name: &'a str,
pub glob_map: Option<GlobMap>,
}
-
#[derive(Copy, Clone)]
pub enum DtorKind {
NoDtor,
"optimize with possible levels 0-3"),
debug_assertions: Option<bool> = (None, parse_opt_bool,
"explicitly enable the cfg(debug_assertions) directive"),
+ inline_threshold: Option<usize> = (None, parse_opt_uint,
+ "set the inlining threshold for"),
}
"const checking",
|| middle::check_const::check_crate(tcx));
- let (exported_items, public_items) =
+ let access_levels =
time(time_passes, "privacy checking", || {
rustc_privacy::check_crate(tcx,
&export_map,
// Do not move this check past lint
time(time_passes, "stability index", || {
- tcx.stability.borrow_mut().build(tcx, krate, &exported_items)
+ tcx.stability.borrow_mut().build(tcx, krate, &access_levels)
});
time(time_passes,
let reachable_map =
time(time_passes,
"reachability checking",
- || reachable::find_reachable(tcx, &exported_items));
+ || reachable::find_reachable(tcx, &access_levels));
time(time_passes, "death checking", || {
- middle::dead::check_crate(tcx,
- &exported_items,
- &reachable_map)
+ middle::dead::check_crate(tcx, &access_levels);
});
let ref lib_features_used =
time(time_passes,
"lint checking",
- || lint::check_crate(tcx, &exported_items));
+ || lint::check_crate(tcx, &access_levels));
// The above three passes generate errors w/o aborting
tcx.sess.abort_if_errors();
mir_map,
ty::CrateAnalysis {
export_map: export_map,
- exported_items: exported_items,
- public_items: public_items,
+ access_levels: access_levels,
reachable: reachable_map,
name: name,
glob_map: glob_map,
// Only check publicly-visible items, using the result from the privacy pass.
// It's an option so the crate root can also use this function (it doesn't
// have a NodeId).
- if let Some(ref id) = id {
- if !cx.exported_items.contains(id) {
+ if let Some(id) = id {
+ if !cx.access_levels.is_exported(id) {
return;
}
}
impl LateLintPass for MissingCopyImplementations {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
- if !cx.exported_items.contains(&item.id) {
+ if !cx.access_levels.is_reachable(item.id) {
return;
}
let (def, ty) = match item.node {
impl LateLintPass for MissingDebugImplementations {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
- if !cx.exported_items.contains(&item.id) {
+ if !cx.access_levels.is_reachable(item.id) {
return;
}
match it.node {
hir::ItemFn(..) => {
if attr::contains_name(&it.attrs, "no_mangle") &&
- !cx.exported_items.contains(&it.id) {
+ !cx.access_levels.is_reachable(it.id) {
let msg = format!("function {} is marked #[no_mangle], but not exported",
it.name);
cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg);
},
hir::ItemStatic(..) => {
if attr::contains_name(&it.attrs, "no_mangle") &&
- !cx.exported_items.contains(&it.id) {
+ !cx.access_levels.is_reachable(it.id) {
let msg = format!("static {} is marked #[no_mangle], but not exported",
it.name);
cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
Model: CodeGenModel,
Reloc: RelocMode,
Level: CodeGenOptLevel,
- EnableSegstk: bool,
UseSoftFP: bool,
PositionIndependentExecutable: bool,
FunctionSections: bool,
use self::PrivacyResult::*;
use self::FieldName::*;
+use std::cmp;
use std::mem::replace;
use rustc_front::hir;
use rustc::middle::def;
use rustc::middle::def_id::DefId;
+use rustc::middle::privacy::{AccessLevel, AccessLevels};
use rustc::middle::privacy::ImportUse::*;
use rustc::middle::privacy::LastPrivate::*;
use rustc::middle::privacy::PrivateDep::*;
-use rustc::middle::privacy::{ExternalExports, ExportedItems, PublicItems};
+use rustc::middle::privacy::ExternalExports;
use rustc::middle::ty::{self, Ty};
-use rustc::util::nodemap::{NodeMap, NodeSet};
+use rustc::util::nodemap::NodeMap;
use rustc::front::map as ast_map;
use syntax::ast;
tcx: &'a ty::ctxt<'tcx>,
export_map: &'a def::ExportMap,
- // This flag is an indicator of whether the previous item in the
- // hierarchical chain was exported or not. This is the indicator of whether
- // children should be exported as well. Note that this can flip from false
- // to true if a reexported module is entered (or an action similar).
- prev_exported: bool,
-
- // This is a list of all exported items in the AST. An exported item is any
- // function/method/item which is usable by external crates. This essentially
- // means that the result is "public all the way down", but the "path down"
- // may jump across private boundaries through reexport statements or type aliases.
- exported_items: ExportedItems,
-
- // Items that are directly public without help of reexports or type aliases.
- // These two fields are closely related to one another in that they are only
- // used for generation of the `public_items` set, not for privacy checking at
- // all. Invariant: at any moment public items are a subset of exported items.
- public_items: PublicItems,
- prev_public: bool,
+ // Accessibility levels for reachable nodes
+ access_levels: AccessLevels,
+ // Previous accessibility level, None means unreachable
+ prev_level: Option<AccessLevel>,
+ // Have something changed in the level map?
+ changed: bool,
}
impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
- // Returns tuple (is_public, is_exported) for a type
- fn is_public_exported_ty(&self, ty: &hir::Ty) -> (bool, bool) {
+ fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
if let hir::TyPath(..) = ty.node {
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {
- (true, true)
+ Some(AccessLevel::Public)
}
def => {
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
- (self.public_items.contains(&node_id),
- self.exported_items.contains(&node_id))
+ self.get(node_id)
} else {
- (true, true)
+ Some(AccessLevel::Public)
}
}
}
} else {
- (true, true)
+ Some(AccessLevel::Public)
}
}
- // Returns tuple (is_public, is_exported) for a trait
- fn is_public_exported_trait(&self, trait_ref: &hir::TraitRef) -> (bool, bool) {
+ fn trait_level(&self, trait_ref: &hir::TraitRef) -> Option<AccessLevel> {
let did = self.tcx.trait_ref_to_def_id(trait_ref);
if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
- (self.public_items.contains(&node_id), self.exported_items.contains(&node_id))
+ self.get(node_id)
} else {
- (true, true)
+ Some(AccessLevel::Public)
}
}
- fn maybe_insert_id(&mut self, id: ast::NodeId) {
- if self.prev_public {
- self.public_items.insert(id);
- }
- if self.prev_exported {
- self.exported_items.insert(id);
+ fn get(&self, id: ast::NodeId) -> Option<AccessLevel> {
+ self.access_levels.map.get(&id).cloned()
+ }
+
+ // Updates node level and returns the updated level
+ fn update(&mut self, id: ast::NodeId, level: Option<AccessLevel>) -> Option<AccessLevel> {
+ let old_level = self.get(id);
+ // Accessibility levels can only grow
+ if level > old_level {
+ self.access_levels.map.insert(id, level.unwrap());
+ self.changed = true;
+ level
+ } else {
+ old_level
}
}
}
fn visit_nested_item(&mut self, item: hir::ItemId) {
self.visit_item(self.tcx.map.expect_item(item.id))
}
+
fn visit_item(&mut self, item: &hir::Item) {
- let orig_all_public = self.prev_public;
- let orig_all_exported = self.prev_exported;
- match item.node {
- // impls/extern blocks do not break the "public chain" because they
- // cannot have visibility qualifiers on them anyway. Impls are also not
- // added to public/exported sets based on inherited publicity.
- hir::ItemImpl(..) | hir::ItemDefaultImpl(..) => {}
+ let inherited_item_level = match item.node {
+ // Impls inherit level from their types and traits
+ hir::ItemImpl(_, _, _, None, ref ty, _) => {
+ self.ty_level(&ty)
+ }
+ hir::ItemImpl(_, _, _, Some(ref trait_ref), ref ty, _) => {
+ cmp::min(self.ty_level(&ty), self.trait_level(trait_ref))
+ }
+ hir::ItemDefaultImpl(_, ref trait_ref) => {
+ self.trait_level(trait_ref)
+ }
+ // Foreign mods inherit level from parents
hir::ItemForeignMod(..) => {
- self.maybe_insert_id(item.id);
+ self.prev_level
}
-
- // Private by default, hence we only retain the "public chain" if
- // `pub` is explicitly listed.
+ // Other `pub` items inherit levels from parents
_ => {
- self.prev_public = self.prev_public && item.vis == hir::Public;
- self.prev_exported = (self.prev_exported && item.vis == hir::Public) ||
- self.exported_items.contains(&item.id);
-
- self.maybe_insert_id(item.id);
+ if item.vis == hir::Public { self.prev_level } else { None }
}
- }
+ };
+ // Update id of the item itself
+ let item_level = self.update(item.id, inherited_item_level);
+
+ // Update ids of nested things
match item.node {
- // Enum variants inherit from their parent, so if the enum is
- // public all variants are public
hir::ItemEnum(ref def, _) => {
for variant in &def.variants {
- self.maybe_insert_id(variant.node.data.id());
+ let variant_level = self.update(variant.node.data.id(), item_level);
for field in variant.node.data.fields() {
- // Variant fields are always public
- self.maybe_insert_id(field.node.id);
+ self.update(field.node.id, variant_level);
}
}
}
-
- // Inherent impls for public/exported types and their public items are public/exported
- hir::ItemImpl(_, _, _, None, ref ty, ref impl_items) => {
- let (public_ty, exported_ty) = self.is_public_exported_ty(&ty);
-
- if public_ty {
- self.public_items.insert(item.id);
- }
- if exported_ty {
- self.exported_items.insert(item.id);
- }
-
+ hir::ItemImpl(_, _, _, None, _, ref impl_items) => {
for impl_item in impl_items {
if impl_item.vis == hir::Public {
- if public_ty {
- self.public_items.insert(impl_item.id);
- }
- if exported_ty {
- self.exported_items.insert(impl_item.id);
- }
+ self.update(impl_item.id, item_level);
}
}
}
-
- // Trait impl and its items are public/exported if both the self type and the trait
- // of this impl are public/exported
- hir::ItemImpl(_, _, _, Some(ref trait_ref), ref ty, ref impl_items) => {
- let (public_ty, exported_ty) = self.is_public_exported_ty(&ty);
- let (public_trait, exported_trait) = self.is_public_exported_trait(trait_ref);
-
- if public_ty && public_trait {
- self.public_items.insert(item.id);
- }
- if exported_ty && exported_trait {
- self.exported_items.insert(item.id);
- }
-
+ hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) => {
for impl_item in impl_items {
- if public_ty && public_trait {
- self.public_items.insert(impl_item.id);
- }
- if exported_ty && exported_trait {
- self.exported_items.insert(impl_item.id);
- }
- }
- }
-
- // Default trait impls are public/exported for public/exported traits
- hir::ItemDefaultImpl(_, ref trait_ref) => {
- let (public_trait, exported_trait) = self.is_public_exported_trait(trait_ref);
-
- if public_trait {
- self.public_items.insert(item.id);
- }
- if exported_trait {
- self.exported_items.insert(item.id);
+ self.update(impl_item.id, item_level);
}
}
-
- // Default methods on traits are all public/exported so long as the trait
- // is public/exported
hir::ItemTrait(_, _, _, ref trait_items) => {
for trait_item in trait_items {
- self.maybe_insert_id(trait_item.id);
+ self.update(trait_item.id, item_level);
}
}
-
- // Struct constructors are public if the struct is all public.
hir::ItemStruct(ref def, _) => {
if !def.is_struct() {
- self.maybe_insert_id(def.id());
+ self.update(def.id(), item_level);
}
for field in def.fields() {
- // Struct fields can be public or private, so lets check
if field.node.kind.visibility() == hir::Public {
- self.maybe_insert_id(field.node.id);
+ self.update(field.node.id, item_level);
}
}
}
-
- hir::ItemTy(ref ty, _) if self.prev_exported => {
+ hir::ItemForeignMod(ref foreign_mod) => {
+ for foreign_item in &foreign_mod.items {
+ if foreign_item.vis == hir::Public {
+ self.update(foreign_item.id, item_level);
+ }
+ }
+ }
+ hir::ItemTy(ref ty, _) if item_level.is_some() => {
if let hir::TyPath(..) = ty.node {
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {},
def => {
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
- self.exported_items.insert(node_id);
+ self.update(node_id, Some(AccessLevel::Reachable));
}
}
}
}
}
-
- hir::ItemForeignMod(ref foreign_mod) => {
- for foreign_item in &foreign_mod.items {
- let public = self.prev_public && foreign_item.vis == hir::Public;
- let exported = (self.prev_exported && foreign_item.vis == hir::Public) ||
- self.exported_items.contains(&foreign_item.id);
-
- if public {
- self.public_items.insert(foreign_item.id);
- }
- if exported {
- self.exported_items.insert(foreign_item.id);
- }
- }
- }
-
_ => {}
}
+ let orig_level = self.prev_level;
+ self.prev_level = item_level;
+
intravisit::walk_item(self, item);
- self.prev_public = orig_all_public;
- self.prev_exported = orig_all_exported;
+ self.prev_level = orig_level;
}
fn visit_block(&mut self, b: &'v hir::Block) {
- let orig_all_public = replace(&mut self.prev_public, false);
- let orig_all_exported = replace(&mut self.prev_exported, false);
+ let orig_level = replace(&mut self.prev_level, None);
- // Blocks can have exported and public items, for example impls, but they always
- // start as non-public and non-exported regardless of publicity of a function,
+ // Blocks can have public items, for example impls, but they always
+ // start as completely private regardless of publicity of a function,
// constant, type, field, etc. in which this block resides
intravisit::walk_block(self, b);
- self.prev_public = orig_all_public;
- self.prev_exported = orig_all_exported;
+ self.prev_level = orig_level;
}
fn visit_mod(&mut self, m: &hir::Mod, _sp: Span, id: ast::NodeId) {
// This code is here instead of in visit_item so that the
// crate module gets processed as well.
- if self.prev_exported {
- assert!(self.export_map.contains_key(&id), "wut {}", id);
- for export in self.export_map.get(&id).unwrap() {
+ if self.prev_level.is_some() {
+ for export in self.export_map.get(&id).expect("module isn't found in export map") {
if let Some(node_id) = self.tcx.map.as_local_node_id(export.def_id) {
- self.exported_items.insert(node_id);
+ self.update(node_id, Some(AccessLevel::Exported));
}
}
}
- intravisit::walk_mod(self, m)
+
+ intravisit::walk_mod(self, m);
}
fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
- self.maybe_insert_id(md.id);
+ self.update(md.id, Some(AccessLevel::Public));
}
}
struct VisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
- exported_items: &'a ExportedItems,
- public_items: &'a PublicItems,
+ access_levels: &'a AccessLevels,
in_variant: bool,
}
fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
// FIXME: this would preferably be using `exported_items`, but all
// traits are exported currently (see `EmbargoVisitor.exported_trait`)
- self.public_items.contains(&trait_id)
+ self.access_levels.is_public(trait_id)
}
fn check_ty_param_bound(&self,
}
fn item_is_public(&self, id: &ast::NodeId, vis: hir::Visibility) -> bool {
- self.exported_items.contains(id) || vis == hir::Public
+ self.access_levels.is_reachable(*id) || vis == hir::Public
}
}
match impl_item.node {
hir::ImplItemKind::Const(..) |
hir::ImplItemKind::Method(..) => {
- self.exported_items.contains(&impl_item.id)
+ self.access_levels.is_reachable(impl_item.id)
}
hir::ImplItemKind::Type(_) => false,
}
}
fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
- if self.exported_items.contains(&item.id) {
+ if self.access_levels.is_reachable(item.id) {
intravisit::walk_foreign_item(self, item)
}
}
}
fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
- if self.exported_items.contains(&v.node.data.id()) {
+ if self.access_levels.is_reachable(v.node.data.id()) {
self.in_variant = true;
intravisit::walk_variant(self, v, g, item_id);
self.in_variant = false;
pub fn check_crate(tcx: &ty::ctxt,
export_map: &def::ExportMap,
external_exports: ExternalExports)
- -> (ExportedItems, PublicItems) {
+ -> AccessLevels {
let krate = tcx.map.krate();
// Sanity check to make sure that all privacy usage and controls are
// items which are reachable from external crates based on visibility.
let mut visitor = EmbargoVisitor {
tcx: tcx,
- exported_items: NodeSet(),
- public_items: NodeSet(),
export_map: export_map,
- prev_exported: true,
- prev_public: true,
+ access_levels: Default::default(),
+ prev_level: Some(AccessLevel::Public),
+ changed: false,
};
- visitor.exported_items.insert(ast::CRATE_NODE_ID);
- visitor.public_items.insert(ast::CRATE_NODE_ID);
loop {
- let before = (visitor.exported_items.len(), visitor.public_items.len());
intravisit::walk_crate(&mut visitor, krate);
- let after = (visitor.exported_items.len(), visitor.public_items.len());
- if after == before {
+ if visitor.changed {
+ visitor.changed = false;
+ } else {
break
}
}
+ visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public));
- let EmbargoVisitor { exported_items, public_items, .. } = visitor;
+ let EmbargoVisitor { access_levels, .. } = visitor;
{
let mut visitor = VisiblePrivateTypesVisitor {
tcx: tcx,
- exported_items: &exported_items,
- public_items: &public_items,
+ access_levels: &access_levels,
in_variant: false,
};
intravisit::walk_crate(&mut visitor, krate);
}
- return (exported_items, public_items);
+
+ access_levels
}
code_model,
reloc_model,
opt_level,
- true /* EnableSegstk */,
use_softfp,
!any_library && reloc_model == llvm::RelocPIC,
ffunction_sections,
vectorize_loop: bool,
vectorize_slp: bool,
merge_functions: bool,
+ inline_threshold: Option<usize>
}
unsafe impl Send for ModuleConfig { }
vectorize_loop: false,
vectorize_slp: false,
merge_functions: false,
+ inline_threshold: None
}
}
self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
self.no_builtins = trans.no_builtins;
self.time_passes = sess.time_passes();
+ self.inline_threshold = sess.opts.cg.inline_threshold;
// Copy what clang does by turning on loop vectorization at O2 and
// slp vectorization at O3. Otherwise configure other optimization aspects
// manager.
let builder = llvm::LLVMPassManagerBuilderCreate();
let opt = config.opt_level.unwrap_or(llvm::CodeGenLevelNone);
+ let inline_threshold = config.inline_threshold;
llvm::LLVMRustConfigurePassManagerBuilder(builder, opt,
config.merge_functions,
// always-inline functions (but don't add lifetime intrinsics), at O1 we
// inline with lifetime intrinsics, and O2+ we add an inliner with a
// thresholds copied from clang.
- match opt {
- llvm::CodeGenLevelNone => {
+ match (opt, inline_threshold) {
+ (_, Some(t)) => {
+ llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32);
+ }
+ (llvm::CodeGenLevelNone, _) => {
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
}
- llvm::CodeGenLevelLess => {
+ (llvm::CodeGenLevelLess, _) => {
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
}
- llvm::CodeGenLevelDefault => {
+ (llvm::CodeGenLevelDefault, _) => {
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
}
- llvm::CodeGenLevelAggressive => {
+ (llvm::CodeGenLevelAggressive, _) => {
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
}
}
ty::TyBareFn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
_ => panic!("bad function"),
};
+
+ let constness = if csearch::is_const_fn(&tcx.sess.cstore, did) {
+ hir::Constness::Const
+ } else {
+ hir::Constness::NotConst
+ };
+
let predicates = tcx.lookup_predicates(did);
clean::Function {
decl: decl,
generics: (&t.generics, &predicates, subst::FnSpace).clean(cx),
unsafety: style,
- constness: hir::Constness::NotConst,
+ constness: constness,
abi: abi,
}
}
clean::TyMethodItem(clean::TyMethod {
unsafety, decl, self_, generics, abi
}) => {
+ let constness = if csearch::is_const_fn(&tcx.sess.cstore, did) {
+ hir::Constness::Const
+ } else {
+ hir::Constness::NotConst
+ };
+
clean::MethodItem(clean::Method {
unsafety: unsafety,
- constness: hir::Constness::NotConst,
+ constness: constness,
decl: decl,
self_: self_,
generics: generics,
use rustc_driver::{driver, target_features};
use rustc::session::{self, config};
use rustc::middle::def_id::DefId;
+use rustc::middle::privacy::AccessLevels;
use rustc::middle::ty;
use rustc::front::map as hir_map;
use rustc::lint;
-use rustc::util::nodemap::DefIdSet;
use rustc_trans::back::link;
use rustc_resolve as resolve;
use rustc_front::lowering::{lower_crate, LoweringContext};
}
pub struct CrateAnalysis {
- pub exported_items: DefIdSet,
- pub public_items: DefIdSet,
+ pub access_levels: AccessLevels<DefId>,
pub external_paths: ExternalPaths,
pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
pub inlined: RefCell<Option<HashSet<DefId>>>,
&name,
resolve::MakeGlobMap::No,
|tcx, _, analysis| {
- let ty::CrateAnalysis { exported_items, public_items, .. } = analysis;
+ let ty::CrateAnalysis { access_levels, .. } = analysis;
// Convert from a NodeId set to a DefId set since we don't always have easy access
// to the map from defid -> nodeid
- let exported_items: DefIdSet =
- exported_items.into_iter()
- .map(|n| tcx.map.local_def_id(n))
- .collect();
- let public_items: DefIdSet =
- public_items.into_iter()
- .map(|n| tcx.map.local_def_id(n))
- .collect();
+ let access_levels = AccessLevels {
+ map: access_levels.map.into_iter()
+ .map(|(k, v)| (tcx.map.local_def_id(k), v))
+ .collect()
+ };
let ctxt = DocContext {
map: &tcx.map,
debug!("crate: {:?}", ctxt.map.krate());
let mut analysis = CrateAnalysis {
- exported_items: exported_items,
- public_items: public_items,
+ access_levels: access_levels,
external_paths: RefCell::new(None),
external_typarams: RefCell::new(None),
inlined: RefCell::new(None),
use syntax::{abi, ast};
use rustc::metadata::cstore::LOCAL_CRATE;
use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::middle::privacy::AccessLevels;
use rustc::middle::stability;
-use rustc::util::nodemap::DefIdSet;
use rustc_front::hir;
use clean::{self, SelfTy};
search_index: Vec<IndexItem>,
privmod: bool,
remove_priv: bool,
- public_items: DefIdSet,
+ access_levels: AccessLevels<DefId>,
deref_trait_did: Option<DefId>,
// In rare case where a structure is defined in one module but implemented
// Crawl the crate to build various caches used for the output
let analysis = ::ANALYSISKEY.with(|a| a.clone());
let analysis = analysis.borrow();
- let public_items = analysis.as_ref().map(|a| a.public_items.clone());
- let public_items = public_items.unwrap_or(DefIdSet());
+ let access_levels = analysis.as_ref().map(|a| a.access_levels.clone());
+ let access_levels = access_levels.unwrap_or(Default::default());
let paths: HashMap<DefId, (Vec<String>, ItemType)> =
analysis.as_ref().map(|a| {
let paths = a.external_paths.borrow_mut().take().unwrap();
primitive_locations: HashMap::new(),
remove_priv: cx.passes.contains("strip-private"),
privmod: false,
- public_items: public_items,
+ access_levels: access_levels,
orphan_methods: Vec::new(),
traits: mem::replace(&mut krate.external_traits, HashMap::new()),
deref_trait_did: analysis.as_ref().and_then(|a| a.deref_trait_did),
if
!self.paths.contains_key(&item.def_id) ||
!item.def_id.is_local() ||
- self.public_items.contains(&item.def_id)
+ self.access_levels.is_public(item.def_id)
{
self.paths.insert(item.def_id,
(self.stack.clone(), shortty(&item)));
fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
f: &clean::Function) -> fmt::Result {
- try!(write!(w, "<pre class='rust fn'>{vis}{unsafety}{abi}{constness}fn \
+ try!(write!(w, "<pre class='rust fn'>{vis}{constness}{unsafety}{abi}fn \
{name}{generics}{decl}{where_clause}</pre>",
vis = VisSpace(it.visibility),
+ constness = ConstnessSpace(f.constness),
unsafety = UnsafetySpace(f.unsafety),
abi = AbiSpace(f.abi),
- constness = ConstnessSpace(f.constness),
name = it.name.as_ref().unwrap(),
generics = f.generics,
where_clause = WhereClause(&f.generics),
};
write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
{generics}{decl}{where_clause}",
- UnsafetySpace(unsafety),
ConstnessSpace(constness),
+ UnsafetySpace(unsafety),
match abi {
Abi::Rust => String::new(),
a => format!("extern {} ", a.to_string())
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use rustc::middle::def_id::DefId;
+use rustc::middle::privacy::AccessLevels;
use rustc::util::nodemap::DefIdSet;
use std::cmp;
use std::string::String;
let analysis = super::ANALYSISKEY.with(|a| a.clone());
let analysis = analysis.borrow();
let analysis = analysis.as_ref().unwrap();
- let exported_items = analysis.exported_items.clone();
+ let access_levels = analysis.access_levels.clone();
// strip all private items
{
let mut stripper = Stripper {
retained: &mut retained,
- exported_items: &exported_items,
+ access_levels: &access_levels,
};
krate = stripper.fold_crate(krate);
}
struct Stripper<'a> {
retained: &'a mut DefIdSet,
- exported_items: &'a DefIdSet,
+ access_levels: &'a AccessLevels<DefId>,
}
impl<'a> fold::DocFolder for Stripper<'a> {
clean::VariantItem(..) | clean::MethodItem(..) |
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => {
if i.def_id.is_local() {
- if !self.exported_items.contains(&i.def_id) {
- return None;
- }
- // Traits are in exported_items even when they're totally private.
- if i.is_trait() && i.visibility != Some(hir::Public) {
+ if !self.access_levels.is_exported(i.def_id) {
return None;
}
}
}
clean::ConstantItem(..) => {
- if i.def_id.is_local() && !self.exported_items.contains(&i.def_id) {
+ if i.def_id.is_local() && !self.access_levels.is_exported(i.def_id) {
return None;
}
}
clean::ImplItem(clean::Impl{
for_: clean::ResolvedPath{ did, .. }, ..
}) => {
- if did.is_local() && !self.exported_items.contains(&did) {
+ if did.is_local() && !self.access_levels.is_exported(did) {
return None;
}
}
let analysis = match self.analysis {
Some(analysis) => analysis, None => return false
};
- if !please_inline && analysis.public_items.contains(&def) {
+ if !please_inline && analysis.access_levels.is_public(def) {
return false
}
if !self.view_item_stack.insert(def_node_id) { return false }
/// println!("{}", x);
/// }
///
- /// let diff: HashSet<_> = a.intersection(&b).cloned().collect();
- /// assert_eq!(diff, [2, 3].iter().cloned().collect());
+ /// let intersection: HashSet<_> = a.intersection(&b).cloned().collect();
+ /// assert_eq!(intersection, [2, 3].iter().cloned().collect());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> {
/// println!("{}", x);
/// }
///
- /// let diff: HashSet<_> = a.union(&b).cloned().collect();
- /// assert_eq!(diff, [1, 2, 3, 4].iter().cloned().collect());
+ /// let union: HashSet<_> = a.union(&b).cloned().collect();
+ /// assert_eq!(union, [1, 2, 3, 4].iter().cloned().collect());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
CodeModel::Model CM,
Reloc::Model RM,
CodeGenOpt::Level OptLevel,
- bool EnableSegmentedStacks,
bool UseSoftFloat,
bool PositionIndependentExecutable,
bool FunctionSections,
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+
+pub const fn foo() {}
+pub const unsafe fn bar() {}
+
+pub struct Foo;
+
+impl Foo {
+ pub const unsafe fn baz() {}
+}
("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
("I", 1)];
- let text = match args {
- [TokenTree::Token(_, token::Ident(s, _))] => s.to_string(),
+ if args.len() != 1 {
+ cx.span_err(
+ sp,
+ &format!("argument should be a single identifier, but got {} arguments", args.len()));
+ return DummyResult::any(sp);
+ }
+
+ let text = match args[0] {
+ TokenTree::Token(_, token::Ident(s, _)) => s.to_string(),
_ => {
cx.span_err(sp, "argument should be a single identifier");
return DummyResult::any(sp);
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+
+const unsafe fn g(x: usize) -> usize {
+ x
+}
+
+fn f(x: usize) -> usize {
+ x
+}
+
+fn main() {
+ let _ = [0; f(2)]; //~ ERROR: non-constant path in constant expression [E0307]
+ let _ = [0; g(2)]; //~ ERROR: non-constant path in constant expression [E0307]
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue-27362.rs
+// ignore-cross-compile
+
+extern crate issue_27362;
+pub use issue_27362 as quux;
+
+// @matches issue_27362/quux/fn.foo.html '//pre' "pub const fn foo()"
+// @matches issue_27362/quux/fn.bar.html '//pre' "pub const unsafe fn bar()"
+// @matches issue_27362/quux/struct.Foo.html '//code' "const unsafe fn baz()"