Skip to content

Commit a3126a5

Browse files
committed
resolve: Introduce a new scope for derive helpers
1 parent c064630 commit a3126a5

File tree

5 files changed

+78
-13
lines changed

5 files changed

+78
-13
lines changed

src/librustc_resolve/diagnostics.rs

+9
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,15 @@ impl<'a> Resolver<'a> {
368368
let mut suggestions = Vec::new();
369369
self.visit_scopes(scope_set, parent_scope, ident, |this, scope, use_prelude, _| {
370370
match scope {
371+
Scope::DeriveHelpers(expn_id) => {
372+
let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
373+
if filter_fn(res) {
374+
suggestions.extend(this.helper_attrs.get(&expn_id)
375+
.into_iter().flatten().map(|ident| {
376+
TypoSuggestion::from_res(ident.name, res)
377+
}));
378+
}
379+
}
371380
Scope::DeriveHelpersCompat => {
372381
let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
373382
if filter_fn(res) {

src/librustc_resolve/lib.rs

+24-6
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use syntax::symbol::{kw, sym};
4545
use syntax::source_map::Spanned;
4646
use syntax::visit::{self, Visitor};
4747
use syntax_expand::base::SyntaxExtension;
48-
use syntax_pos::hygiene::{MacroKind, ExpnId, Transparency, SyntaxContext};
48+
use syntax_pos::hygiene::{MacroKind, ExpnId, ExpnKind, Transparency, SyntaxContext};
4949
use syntax_pos::{Span, DUMMY_SP};
5050
use errors::{Applicability, DiagnosticBuilder};
5151

@@ -97,6 +97,7 @@ impl Determinacy {
9797
/// but not for late resolution yet.
9898
#[derive(Clone, Copy)]
9999
enum Scope<'a> {
100+
DeriveHelpers(ExpnId),
100101
DeriveHelpersCompat,
101102
MacroRules(LegacyScope<'a>),
102103
CrateRoot,
@@ -942,6 +943,8 @@ pub struct Resolver<'a> {
942943
/// Legacy scopes *produced* by expanding the macro invocations,
943944
/// include all the `macro_rules` items and other invocations generated by them.
944945
output_legacy_scopes: FxHashMap<ExpnId, LegacyScope<'a>>,
946+
/// Helper attributes that are in scope for the given expansion.
947+
helper_attrs: FxHashMap<ExpnId, Vec<Ident>>,
945948

946949
/// Avoid duplicated errors for "name already defined".
947950
name_already_seen: FxHashMap<Name, Span>,
@@ -1219,6 +1222,7 @@ impl<'a> Resolver<'a> {
12191222
non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
12201223
invocation_parent_scopes,
12211224
output_legacy_scopes: Default::default(),
1225+
helper_attrs: Default::default(),
12221226
macro_defs,
12231227
local_macro_def_scopes: FxHashMap::default(),
12241228
name_already_seen: FxHashMap::default(),
@@ -1467,23 +1471,26 @@ impl<'a> Resolver<'a> {
14671471
// in prelude, not sure where exactly (creates ambiguities with any other prelude names).
14681472

14691473
let rust_2015 = ident.span.rust_2015();
1470-
let (ns, is_absolute_path) = match scope_set {
1471-
ScopeSet::All(ns, _) => (ns, false),
1472-
ScopeSet::AbsolutePath(ns) => (ns, true),
1473-
ScopeSet::Macro(_) => (MacroNS, false),
1474+
let (ns, macro_kind, is_absolute_path) = match scope_set {
1475+
ScopeSet::All(ns, _) => (ns, None, false),
1476+
ScopeSet::AbsolutePath(ns) => (ns, None, true),
1477+
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
14741478
};
14751479
// Jump out of trait or enum modules, they do not act as scopes.
14761480
let module = parent_scope.module.nearest_item_scope();
14771481
let mut scope = match ns {
14781482
_ if is_absolute_path => Scope::CrateRoot,
14791483
TypeNS | ValueNS => Scope::Module(module),
1480-
MacroNS => Scope::DeriveHelpersCompat,
1484+
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
14811485
};
14821486
let mut ident = ident.modern();
14831487
let mut use_prelude = !module.no_implicit_prelude;
14841488

14851489
loop {
14861490
let visit = match scope {
1491+
// Derive helpers are not in scope when resolving derives in the same container.
1492+
Scope::DeriveHelpers(expn_id) =>
1493+
!(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive)),
14871494
Scope::DeriveHelpersCompat => true,
14881495
Scope::MacroRules(..) => true,
14891496
Scope::CrateRoot => true,
@@ -1505,6 +1512,17 @@ impl<'a> Resolver<'a> {
15051512
}
15061513

15071514
scope = match scope {
1515+
Scope::DeriveHelpers(expn_id) if expn_id != ExpnId::root() => {
1516+
// Derive helpers are not visible to code generated by bang or derive macros.
1517+
let expn_data = expn_id.expn_data();
1518+
match expn_data.kind {
1519+
ExpnKind::Root |
1520+
ExpnKind::Macro(MacroKind::Bang, _) |
1521+
ExpnKind::Macro(MacroKind::Derive, _) => Scope::DeriveHelpersCompat,
1522+
_ => Scope::DeriveHelpers(expn_data.parent),
1523+
}
1524+
}
1525+
Scope::DeriveHelpers(..) => Scope::DeriveHelpersCompat,
15081526
Scope::DeriveHelpersCompat =>
15091527
Scope::MacroRules(parent_scope.legacy),
15101528
Scope::MacroRules(legacy_scope) => match legacy_scope {

src/librustc_resolve/macros.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,23 @@ impl<'a> base::Resolver for Resolver<'a> {
237237
// - Derives in the container need to know whether one of them is a built-in `Copy`.
238238
// FIXME: Try to avoid repeated resolutions for derives here and in expansion.
239239
let mut exts = Vec::new();
240+
let mut helper_attrs = Vec::new();
240241
for path in derives {
241242
exts.push(match self.resolve_macro_path(
242243
path, Some(MacroKind::Derive), &parent_scope, true, force
243244
) {
244-
Ok((Some(ext), _)) => ext,
245+
Ok((Some(ext), _)) => {
246+
let span = path.segments.last().unwrap().ident.span.modern();
247+
helper_attrs.extend(
248+
ext.helper_attrs.iter().map(|name| Ident::new(*name, span))
249+
);
250+
ext
251+
}
245252
Ok(_) | Err(Determinacy::Determined) => self.dummy_ext(MacroKind::Derive),
246253
Err(Determinacy::Undetermined) => return Err(Indeterminate),
247254
})
248255
}
256+
self.helper_attrs.insert(invoc_id, helper_attrs);
249257
return Ok(InvocationRes::DeriveContainer(exts));
250258
}
251259
};
@@ -498,6 +506,18 @@ impl<'a> Resolver<'a> {
498506
Flags::empty(),
499507
));
500508
let result = match scope {
509+
Scope::DeriveHelpers(expn_id) => {
510+
if let Some(attr) = this.helper_attrs.get(&expn_id).and_then(|attrs| {
511+
attrs.iter().rfind(|i| ident == **i)
512+
}) {
513+
let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
514+
ty::Visibility::Public, attr.span, expn_id)
515+
.to_name_binding(this.arenas);
516+
Ok((binding, Flags::empty()))
517+
} else {
518+
Err(Determinacy::Determined)
519+
}
520+
}
501521
Scope::DeriveHelpersCompat => {
502522
let mut result = Err(Determinacy::Determined);
503523
for derive in parent_scope.derives {

src/test/ui/proc-macro/derive-helper-shadowing.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// edition:2018
12
// aux-build:test-macros.rs
23

34
#[macro_use]
@@ -11,8 +12,7 @@ struct S {
1112
// FIXME No ambiguity, attributes in non-macro positions are not resolved properly
1213
#[empty_helper]
1314
field: [u8; {
14-
// FIXME No ambiguity, derive helpers are not put into scope for non-attributes
15-
use empty_helper;
15+
use empty_helper; //~ ERROR `empty_helper` is ambiguous
1616

1717
// FIXME No ambiguity, derive helpers are not put into scope for inner items
1818
#[empty_helper]
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,39 @@
1+
error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution)
2+
--> $DIR/derive-helper-shadowing.rs:15:13
3+
|
4+
LL | use empty_helper;
5+
| ^^^^^^^^^^^^ ambiguous name
6+
|
7+
note: `empty_helper` could refer to the derive helper attribute defined here
8+
--> $DIR/derive-helper-shadowing.rs:10:10
9+
|
10+
LL | #[derive(Empty)]
11+
| ^^^^^
12+
note: `empty_helper` could also refer to the attribute macro imported here
13+
--> $DIR/derive-helper-shadowing.rs:7:5
14+
|
15+
LL | use test_macros::empty_attr as empty_helper;
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
= help: use `crate::empty_helper` to refer to this attribute macro unambiguously
18+
119
error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
2-
--> $DIR/derive-helper-shadowing.rs:8:3
20+
--> $DIR/derive-helper-shadowing.rs:9:3
321
|
422
LL | #[empty_helper]
523
| ^^^^^^^^^^^^ ambiguous name
624
|
725
note: `empty_helper` could refer to the derive helper attribute defined here
8-
--> $DIR/derive-helper-shadowing.rs:9:10
26+
--> $DIR/derive-helper-shadowing.rs:10:10
927
|
1028
LL | #[derive(Empty)]
1129
| ^^^^^
1230
note: `empty_helper` could also refer to the attribute macro imported here
13-
--> $DIR/derive-helper-shadowing.rs:6:5
31+
--> $DIR/derive-helper-shadowing.rs:7:5
1432
|
1533
LL | use test_macros::empty_attr as empty_helper;
1634
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1735
= help: use `crate::empty_helper` to refer to this attribute macro unambiguously
1836

19-
error: aborting due to previous error
37+
error: aborting due to 2 previous errors
2038

2139
For more information about this error, try `rustc --explain E0659`.

0 commit comments

Comments
 (0)