Skip to content

Commit 2b3e98f

Browse files
committed
resolve: Future proof derive helper attributes
1 parent 1b6be5a commit 2b3e98f

File tree

6 files changed

+117
-38
lines changed

6 files changed

+117
-38
lines changed

src/librustc_resolve/macros.rs

+36-38
Original file line numberDiff line numberDiff line change
@@ -532,41 +532,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
532532
parent_scope.module.legacy_macro_resolutions.borrow_mut()
533533
.push((path[0], kind, parent_scope.clone(), result.ok()));
534534

535-
if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else {
536-
return result;
537-
}
538-
539-
// At this point we've found that the `attr` is determinately unresolved and thus can be
540-
// interpreted as a custom attribute. Normally custom attributes are feature gated, but
541-
// it may be a custom attribute whitelisted by a derive macro and they do not require
542-
// a feature gate.
543-
//
544-
// So here we look through all of the derive annotations in scope and try to resolve them.
545-
// If they themselves successfully resolve *and* one of the resolved derive macros
546-
// whitelists this attribute's name, then this is a registered attribute and we can convert
547-
// it from a "generic custom attrite" into a "known derive helper attribute".
548-
assert!(kind == MacroKind::Attr);
549-
enum ConvertToDeriveHelper { Yes, No, DontKnow }
550-
let mut convert_to_derive_helper = ConvertToDeriveHelper::No;
551-
for derive in &parent_scope.derives {
552-
match self.resolve_macro_to_def(derive, MacroKind::Derive, parent_scope, force) {
553-
Ok((_, ext)) => if let SyntaxExtension::ProcMacroDerive(_, inert_attrs, _) = &*ext {
554-
if inert_attrs.contains(&path[0].name) {
555-
convert_to_derive_helper = ConvertToDeriveHelper::Yes;
556-
break
557-
}
558-
},
559-
Err(Determinacy::Undetermined) =>
560-
convert_to_derive_helper = ConvertToDeriveHelper::DontKnow,
561-
Err(Determinacy::Determined) => {}
562-
}
563-
}
564-
565-
match convert_to_derive_helper {
566-
ConvertToDeriveHelper::Yes => Ok(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)),
567-
ConvertToDeriveHelper::No => result,
568-
ConvertToDeriveHelper::DontKnow => Err(Determinacy::determined(force)),
569-
}
535+
result
570536
}
571537

572538
// Resolve the initial segment of a non-global macro path
@@ -607,6 +573,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
607573
// 2b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
608574
// 3. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
609575
// 4. Language prelude: builtin attributes (closed, controlled).
576+
// N (unordered). Derive helpers (open, not controlled). All ambiguities with other names
577+
// are currently reported as errors. They should be higher in priority than preludes
578+
// and maybe even names in modules according to the "general principles" above. They
579+
// also should be subject to restricted shadowing because are effectively produced by
580+
// derives (you need to resolve the derive first to add helpers into scope), but they
581+
// should be available before the derive is expanded for compatibility.
582+
// It's mess in general, so we are being conservative for now.
610583

