Skip to content

Turn extern crate and use into first-class items. #20179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jan 22, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 9 additions & 23 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
@@ -803,8 +803,9 @@ Crates contain [items](#items), each of which may have some number of
## Items

```{.ebnf .gram}
item : mod_item | fn_item | type_item | struct_item | enum_item
| static_item | trait_item | impl_item | extern_block ;
item : extern_crate_decl | use_decl | mod_item | fn_item | type_item
| struct_item | enum_item | static_item | trait_item | impl_item
| extern_block ;
```

An _item_ is a component of a crate; some module items can be defined in crate
@@ -818,6 +819,8 @@ execution, and may reside in read-only memory.

There are several kinds of item:

* [`extern crate` declarations](#extern-crate-declarations)
* [`use` declarations](#use-declarations)
* [modules](#modules)
* [functions](#functions)
* [type definitions](#type-definitions)
@@ -854,13 +857,10 @@ no notion of type abstraction: there are no first-class "forall" types.

```{.ebnf .gram}
mod_item : "mod" ident ( ';' | '{' mod '}' );
mod : [ view_item | item ] * ;
mod : item * ;
```

A module is a container for zero or more [view items](#view-items) and zero or
more [items](#items). The view items manage the visibility of the items defined
within the module, as well as the visibility of names from outside the module
when referenced from inside the module.
A module is a container for zero or more [items](#items).

A _module item_ is a module, surrounded in braces, named, and prefixed with the
keyword `mod`. A module item introduces a new, named module into the tree of
@@ -918,19 +918,6 @@ mod thread {
}
```

#### View items

```{.ebnf .gram}
view_item : extern_crate_decl | use_decl ;
```

A view item manages the namespace of a module. View items do not define new
items, but rather, simply change other items' visibility. There are two
kinds of view items:

* [`extern crate` declarations](#extern-crate-declarations)
* [`use` declarations](#use-declarations)

##### Extern crate declarations

```{.ebnf .gram}
@@ -2891,13 +2878,12 @@ Point3d {y: 0, z: 10, .. base};
### Block expressions

```{.ebnf .gram}
block_expr : '{' [ view_item ] *
[ stmt ';' | item ] *
block_expr : '{' [ stmt ';' | item ] *
[ expr ] '}' ;
```

A _block expression_ is similar to a module in terms of the declarations that
are possible. Each block conceptually introduces a new namespace scope. View
are possible. Each block conceptually introduces a new namespace scope. Use
items can bring new names into scopes and declared items are in scope for only
the block itself.

1 change: 1 addition & 0 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -52,6 +52,7 @@ register_diagnostics! {
E0140,
E0152,
E0153,
E0154,
E0157,
E0158,
E0161,
37 changes: 16 additions & 21 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
@@ -1202,17 +1202,17 @@ impl LintPass for UnusedImportBraces {
lint_array!(UNUSED_IMPORT_BRACES)
}

fn check_view_item(&mut self, cx: &Context, view_item: &ast::ViewItem) {
match view_item.node {
ast::ViewItemUse(ref view_path) => {
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
match item.node {
ast::ItemUse(ref view_path) => {
match view_path.node {
ast::ViewPathList(_, ref items, _) => {
ast::ViewPathList(_, ref items) => {
if items.len() == 1 {
match items[0].node {
ast::PathListIdent {ref name, ..} => {
let m = format!("braces around {} is unnecessary",
token::get_ident(*name).get());
cx.span_lint(UNUSED_IMPORT_BRACES, view_item.span,
cx.span_lint(UNUSED_IMPORT_BRACES, item.span,
&m[]);
},
_ => ()
@@ -1709,22 +1709,6 @@ impl LintPass for Stability {
}
}

fn check_view_item(&mut self, cx: &Context, item: &ast::ViewItem) {
// compiler-generated `extern crate` statements have a dummy span.
if item.span == DUMMY_SP { return }

let id = match item.node {
ast::ViewItemExternCrate(_, _, id) => id,
ast::ViewItemUse(..) => return,
};
let cnum = match cx.tcx.sess.cstore.find_extern_mod_stmt_cnum(id) {
Some(cnum) => cnum,
None => return,
};
let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID };
self.lint(cx, id, item.span);
}

fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
if self.is_internal(cx, e.span) { return; }

@@ -1776,6 +1760,17 @@ impl LintPass for Stability {
if self.is_internal(cx, item.span) { return }

match item.node {
ast::ItemExternCrate(_) => {
// compiler-generated `extern crate` items have a dummy span.
if item.span == DUMMY_SP { return }

let cnum = match cx.tcx.sess.cstore.find_extern_mod_stmt_cnum(item.id) {
Some(cnum) => cnum,
None => return,
};
let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID };
self.lint(cx, id, item.span);
}
ast::ItemTrait(_, _, ref supertraits, _) => {
for t in supertraits.iter() {
if let ast::TraitTyParamBound(ref t, _) = *t {
8 changes: 0 additions & 8 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
@@ -603,14 +603,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
})
}

fn visit_view_item(&mut self, i: &ast::ViewItem) {
self.with_lint_attrs(&i.attrs[], |cx| {
run_lints!(cx, check_view_item, i);
cx.visit_ids(|v| v.visit_view_item(i));
visit::walk_view_item(cx, i);
})
}

fn visit_pat(&mut self, p: &ast::Pat) {
run_lints!(self, check_pat, p);
visit::walk_pat(self, p);
1 change: 0 additions & 1 deletion src/librustc/lint/mod.rs
Original file line number Diff line number Diff line change
@@ -128,7 +128,6 @@ pub trait LintPass {
fn check_crate(&mut self, _: &Context, _: &ast::Crate) { }
fn check_ident(&mut self, _: &Context, _: Span, _: ast::Ident) { }
fn check_mod(&mut self, _: &Context, _: &ast::Mod, _: Span, _: ast::NodeId) { }
fn check_view_item(&mut self, _: &Context, _: &ast::ViewItem) { }
fn check_foreign_item(&mut self, _: &Context, _: &ast::ForeignItem) { }
fn check_item(&mut self, _: &Context, _: &ast::Item) { }
fn check_local(&mut self, _: &Context, _: &ast::Local) { }
56 changes: 25 additions & 31 deletions src/librustc/metadata/creader.rs
Original file line number Diff line number Diff line change
@@ -40,10 +40,6 @@ pub struct CrateReader<'a> {
}

impl<'a, 'v> visit::Visitor<'v> for CrateReader<'a> {
fn visit_view_item(&mut self, a: &ast::ViewItem) {
self.process_view_item(a);
visit::walk_view_item(self, a);
}
fn visit_item(&mut self, a: &ast::Item) {
self.process_item(a);
visit::walk_item(self, a);
@@ -64,9 +60,8 @@ fn dump_crates(cstore: &CStore) {
})
}

fn should_link(i: &ast::ViewItem) -> bool {
fn should_link(i: &ast::Item) -> bool {
!attr::contains_name(&i.attrs[], "no_link")

}

struct CrateInfo {
@@ -181,29 +176,10 @@ impl<'a> CrateReader<'a> {
}
}

fn process_view_item(&mut self, i: &ast::ViewItem) {
if !should_link(i) {
return;
}

match self.extract_crate_info(i) {
Some(info) => {
let (cnum, _, _) = self.resolve_crate(&None,
&info.ident[],
&info.name[],
None,
i.span,
PathKind::Crate);
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
}
None => ()
}
}

fn extract_crate_info(&self, i: &ast::ViewItem) -> Option<CrateInfo> {
fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> {
match i.node {
ast::ViewItemExternCrate(ident, ref path_opt, id) => {
let ident = token::get_ident(ident);
ast::ItemExternCrate(ref path_opt) => {
let ident = token::get_ident(i.ident);
debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
ident, path_opt);
let name = match *path_opt {
@@ -218,16 +194,34 @@ impl<'a> CrateReader<'a> {
Some(CrateInfo {
ident: ident.get().to_string(),
name: name,
id: id,
id: i.id,
should_link: should_link(i),
})
}
_ => None
}
}

fn process_item(&self, i: &ast::Item) {
fn process_item(&mut self, i: &ast::Item) {
match i.node {
ast::ItemExternCrate(_) => {
if !should_link(i) {
return;
}

match self.extract_crate_info(i) {
Some(info) => {
let (cnum, _, _) = self.resolve_crate(&None,
&info.ident[],
&info.name[],
None,
i.span,
PathKind::Crate);
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
}
None => ()
}
}
ast::ItemForeignMod(ref fm) => {
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
return;
@@ -533,7 +527,7 @@ impl<'a> CrateReader<'a> {

#[derive(Copy)]
pub enum CrateOrString<'a> {
Krate(&'a ast::ViewItem),
Krate(&'a ast::Item),
Str(&'a str)
}

4 changes: 2 additions & 2 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
@@ -1456,8 +1456,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
rbml_w.end_tag();
}
}
ast::ItemMac(..) => {
// macros are encoded separately
ast::ItemExternCrate(_) | ast::ItemUse(_) |ast::ItemMac(..) => {
// these are encoded separately
}
}
}
2 changes: 0 additions & 2 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
@@ -332,8 +332,6 @@ impl Folder for NestedItemsDropper {
}
}).collect();
let blk_sans_items = P(ast::Block {
view_items: Vec::new(), // I don't know if we need the view_items
// here, but it doesn't break tests!
stmts: stmts_sans_items,
expr: expr,
id: id,
1 change: 1 addition & 0 deletions src/librustc/middle/reachable.rs
Original file line number Diff line number Diff line change
@@ -297,6 +297,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
// These are normal, nothing reachable about these
// inherently and their children are already in the
// worklist, as determined by the privacy pass
ast::ItemExternCrate(_) | ast::ItemUse(_) |
ast::ItemTy(..) | ast::ItemStatic(_, _, _) |
ast::ItemMod(..) | ast::ItemForeignMod(..) |
ast::ItemImpl(..) | ast::ItemTrait(..) |
2 changes: 2 additions & 0 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
@@ -94,6 +94,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
// Fn lifetimes get added in visit_fn below:
visit::walk_item(this, item);
}
ast::ItemExternCrate(_) |
ast::ItemUse(_) |
ast::ItemMod(..) |
ast::ItemMac(..) |
ast::ItemForeignMod(..) |
24 changes: 16 additions & 8 deletions src/librustc/plugin/load.rs
Original file line number Diff line number Diff line change
@@ -73,8 +73,10 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,
// We need to error on `#[macro_use] extern crate` when it isn't at the
// crate root, because `$crate` won't work properly. Identify these by
// spans, because the crate map isn't set up yet.
for vi in krate.module.view_items.iter() {
loader.span_whitelist.insert(vi.span);
for item in krate.module.items.iter() {
if let ast::ItemExternCrate(_) = item.node {
loader.span_whitelist.insert(item.span);
}
}

visit::walk_crate(&mut loader, krate);
@@ -91,18 +93,21 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,

// note that macros aren't expanded yet, and therefore macros can't add plugins.
impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
fn visit_view_item(&mut self, vi: &ast::ViewItem) {
fn visit_item(&mut self, item: &ast::Item) {
// We're only interested in `extern crate`.
match vi.node {
ast::ViewItemExternCrate(..) => (),
_ => return,
match item.node {
ast::ItemExternCrate(_) => {}
_ => {
visit::walk_item(self, item);
return;
}
}

// Parse the attributes relating to macro / plugin loading.
let mut plugin_attr = None;
let mut macro_selection = Some(HashSet::new()); // None => load all
let mut reexport = HashSet::new();
for attr in vi.attrs.iter() {
for attr in item.attrs.iter() {
let mut used = true;
match attr.name().get() {
"phase" => {
@@ -155,7 +160,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
}
}

self.load_plugin(CrateOrString::Krate(vi), plugin_attr, macro_selection, Some(reexport))
self.load_plugin(CrateOrString::Krate(item),
plugin_attr,
macro_selection,
Some(reexport))
}

fn visit_mac(&mut self, _: &ast::Mac) {
14 changes: 0 additions & 14 deletions src/librustc_back/svh.rs
Original file line number Diff line number Diff line change
@@ -188,7 +188,6 @@ mod svh_visitor {
SawLifetimeDef(token::InternedString),

SawMod,
SawViewItem,
SawForeignItem,
SawItem,
SawDecl,
@@ -436,19 +435,6 @@ mod svh_visitor {
SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s)
}

fn visit_view_item(&mut self, i: &ViewItem) {
// Two kinds of view items can affect the ABI for a crate:
// exported `pub use` view items (since that may expose
// items that downstream crates can call), and `use
// foo::Trait`, since changing that may affect method
// resolution.
//
// The simplest approach to handling both of the above is
// just to adopt the same simple-minded (fine-grained)
// hash that I am deploying elsewhere here.
SawViewItem.hash(self.st); visit::walk_view_item(self, i)
}

fn visit_foreign_item(&mut self, i: &ForeignItem) {
// FIXME (#14132) ideally we would incorporate privacy (or
// perhaps reachability) somewhere here, so foreign items
2 changes: 1 addition & 1 deletion src/librustc_driver/pretty.rs
Original file line number Diff line number Diff line change
@@ -477,7 +477,7 @@ impl fold::Folder for ReplaceBodyWithLoop {
e: Option<P<ast::Expr>>) -> P<ast::Block> {
P(ast::Block {
expr: e,
view_items: vec![], stmts: vec![], rules: rules,
stmts: vec![], rules: rules,
id: ast::DUMMY_NODE_ID, span: codemap::DUMMY_SP,
})
}
Loading