]> git.lizzy.rs Git - rust.git/commitdiff
resolve: Future proof derive helper attributes
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Thu, 13 Sep 2018 02:11:13 +0000 (05:11 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Thu, 13 Sep 2018 02:11:13 +0000 (05:11 +0300)
src/librustc_resolve/macros.rs
src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs [new file with mode: 0644]
src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs [new file with mode: 0644]
src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs [new file with mode: 0644]
src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr [new file with mode: 0644]
src/test/ui-fulldeps/proc-macro/issue-53481.rs [new file with mode: 0644]

index af3da94ced926cf679d3a3599790129fdd0b5596..f687e022a412cf646215307bf1c0dda60705c971 100644 (file)
@@ -532,41 +532,7 @@ pub fn resolve_macro_to_def_inner(
         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 @@ enum ConvertToDeriveHelper { Yes, No, DontKnow }
         // 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 @@ enum WhereToResolve<'a> {
             MacroUsePrelude,
             BuiltinMacros,
             BuiltinAttrs,
+            DeriveHelpers,
             ExternPrelude,
             ToolPrelude,
             StdLibPrelude,
@@ -679,6 +653,26 @@ enum WhereToResolve<'a> {
                         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 @@ macro_rules! continue_search { () => {
                     }
                     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 @@ macro_rules! continue_search { () => {
 
                     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,
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs
new file mode 100644 (file)
index 0000000..0fd8aa5
--- /dev/null
@@ -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()
+}
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs
new file mode 100644 (file)
index 0000000..9554cdd
--- /dev/null
@@ -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()
+}
diff --git a/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs b/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs
new file mode 100644 (file)
index 0000000..c2357d5
--- /dev/null
@@ -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() {}
diff --git a/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr b/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr
new file mode 100644 (file)
index 0000000..d597b57
--- /dev/null
@@ -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`.
diff --git a/src/test/ui-fulldeps/proc-macro/issue-53481.rs b/src/test/ui-fulldeps/proc-macro/issue-53481.rs
new file mode 100644 (file)
index 0000000..479fd1d
--- /dev/null
@@ -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() {}