611584
assert!(ns == TypeNS || ns == MacroNS);
612585
assert!(force || !record_used); // `record_used` implies `force`
@@ -630,6 +603,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
630603
MacroUsePrelude,
631604
BuiltinMacros,
632605
BuiltinAttrs,
606+
DeriveHelpers,
633607
ExternPrelude,
634608
ToolPrelude,
635609
StdLibPrelude,
@@ -679,6 +653,26 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
679653
Err(Determinacy::Determined)
680654
}
681655
}
656+
WhereToResolve::DeriveHelpers => {
657+
let mut result = Err(Determinacy::Determined);
658+
for derive in &parent_scope.derives {
659+
let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
660+
if let Ok((_, ext)) = self.resolve_macro_to_def(derive, MacroKind::Derive,
661+
&parent_scope, force) {
662+
if let SyntaxExtension::ProcMacroDerive(_, helper_attrs, _) = &*ext {
663+
if helper_attrs.contains(&ident.name) {
664+
let binding =
665+
(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
666+
ty::Visibility::Public, derive.span, Mark::root())
667+
.to_name_binding(self.arenas);
668+
result = Ok((binding, FromPrelude(false)));
669+
break;
670+
}
671+
}
672+
}
673+
}
674+
result
675+
}
682676
WhereToResolve::ExternPrelude => {
683677
if use_prelude && self.extern_prelude.contains(&ident.name) {
684678
if !self.session.features_untracked().extern_prelude &&
@@ -758,7 +752,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
758752
}
759753
WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
760754
WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
761-
WhereToResolve::BuiltinAttrs => break, // nowhere else to search
755+
WhereToResolve::BuiltinAttrs => WhereToResolve::DeriveHelpers,
756+
WhereToResolve::DeriveHelpers => break, // nowhere else to search
762757
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
763758
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
764759
WhereToResolve::StdLibPrelude => WhereToResolve::BuiltinTypes,
@@ -780,9 +775,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
780775

781776
if let Some(innermost_result) = innermost_result {
782777
// Found another solution, if the first one was "weak", report an error.
783-
if result.0.def() != innermost_result.0.def() &&
778+
let (def, innermost_def) = (result.0.def(), innermost_result.0.def());
779+
if def != innermost_def &&
784780
(innermost_result.0.is_glob_import() ||
785-
innermost_result.0.may_appear_after(parent_scope.expansion, result.0)) {
781+
innermost_result.0.may_appear_after(parent_scope.expansion, result.0) ||
782+
innermost_def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper) ||
783+
def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)) {
786784
self.ambiguity_errors.push(AmbiguityError {
787785
ident,
788786
b1: innermost_result.0,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// no-prefer-dynamic
2+
3+
#![crate_type = "proc-macro"]
4+
5+
extern crate proc_macro;
6+
use proc_macro::*;
7+
8+
#[proc_macro_attribute]
9+
pub fn my_attr(_: TokenStream, input: TokenStream) -> TokenStream {
10+
input
11+
}
12+
13+
#[proc_macro_derive(MyTrait, attributes(my_attr))]
14+
pub fn derive(input: TokenStream) -> TokenStream {
15+
TokenStream::new()
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// no-prefer-dynamic
2+
3+
#![crate_type = "proc-macro"]
4+
5+
extern crate proc_macro;
6+
7+
use proc_macro::*;
8+
9+
#[proc_macro_derive(MyTrait, attributes(my_attr))]
10+
pub fn foo(_: TokenStream) -> TokenStream {
11+
TokenStream::new()
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// aux-build:derive-helper-shadowing.rs
2+
3+
extern crate derive_helper_shadowing;
4+
use derive_helper_shadowing::*;
5+
6+
#[derive(MyTrait)]
7+
#[my_attr] //~ ERROR `my_attr` is ambiguous
8+
struct S;
9+
10+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0659]: `my_attr` is ambiguous
2+
--> $DIR/derive-helper-shadowing.rs:7:3
3+
|
4+
LL | #[my_attr] //~ ERROR `my_attr` is ambiguous
5+
| ^^^^^^^ ambiguous name
6+
|
7+
note: `my_attr` could refer to the name imported here
8+
--> $DIR/derive-helper-shadowing.rs:4:5
9+
|
10+
LL | use derive_helper_shadowing::*;
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
note: `my_attr` could also refer to the name defined here
13+
--> $DIR/derive-helper-shadowing.rs:6:10
14+
|
15+
LL | #[derive(MyTrait)]
16+
| ^^^^^^^
17+
= note: consider adding an explicit import of `my_attr` to disambiguate
18+
19+
error: aborting due to previous error
20+
21+
For more information about this error, try `rustc --explain E0659`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// compile-pass
2+
// aux-build:issue-53481.rs
3+
4+
#[macro_use]
5+
extern crate issue_53481;
6+
7+
mod m1 {
8+
use m2::MyTrait;
9+
10+
#[derive(MyTrait)]
11+
struct A {}
12+
}
13+
14+
mod m2 {
15+
pub type MyTrait = u8;
16+
17+
#[derive(MyTrait)]
18+
#[my_attr]
19+
struct B {}
20+
}
21+
22+
fn main() {}

0 commit comments

Comments
 (0)