Rollup merge of #40509 - jseyfried:duplicate_check_macro_exports, r=nrc
Forbid conflicts between macros 1.0 exports and macros 2.0 exports This PR forbids for conflicts between `#[macro_export]`/`#[macro_reexport]` macro exports and `pub use` macro exports. For example, ```rust // crate A: pub use macros::foo; //^ This is allowed today, will be forbidden by this PR. // crate B: extern crate A; // This triggers a confusing error today. use A::foo; // This could refer to refer to either macro export in crate A. ``` r? @nrc
This commit is contained in:
commit
880f03b28c
6 changed files with 45 additions and 20 deletions
|
@ -12,6 +12,7 @@ use hir::def_id::DefId;
|
|||
use util::nodemap::NodeMap;
|
||||
use syntax::ast;
|
||||
use syntax::ext::base::MacroKind;
|
||||
use syntax_pos::Span;
|
||||
use hir;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
|
@ -116,6 +117,7 @@ pub type ExportMap = NodeMap<Vec<Export>>;
|
|||
pub struct Export {
|
||||
pub name: ast::Name, // The name of the target.
|
||||
pub def: Def, // The definition of the target.
|
||||
pub span: Span, // The span of the target definition.
|
||||
}
|
||||
|
||||
impl CtorKind {
|
||||
|
|
|
@ -683,7 +683,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
},
|
||||
ext.kind()
|
||||
);
|
||||
callback(def::Export { name: name, def: def });
|
||||
callback(def::Export { name: name, def: def, span: DUMMY_SP });
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -720,6 +720,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
callback(def::Export {
|
||||
def: def,
|
||||
name: self.item_name(child_index),
|
||||
span: self.entry(child_index).span.decode(self),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -732,12 +733,10 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
}
|
||||
|
||||
let def_key = self.def_key(child_index);
|
||||
let span = child.span.decode(self);
|
||||
if let (Some(def), Some(name)) =
|
||||
(self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) {
|
||||
callback(def::Export {
|
||||
def: def,
|
||||
name: name,
|
||||
});
|
||||
callback(def::Export { def: def, name: name, span: span });
|
||||
// For non-reexport structs and variants add their constructors to children.
|
||||
// Reexport lists automatically contain constructors when necessary.
|
||||
match def {
|
||||
|
@ -745,10 +744,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
if let Some(ctor_def_id) = self.get_struct_ctor_def_id(child_index) {
|
||||
let ctor_kind = self.get_ctor_kind(child_index);
|
||||
let ctor_def = Def::StructCtor(ctor_def_id, ctor_kind);
|
||||
callback(def::Export {
|
||||
def: ctor_def,
|
||||
name: name,
|
||||
});
|
||||
callback(def::Export { def: ctor_def, name: name, span: span });
|
||||
}
|
||||
}
|
||||
Def::Variant(def_id) => {
|
||||
|
@ -756,10 +752,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
// value namespace, they are reserved for possible future use.
|
||||
let ctor_kind = self.get_ctor_kind(child_index);
|
||||
let ctor_def = Def::VariantCtor(def_id, ctor_kind);
|
||||
callback(def::Export {
|
||||
def: ctor_def,
|
||||
name: name,
|
||||
});
|
||||
callback(def::Export { def: ctor_def, name: name, span: span });
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -605,7 +605,7 @@ impl<'a> Resolver<'a> {
|
|||
let ident = Ident::with_empty_ctxt(name);
|
||||
let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None);
|
||||
if let Ok(binding) = result {
|
||||
self.macro_exports.push(Export { name: name, def: binding.def() });
|
||||
self.macro_exports.push(Export { name: name, def: binding.def(), span: span });
|
||||
} else {
|
||||
span_err!(self.session, span, E0470, "reexported macro not found");
|
||||
}
|
||||
|
|
|
@ -653,7 +653,7 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
if attr::contains_name(&item.attrs, "macro_export") {
|
||||
let def = Def::Macro(def_id, MacroKind::Bang);
|
||||
self.macro_exports.push(Export { name: ident.name, def: def });
|
||||
self.macro_exports.push(Export { name: ident.name, def: def, span: item.span });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ use rustc::ty;
|
|||
use rustc::lint::builtin::PRIVATE_IN_PUBLIC;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::def::*;
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
|
||||
use syntax::ast::{Ident, NodeId};
|
||||
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
|
||||
|
@ -763,10 +763,11 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
|||
*module.globs.borrow_mut() = Vec::new();
|
||||
|
||||
let mut reexports = Vec::new();
|
||||
let mut exported_macro_names = FxHashMap();
|
||||
if module as *const _ == self.graph_root as *const _ {
|
||||
let mut exported_macro_names = FxHashSet();
|
||||
for export in mem::replace(&mut self.macro_exports, Vec::new()).into_iter().rev() {
|
||||
if exported_macro_names.insert(export.name) {
|
||||
let macro_exports = mem::replace(&mut self.macro_exports, Vec::new());
|
||||
for export in macro_exports.into_iter().rev() {
|
||||
if exported_macro_names.insert(export.name, export.span).is_none() {
|
||||
reexports.push(export);
|
||||
}
|
||||
}
|
||||
|
@ -786,7 +787,17 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
|||
if !def.def_id().is_local() {
|
||||
self.session.cstore.export_macros(def.def_id().krate);
|
||||
}
|
||||
reexports.push(Export { name: ident.name, def: def });
|
||||
if let Def::Macro(..) = def {
|
||||
if let Some(&span) = exported_macro_names.get(&ident.name) {
|
||||
let msg =
|
||||
format!("a macro named `{}` has already been exported", ident);
|
||||
self.session.struct_span_err(span, &msg)
|
||||
.span_label(span, &format!("`{}` already exported", ident))
|
||||
.span_note(binding.span, "previous macro export here")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
reexports.push(Export { name: ident.name, def: def, span: binding.span });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
19
src/test/compile-fail/duplicate-check-macro-exports.rs
Normal file
19
src/test/compile-fail/duplicate-check-macro-exports.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2017 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(use_extern_macros)]
|
||||
|
||||
pub use std::panic; //~ NOTE previous macro export here
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! panic { () => {} } //~ ERROR a macro named `panic` has already been exported
|
||||
//~| NOTE `panic` already exported
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Reference in a new issue