mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-20 02:43:45 +00:00
resolve: Future proof derive helper attributes
This commit is contained in:
parent
1b6be5a1ca
commit
2b3e98f4e3
@ -532,41 +532,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
parent_scope.module.legacy_macro_resolutions.borrow_mut()
|
||||
.push((path[0], kind, parent_scope.clone(), result.ok()));
|
||||
|
||||
if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else {
|
||||
return result;
|
||||
}
|
||||
|
||||
// At this point we've found that the `attr` is determinately unresolved and thus can be
|
||||
// interpreted as a custom attribute. Normally custom attributes are feature gated, but
|
||||
// it may be a custom attribute whitelisted by a derive macro and they do not require
|
||||
// a feature gate.
|
||||
//
|
||||
// So here we look through all of the derive annotations in scope and try to resolve them.
|
||||
// If they themselves successfully resolve *and* one of the resolved derive macros
|
||||
// whitelists this attribute's name, then this is a registered attribute and we can convert
|
||||
// it from a "generic custom attrite" into a "known derive helper attribute".
|
||||
assert!(kind == MacroKind::Attr);
|
||||
enum ConvertToDeriveHelper { Yes, No, DontKnow }
|
||||
let mut convert_to_derive_helper = ConvertToDeriveHelper::No;
|
||||
for derive in &parent_scope.derives {
|
||||
match self.resolve_macro_to_def(derive, MacroKind::Derive, parent_scope, force) {
|
||||
Ok((_, ext)) => if let SyntaxExtension::ProcMacroDerive(_, inert_attrs, _) = &*ext {
|
||||
if inert_attrs.contains(&path[0].name) {
|
||||
convert_to_derive_helper = ConvertToDeriveHelper::Yes;
|
||||
break
|
||||
}
|
||||
},
|
||||
Err(Determinacy::Undetermined) =>
|
||||
convert_to_derive_helper = ConvertToDeriveHelper::DontKnow,
|
||||
Err(Determinacy::Determined) => {}
|
||||
}
|
||||
}
|
||||
|
||||
match convert_to_derive_helper {
|
||||
ConvertToDeriveHelper::Yes => Ok(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)),
|
||||
ConvertToDeriveHelper::No => result,
|
||||
ConvertToDeriveHelper::DontKnow => Err(Determinacy::determined(force)),
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
// Resolve the initial segment of a non-global macro path
|
||||
@ -607,6 +573,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
// 2b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
|
||||
// 3. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
|
||||
// 4. Language prelude: builtin attributes (closed, controlled).
|
||||
// N (unordered). Derive helpers (open, not controlled). All ambiguities with other names
|
||||
// are currently reported as errors. They should be higher in priority than preludes
|
||||
// and maybe even names in modules according to the "general principles" above. They
|
||||
// also should be subject to restricted shadowing because are effectively produced by
|
||||
// derives (you need to resolve the derive first to add helpers into scope), but they
|
||||
// should be available before the derive is expanded for compatibility.
|
||||
// It's mess in general, so we are being conservative for now.
|
||||
|
||||
assert!(ns == TypeNS || ns == MacroNS);
|
||||
assert!(force || !record_used); // `record_used` implies `force`
|
||||
@ -630,6 +603,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
MacroUsePrelude,
|
||||
BuiltinMacros,
|
||||
BuiltinAttrs,
|
||||
DeriveHelpers,
|
||||
ExternPrelude,
|
||||
ToolPrelude,
|
||||
StdLibPrelude,
|
||||
@ -679,6 +653,26 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
}
|
||||
WhereToResolve::DeriveHelpers => {
|
||||
let mut result = Err(Determinacy::Determined);
|
||||
for derive in &parent_scope.derives {
|
||||
let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
|
||||
if let Ok((_, ext)) = self.resolve_macro_to_def(derive, MacroKind::Derive,
|
||||
&parent_scope, force) {
|
||||
if let SyntaxExtension::ProcMacroDerive(_, helper_attrs, _) = &*ext {
|
||||
if helper_attrs.contains(&ident.name) {
|
||||
let binding =
|
||||
(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
|
||||
ty::Visibility::Public, derive.span, Mark::root())
|
||||
.to_name_binding(self.arenas);
|
||||
result = Ok((binding, FromPrelude(false)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
WhereToResolve::ExternPrelude => {
|
||||
if use_prelude && self.extern_prelude.contains(&ident.name) {
|
||||
if !self.session.features_untracked().extern_prelude &&
|
||||
@ -758,7 +752,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
}
|
||||
WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
|
||||
WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
|
||||
WhereToResolve::BuiltinAttrs => break, // nowhere else to search
|
||||
WhereToResolve::BuiltinAttrs => WhereToResolve::DeriveHelpers,
|
||||
WhereToResolve::DeriveHelpers => break, // nowhere else to search
|
||||
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
|
||||
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
|
||||
WhereToResolve::StdLibPrelude => WhereToResolve::BuiltinTypes,
|
||||
@ -780,9 +775,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
|
||||
if let Some(innermost_result) = innermost_result {
|
||||
// Found another solution, if the first one was "weak", report an error.
|
||||
if result.0.def() != innermost_result.0.def() &&
|
||||
let (def, innermost_def) = (result.0.def(), innermost_result.0.def());
|
||||
if def != innermost_def &&
|
||||
(innermost_result.0.is_glob_import() ||
|
||||
innermost_result.0.may_appear_after(parent_scope.expansion, result.0)) {
|
||||
innermost_result.0.may_appear_after(parent_scope.expansion, result.0) ||
|
||||
innermost_def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper) ||
|
||||
def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)) {
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
ident,
|
||||
b1: innermost_result.0,
|
||||
|
@ -0,0 +1,16 @@
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn my_attr(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[proc_macro_derive(MyTrait, attributes(my_attr))]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
TokenStream::new()
|
||||
}
|
12
src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs
Normal file
12
src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro_derive(MyTrait, attributes(my_attr))]
|
||||
pub fn foo(_: TokenStream) -> TokenStream {
|
||||
TokenStream::new()
|
||||
}
|
10
src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs
Normal file
10
src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// aux-build:derive-helper-shadowing.rs
|
||||
|
||||
extern crate derive_helper_shadowing;
|
||||
use derive_helper_shadowing::*;
|
||||
|
||||
#[derive(MyTrait)]
|
||||
#[my_attr] //~ ERROR `my_attr` is ambiguous
|
||||
struct S;
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,21 @@
|
||||
error[E0659]: `my_attr` is ambiguous
|
||||
--> $DIR/derive-helper-shadowing.rs:7:3
|
||||
|
|
||||
LL | #[my_attr] //~ ERROR `my_attr` is ambiguous
|
||||
| ^^^^^^^ ambiguous name
|
||||
|
|
||||
note: `my_attr` could refer to the name imported here
|
||||
--> $DIR/derive-helper-shadowing.rs:4:5
|
||||
|
|
||||
LL | use derive_helper_shadowing::*;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: `my_attr` could also refer to the name defined here
|
||||
--> $DIR/derive-helper-shadowing.rs:6:10
|
||||
|
|
||||
LL | #[derive(MyTrait)]
|
||||
| ^^^^^^^
|
||||
= note: consider adding an explicit import of `my_attr` to disambiguate
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0659`.
|
22
src/test/ui-fulldeps/proc-macro/issue-53481.rs
Normal file
22
src/test/ui-fulldeps/proc-macro/issue-53481.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// compile-pass
|
||||
// aux-build:issue-53481.rs
|
||||
|
||||
#[macro_use]
|
||||
extern crate issue_53481;
|
||||
|
||||
mod m1 {
|
||||
use m2::MyTrait;
|
||||
|
||||
#[derive(MyTrait)]
|
||||
struct A {}
|
||||
}
|
||||
|
||||
mod m2 {
|
||||
pub type MyTrait = u8;
|
||||
|
||||
#[derive(MyTrait)]
|
||||
#[my_attr]
|
||||
struct B {}
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user