Skip to content

Commit 8dad6d8

Browse files
committed
resolve: Future proof resolutions for potentially built-in attributes
1 parent 3f2df20 commit 8dad6d8

7 files changed

+239
-1
lines changed

src/librustc_resolve/build_reduced_graph.rs

+10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use syntax::ext::base::{MacroKind, SyntaxExtension};
3939
use syntax::ext::base::Determinacy::Undetermined;
4040
use syntax::ext::hygiene::Mark;
4141
use syntax::ext::tt::macro_rules;
42+
use syntax::feature_gate::is_builtin_attr;
4243
use syntax::parse::token::{self, Token};
4344
use syntax::std_inject::injected_crate_name;
4445
use syntax::symbol::keywords;
@@ -1060,4 +1061,13 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
10601061
}
10611062
}
10621063
}
1064+
1065+
fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
1066+
if !attr.is_sugared_doc && is_builtin_attr(attr) {
1067+
self.resolver.current_module.builtin_attrs.borrow_mut().push((
1068+
attr.path.segments[0].ident, self.expansion, self.current_legacy_scope
1069+
));
1070+
}
1071+
visit::walk_attribute(self, attr);
1072+
}
10631073
}

src/librustc_resolve/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,7 @@ pub struct ModuleData<'a> {
10121012
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
10131013
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, Mark, LegacyScope<'a>, Option<Def>)>>,
10141014
macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
1015+
builtin_attrs: RefCell<Vec<(Ident, Mark, LegacyScope<'a>)>>,
10151016

10161017
// Macro invocations that can expand into items in this module.
10171018
unresolved_invocations: RefCell<FxHashSet<Mark>>,
@@ -1050,6 +1051,7 @@ impl<'a> ModuleData<'a> {
10501051
resolutions: RefCell::new(FxHashMap()),
10511052
legacy_macro_resolutions: RefCell::new(Vec::new()),
10521053
macro_resolutions: RefCell::new(Vec::new()),
1054+
builtin_attrs: RefCell::new(Vec::new()),
10531055
unresolved_invocations: RefCell::new(FxHashSet()),
10541056
no_implicit_prelude: false,
10551057
glob_importers: RefCell::new(Vec::new()),

src/librustc_resolve/macros.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
619619
}
620620
WhereToResolve::MacroPrelude => {
621621
match self.macro_prelude.get(&ident.name).cloned() {
622-
Some(binding) => Ok((binding, FromPrelude(true))),
622+
Some(binding) => {
623+
let mut result = Ok((binding, FromPrelude(true)));
624+
// HACK: Keep some built-in attributes working even if they are
625+
// shadowed by other built-in or standard library macros.
626+
// We need to come up with some more principled approach instead.
627+
if is_attr && (ident.name == "cfg" || ident.name == "thread_local") {
628+
if let Def::Macro(_, MacroKind::Bang) =
629+
binding.def_ignoring_ambiguity() {
630+
result = Err(Determinacy::Determined);
631+
}
632+
}
633+
result
634+
}
623635
None => Err(Determinacy::Determined),
624636
}
625637
}
@@ -928,6 +940,32 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
928940
}
929941
};
930942
}
943+
944+
for &(ident, parent_expansion, parent_legacy_scope)
945+
in module.builtin_attrs.borrow().iter() {
946+
let resolution = if ident.name == "doc" {
947+
// HACK: Some sugared doc comments in macros lose their memory about being
948+
// sugared doc comments and become shadowed by other macros.
949+
// We need to come up with some more principled approach instead.
950+
None
951+
} else {
952+
self.resolve_legacy_scope(ident, parent_expansion, parent_legacy_scope, true)
953+
}.or_else(|| {
954+
self.resolve_lexical_macro_path_segment(ident, MacroNS, parent_expansion, true,
955+
true, true, ident.span)
956+
.map(|(binding, _)| binding).ok()
957+
});
958+
959+
if let Some(binding) = resolution {
960+
if binding.def_ignoring_ambiguity() !=
961+
Def::NonMacroAttr(NonMacroAttrKind::Builtin) {
962+
let builtin_binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
963+
ty::Visibility::Public, ident.span, Mark::root())
964+
.to_name_binding(self.arenas);
965+
self.report_ambiguity_error(ident.name, ident.span, binding, builtin_binding);
966+
}
967+
}
968+
}
931969
}
932970

