Skip to content

Commit

Permalink
Forbid '#[macro_use] extern crate' outside the crate root
Browse files Browse the repository at this point in the history
  • Loading branch information
Keegan McAllister committed Jan 6, 2015
1 parent c2e2697 commit bbbb85a
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 3 deletions.
16 changes: 16 additions & 0 deletions src/librustc/plugin/load.rs
Expand Up @@ -20,6 +20,7 @@ use std::dynamic_lib::DynamicLibrary;
use std::collections::HashSet;
use syntax::ast;
use syntax::attr;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ptr::P;
use syntax::visit;
Expand All @@ -45,6 +46,7 @@ pub struct Plugins {

struct PluginLoader<'a> {
sess: &'a Session,
span_whitelist: HashSet<Span>,
reader: CrateReader<'a>,
plugins: Plugins,
}
Expand All @@ -54,6 +56,7 @@ impl<'a> PluginLoader<'a> {
PluginLoader {
sess: sess,
reader: CrateReader::new(sess),
span_whitelist: HashSet::new(),
plugins: Plugins {
macros: vec!(),
registrars: vec!(),
Expand All @@ -66,6 +69,14 @@ impl<'a> PluginLoader<'a> {
pub fn load_plugins(sess: &Session, krate: &ast::Crate,
addl_plugins: Option<Plugins>) -> Plugins {
let mut loader = PluginLoader::new(sess);

// 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);
}

visit::walk_crate(&mut loader, krate);

let mut plugins = loader.plugins;
Expand Down Expand Up @@ -158,6 +169,11 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
};
let load_registrar = plugin_attr.is_some();

if load_macros && !self.span_whitelist.contains(&vi.span) {
self.sess.span_err(vi.span, "an `extern crate` loading macros must be at \
the crate root");
}

if load_macros || load_registrar {
let pmd = self.reader.read_plugin_metadata(vi);
if load_macros {
Expand Down
7 changes: 4 additions & 3 deletions src/test/compile-fail/lint-stability.rs
Expand Up @@ -19,13 +19,14 @@
#![deny(experimental)]
#![allow(dead_code)]

#[macro_use]
extern crate lint_stability; //~ ERROR: use of unmarked item

mod cross_crate {
extern crate stability_cfg1;
extern crate stability_cfg2; //~ ERROR: use of experimental item

#[macro_use]
extern crate lint_stability; //~ ERROR: use of unmarked item
use self::lint_stability::*;
use lint_stability::*;

fn test() {
let foo = MethodTester;
Expand Down
20 changes: 20 additions & 0 deletions src/test/compile-fail/macro-crate-nonterminal-non-root.rs
@@ -0,0 +1,20 @@
// 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:macro_crate_nonterminal.rs
// ignore-stage1

mod foo {
#[macro_use]
extern crate macro_crate_nonterminal; //~ ERROR must be at the crate root
}

fn main() {
}

0 comments on commit bbbb85a

Please sign in to comment.