Skip to content

Commit 880f03b

Browse files
authored
Rollup merge of rust-lang#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
2 parents 8c4f2c6 + 678e882 commit 880f03b

File tree

6 files changed

+45
-20
lines changed

6 files changed

+45
-20
lines changed

src/librustc/hir/def.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use hir::def_id::DefId;
1212
use util::nodemap::NodeMap;
1313
use syntax::ast;
1414
use syntax::ext::base::MacroKind;
15+
use syntax_pos::Span;
1516
use hir;
1617

1718
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
@@ -116,6 +117,7 @@ pub type ExportMap = NodeMap<Vec<Export>>;
116117
pub struct Export {
117118
pub name: ast::Name, // The name of the target.
118119
pub def: Def, // The definition of the target.
120+
pub span: Span, // The span of the target definition.
119121
}
120122

121123
impl CtorKind {

src/librustc_metadata/decoder.rs

+6-13
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ impl<'a, 'tcx> CrateMetadata {
683683
},
684684
ext.kind()
685685
);
686-
callback(def::Export { name: name, def: def });
686+
callback(def::Export { name: name, def: def, span: DUMMY_SP });
687687
}
688688
}
689689
return
@@ -720,6 +720,7 @@ impl<'a, 'tcx> CrateMetadata {
720720
callback(def::Export {
721721
def: def,
722722
name: self.item_name(child_index),
723+
span: self.entry(child_index).span.decode(self),
723724
});
724725
}
725726
}
@@ -732,34 +733,26 @@ impl<'a, 'tcx> CrateMetadata {
732733
}
733734

734735
let def_key = self.def_key(child_index);
736+
let span = child.span.decode(self);
735737
if let (Some(def), Some(name)) =
736738
(self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) {
737-
callback(def::Export {
738-
def: def,
739-
name: name,
740-
});
739+
callback(def::Export { def: def, name: name, span: span });
741740
// For non-reexport structs and variants add their constructors to children.
742741
// Reexport lists automatically contain constructors when necessary.
743742
match def {
744743
Def::Struct(..) => {
745744
if let Some(ctor_def_id) = self.get_struct_ctor_def_id(child_index) {
746745
let ctor_kind = self.get_ctor_kind(child_index);
747746
let ctor_def = Def::StructCtor(ctor_def_id, ctor_kind);
748-
callback(def::Export {
749-
def: ctor_def,
750-
name: name,
751-
});
747+
callback(def::Export { def: ctor_def, name: name, span: span });
752748
}
753749
}
754750
Def::Variant(def_id) => {
755751
// Braced variants, unlike structs, generate unusable names in
756752
// value namespace, they are reserved for possible future use.
757753
let ctor_kind = self.get_ctor_kind(child_index);
758754
let ctor_def = Def::VariantCtor(def_id, ctor_kind);
759-
callback(def::Export {
760-
def: ctor_def,
761-
name: name,
762-
});
755+
callback(def::Export { def: ctor_def, name: name, span: span });
763756
}
764757
_ => {}
765758
}

src/librustc_resolve/build_reduced_graph.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ impl<'a> Resolver<'a> {
605605
let ident = Ident::with_empty_ctxt(name);
606606
let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None);
607607
if let Ok(binding) = result {
608-
self.macro_exports.push(Export { name: name, def: binding.def() });
608+
self.macro_exports.push(Export { name: name, def: binding.def(), span: span });
609609
} else {
610610
span_err!(self.session, span, E0470, "reexported macro not found");
611611
}

src/librustc_resolve/macros.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ impl<'a> Resolver<'a> {
653653

654654
if attr::contains_name(&item.attrs, "macro_export") {
655655
let def = Def::Macro(def_id, MacroKind::Bang);
656-
self.macro_exports.push(Export { name: ident.name, def: def });
656+
self.macro_exports.push(Export { name: ident.name, def: def, span: item.span });
657657
}
658658
}
659659

src/librustc_resolve/resolve_imports.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc::ty;
2121
use rustc::lint::builtin::PRIVATE_IN_PUBLIC;
2222
use rustc::hir::def_id::DefId;
2323
use rustc::hir::def::*;
24-
use rustc::util::nodemap::FxHashSet;
24+
use rustc::util::nodemap::FxHashMap;
2525

2626
use syntax::ast::{Ident, NodeId};
2727
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
@@ -763,10 +763,11 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
763763
*module.globs.borrow_mut() = Vec::new();
764764

765765
let mut reexports = Vec::new();
766+
let mut exported_macro_names = FxHashMap();
766767
if module as *const _ == self.graph_root as *const _ {
767-
let mut exported_macro_names = FxHashSet();
768-
for export in mem::replace(&mut self.macro_exports, Vec::new()).into_iter().rev() {
769-
if exported_macro_names.insert(export.name) {
768+
let macro_exports = mem::replace(&mut self.macro_exports, Vec::new());
769+
for export in macro_exports.into_iter().rev() {
770+
if exported_macro_names.insert(export.name, export.span).is_none() {
770771
reexports.push(export);
771772
}
772773
}
@@ -786,7 +787,17 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
786787
if !def.def_id().is_local() {
787788
self.session.cstore.export_macros(def.def_id().krate);
788789
}
789-
reexports.push(Export { name: ident.name, def: def });
790+
if let Def::Macro(..) = def {
791+
if let Some(&span) = exported_macro_names.get(&ident.name) {
792+
let msg =
793+
format!("a macro named `{}` has already been exported", ident);
794+
self.session.struct_span_err(span, &msg)
795+
.span_label(span, &format!("`{}` already exported", ident))
796+
.span_note(binding.span, "previous macro export here")
797+
.emit();
798+
}
799+
}
800+
reexports.push(Export { name: ident.name, def: def, span: binding.span });
790801
}
791802
}
792803

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2017 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+
#![feature(use_extern_macros)]
12+
13+
pub use std::panic; //~ NOTE previous macro export here
14+
15+
#[macro_export]
16+
macro_rules! panic { () => {} } //~ ERROR a macro named `panic` has already been exported
17+
//~| NOTE `panic` already exported
18+
19+
fn main() {}

0 commit comments

Comments
 (0)