933971
fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// compile-flags:--test
2+
3+
#![feature(decl_macro, test)]
4+
5+
extern crate test;
6+
7+
macro test() {}
8+
9+
#[test] //~ ERROR `test` is ambiguous
10+
fn test() {}
11+
12+
macro bench() {}
13+
14+
#[bench] //~ ERROR `bench` is ambiguous
15+
fn bench(b: &mut test::Bencher) {}
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
error[E0659]: `test` is ambiguous
2+
--> $DIR/ambiguous-builtin-attrs-test.rs:9:3
3+
|
4+
LL | #[test] //~ ERROR `test` is ambiguous
5+
| ^^^^
6+
|
7+
note: `test` could refer to the name defined here
8+
--> $DIR/ambiguous-builtin-attrs-test.rs:7:1
9+
|
10+
LL | macro test() {}
11+
| ^^^^^^^^^^^^^^^
12+
note: `test` could also refer to the name defined here
13+
--> $DIR/ambiguous-builtin-attrs-test.rs:9:3
14+
|
15+
LL | #[test] //~ ERROR `test` is ambiguous
16+
| ^^^^
17+
18+
error[E0659]: `bench` is ambiguous
19+
--> $DIR/ambiguous-builtin-attrs-test.rs:14:3
20+
|
21+
LL | #[bench] //~ ERROR `bench` is ambiguous
22+
| ^^^^^
23+
|
24+
note: `bench` could refer to the name defined here
25+
--> $DIR/ambiguous-builtin-attrs-test.rs:12:1
26+
|
27+
LL | macro bench() {}
28+
| ^^^^^^^^^^^^^^^^
29+
note: `bench` could also refer to the name defined here
30+
--> $DIR/ambiguous-builtin-attrs-test.rs:14:3
31+
|
32+
LL | #[bench] //~ ERROR `bench` is ambiguous
33+
| ^^^^^
34+
35+
error: aborting due to 2 previous errors
36+
37+
For more information about this error, try `rustc --explain E0659`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![feature(decl_macro)]
2+
3+
macro repr() {}
4+
5+
#[repr(C)] //~ ERROR `repr` is ambiguous
6+
struct S;
7+
#[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
8+
struct SCond;
9+
10+
macro cfg() {}
11+
12+
#[cfg(all())] //~ ERROR `cfg` is ambiguous
13+
struct A;
14+
#[cfg(any())] // ERROR FIXME
15+
struct A;
16+
17+
macro cfg_attr() {}
18+
19+
#[cfg_attr(all(), cold)] // ERROR FIXME
20+
fn g() {}
21+
#[cfg_attr(any(), cold)] // ERROR FIXME
22+
fn h() {}
23+
24+
macro derive() {}
25+
26+
#[derive(Clone)] // ERROR FIXME
27+
struct B;
28+
29+
macro test() {}
30+
31+
#[test] // ERROR FIXME
32+
fn test() {}
33+
34+
macro bench() {}
35+
36+
#[bench] // ERROR FIXME
37+
fn bench() {}
38+
39+
macro_rules! inline { () => () }
40+
41+
#[inline] //~ ERROR `inline` is ambiguous
42+
fn f() {}
43+
#[cfg_attr(all(), inline)] //~ ERROR `inline` is ambiguous
44+
fn f_cond() {}
45+
46+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
error[E0659]: `repr` is ambiguous
2+
--> $DIR/ambiguous-builtin-attrs.rs:5:3
3+
|
4+
LL | #[repr(C)] //~ ERROR `repr` is ambiguous
5+
| ^^^^
6+
|
7+
note: `repr` could refer to the name defined here
8+
--> $DIR/ambiguous-builtin-attrs.rs:3:1
9+
|
10+
LL | macro repr() {}
11+
| ^^^^^^^^^^^^^^^
12+
note: `repr` could also refer to the name defined here
13+
--> $DIR/ambiguous-builtin-attrs.rs:5:3
14+
|
15+
LL | #[repr(C)] //~ ERROR `repr` is ambiguous
16+
| ^^^^
17+
18+
error[E0659]: `repr` is ambiguous
19+
--> $DIR/ambiguous-builtin-attrs.rs:7:19
20+
|
21+
LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
22+
| ^^^^
23+
|
24+
note: `repr` could refer to the name defined here
25+
--> $DIR/ambiguous-builtin-attrs.rs:3:1
26+
|
27+
LL | macro repr() {}
28+
| ^^^^^^^^^^^^^^^
29+
note: `repr` could also refer to the name defined here
30+
--> $DIR/ambiguous-builtin-attrs.rs:7:19
31+
|
32+
LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
33+
| ^^^^
34+
35+
error[E0659]: `cfg` is ambiguous
36+
--> $DIR/ambiguous-builtin-attrs.rs:12:3
37+
|
38+
LL | #[cfg(all())] //~ ERROR `cfg` is ambiguous
39+
| ^^^
40+
|
41+
note: `cfg` could refer to the name defined here
42+
--> $DIR/ambiguous-builtin-attrs.rs:10:1
43+
|
44+
LL | macro cfg() {}
45+
| ^^^^^^^^^^^^^^
46+
note: `cfg` could also refer to the name defined here
47+
--> $DIR/ambiguous-builtin-attrs.rs:12:3
48+
|
49+
LL | #[cfg(all())] //~ ERROR `cfg` is ambiguous
50+
| ^^^
51+
52+
error[E0659]: `inline` is ambiguous
53+
--> $DIR/ambiguous-builtin-attrs.rs:41:3
54+
|
55+
LL | #[inline] //~ ERROR `inline` is ambiguous
56+
| ^^^^^^
57+
|
58+
note: `inline` could refer to the name defined here
59+
--> $DIR/ambiguous-builtin-attrs.rs:39:1
60+
|
61+
LL | macro_rules! inline { () => () }
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63+
note: `inline` could also refer to the name defined here
64+
--> $DIR/ambiguous-builtin-attrs.rs:41:3
65+
|
66+
LL | #[inline] //~ ERROR `inline` is ambiguous
67+
| ^^^^^^
68+
69+
error[E0659]: `inline` is ambiguous
70+
--> $DIR/ambiguous-builtin-attrs.rs:43:19
71+
|
72+
LL | #[cfg_attr(all(), inline)] //~ ERROR `inline` is ambiguous
73+
| ^^^^^^
74+
|
75+
note: `inline` could refer to the name defined here
76+
--> $DIR/ambiguous-builtin-attrs.rs:39:1
77+
|
78+
LL | macro_rules! inline { () => () }
79+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
80+
note: `inline` could also refer to the name defined here
81+
--> $DIR/ambiguous-builtin-attrs.rs:43:19
82+
|
83+
LL | #[cfg_attr(all(), inline)] //~ ERROR `inline` is ambiguous
84+
| ^^^^^^
85+
86+
error: aborting due to 5 previous errors
87+
88+
For more information about this error, try `rustc --explain E0659`.

0 commit comments

Comments
 (0)