Skip to content

Commit d428871

Browse files
author
Keegan McAllister
committed
Forbid undefined names in macro use / macro reexport
Fixes #21062.
1 parent a954663 commit d428871

File tree

3 files changed

+80
-26
lines changed

3 files changed

+80
-26
lines changed

src/librustc/plugin/load.rs

+41-26
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use plugin::registry::Registry;
1717
use std::mem;
1818
use std::env;
1919
use std::dynamic_lib::DynamicLibrary;
20-
use std::collections::HashSet;
20+
use std::collections::{HashSet, HashMap};
2121
use std::borrow::ToOwned;
2222
use syntax::ast;
2323
use syntax::attr;
@@ -116,6 +116,8 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,
116116
return loader.plugins;
117117
}
118118

119+
pub type MacroSelection = HashMap<token::InternedString, Span>;
120+
119121
// note that macros aren't expanded yet, and therefore macros can't add plugins.
120122
impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
121123
fn visit_item(&mut self, item: &ast::Item) {
@@ -128,9 +130,9 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
128130
}
129131
}
130132

131-
// Parse the attributes relating to macro / plugin loading.
132-
let mut macro_selection = Some(HashSet::new()); // None => load all
133-
let mut reexport = HashSet::new();
133+
// Parse the attributes relating to macro loading.
134+
let mut import = Some(HashMap::new()); // None => load all
135+
let mut reexport = HashMap::new();
134136
for attr in &item.attrs {
135137
let mut used = true;
136138
match &attr.name()[] {
@@ -147,14 +149,14 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
147149
let names = attr.meta_item_list();
148150
if names.is_none() {
149151
// no names => load all
150-
macro_selection = None;
152+
import = None;
151153
}
152-
if let (Some(sel), Some(names)) = (macro_selection.as_mut(), names) {
153-
for name in names {
154-
if let ast::MetaWord(ref name) = name.node {
155-
sel.insert(name.clone());
154+
if let (Some(sel), Some(names)) = (import.as_mut(), names) {
155+
for attr in names {
156+
if let ast::MetaWord(ref name) = attr.node {
157+
sel.insert(name.clone(), attr.span);
156158
} else {
157-
self.sess.span_err(name.span, "bad macro import");
159+
self.sess.span_err(attr.span, "bad macro import");
158160
}
159161
}
160162
}
@@ -168,11 +170,11 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
168170
}
169171
};
170172

171-
for name in names {
172-
if let ast::MetaWord(ref name) = name.node {
173-
reexport.insert(name.clone());
173+
for attr in names {
174+
if let ast::MetaWord(ref name) = attr.node {
175+
reexport.insert(name.clone(), attr.span);
174176
} else {
175-
self.sess.span_err(name.span, "bad macro reexport");
177+
self.sess.span_err(attr.span, "bad macro reexport");
176178
}
177179
}
178180
}
@@ -183,7 +185,7 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
183185
}
184186
}
185187

186-
self.load_macros(item, macro_selection, Some(reexport))
188+
self.load_macros(item, import, reexport)
187189
}
188190

189191
fn visit_mac(&mut self, _: &ast::Mac) {
@@ -195,10 +197,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
195197
impl<'a> PluginLoader<'a> {
196198
pub fn load_macros<'b>(&mut self,
197199
vi: &ast::Item,
198-
macro_selection: Option<HashSet<token::InternedString>>,
199-
reexport: Option<HashSet<token::InternedString>>) {
200-
if let (Some(sel), Some(re)) = (macro_selection.as_ref(), reexport.as_ref()) {
201-
if sel.is_empty() && re.is_empty() {
200+
import: Option<MacroSelection>,
201+
reexport: MacroSelection) {
202+
if let Some(sel) = import.as_ref() {
203+
if sel.is_empty() && reexport.is_empty() {
202204
return;
203205
}
204206
}
@@ -211,19 +213,32 @@ impl<'a> PluginLoader<'a> {
211213

212214
let pmd = self.reader.read_plugin_metadata(CrateOrString::Krate(vi));
213215

216+
let mut seen = HashSet::new();
214217
for mut def in pmd.exported_macros() {
215218
let name = token::get_ident(def.ident);
216-
def.use_locally = match macro_selection.as_ref() {
219+
seen.insert(name.clone());
220+
221+
def.use_locally = match import.as_ref() {
217222
None => true,
218-
Some(sel) => sel.contains(&name),
219-
};
220-
def.export = if let Some(ref re) = reexport {
221-
re.contains(&name)
222-
} else {
223-
false // Don't reexport macros from crates loaded from the command line
223+
Some(sel) => sel.contains_key(&name),
224224
};
225+
def.export = reexport.contains_key(&name);
225226
self.plugins.macros.push(def);
226227
}
228+
229+
if let Some(sel) = import.as_ref() {
230+
for (name, span) in sel.iter() {
231+
if !seen.contains(name) {
232+
self.sess.span_err(*span, "imported macro not found");
233+
}
234+
}
235+
}
236+
237+
for (name, span) in reexport.iter() {
238+
if !seen.contains(name) {
239+
self.sess.span_err(*span, "reexported macro not found");
240+
}
241+
}
227242
}
228243

229244
pub fn load_plugin<'b>(&mut self,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:two_macros.rs
12+
// ignore-stage1
13+
14+
#[macro_use(macro_two)]
15+
#[macro_reexport(no_way)] //~ ERROR reexported macro not found
16+
extern crate two_macros;
17+
18+
pub fn main() {
19+
macro_two!();
20+
}
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:two_macros.rs
12+
// ignore-stage1
13+
14+
#[macro_use(macro_two, no_way)] //~ ERROR imported macro not found
15+
extern crate two_macros;
16+
17+
pub fn main() {
18+
macro_two!();
19+
}

0 commit comments

Comments
 (0)