]> git.lizzy.rs Git - rust.git/commitdiff
Improve Rustdoc's handling of procedural macros
authorAaron Hill <aa1ronham@gmail.com>
Sat, 20 Jul 2019 20:34:41 +0000 (16:34 -0400)
committerAaron Hill <aa1ronham@gmail.com>
Sat, 24 Aug 2019 17:11:57 +0000 (13:11 -0400)
Fixes #58700
Fixes #58696
Fixes #49553
Fixes #52210

This commit removes the special rustdoc handling for proc macros, as we
can now
retrieve their span and attributes just like any other item.

A new command-line option is added to rustdoc: `--crate-type`. This
takes the same options as rustc's `--crate-type` option. However, all
values other than `proc-macro` are treated the same. This allows Rustdoc
to enable 'proc macro mode' when handling a proc macro crate.

In compiletest, a new 'rustdoc-flags' option is added. This allows us to
pass in the '--proc-macro-crate' flag in the absence of Cargo.

I've opened [an additional PR to
Cargo](https://github.com/rust-lang/cargo/pull/7159) to support passing
in this flag.
These two PRS can be merged in any order - the Cargo changes will not
take effect until the 'cargo' submodule is updated in this repository.

13 files changed:
src/librustc/session/config.rs
src/librustc_interface/passes.rs
src/librustdoc/clean/inline.rs
src/librustdoc/config.rs
src/librustdoc/core.rs
src/librustdoc/lib.rs
src/librustdoc/test.rs
src/test/rustdoc-ui/failed-doctest-output.rs
src/test/rustdoc-ui/failed-doctest-output.stdout
src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs
src/test/rustdoc/inline_cross/proc_macro.rs
src/test/rustdoc/proc-macro.rs
src/test/rustdoc/rustc-macro-crate.rs

index 8e3b910e0da3a89a0b8c8c56baa192f4adbc4d63..9ecdff25d26492a95c770e2f2611b4bfe8d516a3 100644 (file)
@@ -1719,13 +1719,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
                              static, framework, or dylib (the default).",
             "[KIND=]NAME",
         ),
-        opt::multi_s(
-            "",
-            "crate-type",
-            "Comma separated list of types of crates
-                                    for the compiler to emit",
-            "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
-        ),
+        make_crate_type_option(),
         opt::opt_s(
             "",
             "crate-name",
@@ -2506,6 +2500,16 @@ pub fn build_session_options_and_crate_config(
     )
 }
 
+pub fn make_crate_type_option() -> RustcOptGroup {
+    opt::multi_s(
+        "",
+        "crate-type",
+        "Comma separated list of types of crates
+                                for the compiler to emit",
+        "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
+    )
+}
+
 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
     let mut crate_types: Vec<CrateType> = Vec::new();
     for unparsed_crate_type in &list_list {
index 8b0b5a5b7a2bd11e2b87c815aeb98f0dedf98283..856690903c659d91aeedda5b787eb437f16545bf 100644 (file)
@@ -473,27 +473,22 @@ fn configure_and_expand_inner<'a>(
         ast_validation::check_crate(sess, &krate)
     });
 
-    // If we're in rustdoc we're always compiling as an rlib, but that'll trip a
-    // bunch of checks in the `modify` function below. For now just skip this
-    // step entirely if we're rustdoc as it's not too useful anyway.
-    if !sess.opts.actually_rustdoc {
-        krate = time(sess, "maybe creating a macro crate", || {
-            let crate_types = sess.crate_types.borrow();
-            let num_crate_types = crate_types.len();
-            let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro);
-            let is_test_crate = sess.opts.test;
-            syntax_ext::proc_macro_harness::inject(
-                &sess.parse_sess,
-                &mut resolver,
-                krate,
-                is_proc_macro_crate,
-                has_proc_macro_decls,
-                is_test_crate,
-                num_crate_types,
-                sess.diagnostic(),
-            )
-        });
-    }
+    krate = time(sess, "maybe creating a macro crate", || {
+        let crate_types = sess.crate_types.borrow();
+        let num_crate_types = crate_types.len();
+        let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro);
+        let is_test_crate = sess.opts.test;
+        syntax_ext::proc_macro_harness::inject(
+            &sess.parse_sess,
+            &mut resolver,
+            krate,
+            is_proc_macro_crate,
+            has_proc_macro_decls,
+            is_test_crate,
+            num_crate_types,
+            sess.diagnostic(),
+        )
+    });
 
     // Done with macro expansion!
 
index 6f93c95edef08713d5a625ac8b3a1a46b576e455..9d93e5f93c13e27b9fc55edaf538d49e0af39d3f 100644 (file)
@@ -20,6 +20,7 @@
     self,
     GetDefId,
     ToSource,
+    TypeKind
 };
 
 use super::Clean;
@@ -107,15 +108,16 @@ pub fn try_inline(
             record_extern_fqn(cx, did, clean::TypeKind::Const);
             clean::ConstantItem(build_const(cx, did))
         }
-        // FIXME: proc-macros don't propagate attributes or spans across crates, so they look empty
-        Res::Def(DefKind::Macro(MacroKind::Bang), did) => {
+        Res::Def(DefKind::Macro(kind), did) => {
             let mac = build_macro(cx, did, name);
-            if let clean::MacroItem(..) = mac {
-                record_extern_fqn(cx, did, clean::TypeKind::Macro);
-                mac
-            } else {
-                return None;
-            }
+
+            let type_kind = match kind {
+                MacroKind::Bang => TypeKind::Macro,
+                MacroKind::Attr => TypeKind::Attr,
+                MacroKind::Derive => TypeKind::Derive
+            };
+            record_extern_fqn(cx, did, type_kind);
+            mac
         }
         _ => return None,
     };
index 98ab957ecbb38078a3b5fea1af8d3e21c9d03235..cefae2e105eda731cedfd7ece1a0c66a69d1a101 100644 (file)
@@ -6,6 +6,7 @@
 use getopts;
 use rustc::lint::Level;
 use rustc::session;
+use rustc::session::config::{CrateType, parse_crate_types_from_list};
 use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
 use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options,
                              get_cmd_lint_options, ExternEntry};
@@ -32,6 +33,8 @@ pub struct Options {
     pub input: PathBuf,
     /// The name of the crate being documented.
     pub crate_name: Option<String>,
+    /// Whether or not this is a proc-macro crate
+    pub proc_macro_crate: bool,
     /// How to format errors and warnings.
     pub error_format: ErrorOutputType,
     /// Library search paths to hand to the compiler.
@@ -111,6 +114,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Options")
             .field("input", &self.input)
             .field("crate_name", &self.crate_name)
+            .field("proc_macro_crate", &self.proc_macro_crate)
             .field("error_format", &self.error_format)
             .field("libs", &self.libs)
             .field("externs", &FmtExterns(&self.externs))
@@ -431,7 +435,16 @@ pub fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
         };
         let manual_passes = matches.opt_strs("passes");
 
+        let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) {
+            Ok(types) => types,
+            Err(e) =>{
+                diag.struct_err(&format!("unknown crate type: {}", e)).emit();
+                return Err(1);
+            }
+        };
+
         let crate_name = matches.opt_str("crate-name");
+        let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
         let playground_url = matches.opt_str("playground-url");
         let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
         let display_warnings = matches.opt_present("display-warnings");
@@ -454,6 +467,7 @@ pub fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
         Ok(Options {
             input,
             crate_name,
+            proc_macro_crate,
             error_format,
             libs,
             externs,
index 87381f224d0bb424482d1c6f409599da3a84f81b..003276a5e4868f578f20039f8c36dc6f2c40a6cb 100644 (file)
@@ -228,6 +228,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
     let RustdocOptions {
         input,
         crate_name,
+        proc_macro_crate,
         error_format,
         libs,
         externs,
@@ -293,11 +294,16 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
     }).collect();
 
     let host_triple = TargetTriple::from_triple(config::host_triple());
+    let crate_types = if proc_macro_crate {
+        vec![config::CrateType::ProcMacro]
+    } else {
+        vec![config::CrateType::Rlib]
+    };
     // plays with error output here!
     let sessopts = config::Options {
         maybe_sysroot,
         search_paths: libs,
-        crate_types: vec![config::CrateType::Rlib],
+        crate_types,
         lint_opts: if !display_warnings {
             lint_opts
         } else {
index e30b35937db9fbf55f518b43273401287f8b48fa..bb83ff64b2f181026ed10c2ecc280716c5d46f44 100644 (file)
@@ -46,7 +46,7 @@
 use std::process;
 
 use rustc::session::{early_warn, early_error};
-use rustc::session::config::{ErrorOutputType, RustcOptGroup};
+use rustc::session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option};
 
 #[macro_use]
 mod externalfiles;
@@ -132,6 +132,7 @@ fn opts() -> Vec<RustcOptGroup> {
         stable("crate-name", |o| {
             o.optopt("", "crate-name", "specify the name of this crate", "NAME")
         }),
+        make_crate_type_option(),
         stable("L", |o| {
             o.optmulti("L", "library-path", "directory to add to crate search path",
                        "DIR")
index 83a8d3fc109994d008510c0538b670133b0dd72c..87bc6f09e74f5a3a53193a9e6a8c1cbc0c650105 100644 (file)
@@ -43,10 +43,16 @@ pub struct TestOptions {
 pub fn run(options: Options) -> i32 {
     let input = config::Input::File(options.input.clone());
 
+    let crate_types = if options.proc_macro_crate {
+        vec![config::CrateType::ProcMacro]
+    } else {
+        vec![config::CrateType::Dylib]
+    };
+
     let sessopts = config::Options {
         maybe_sysroot: options.maybe_sysroot.clone(),
         search_paths: options.libs.clone(),
-        crate_types: vec![config::CrateType::Dylib],
+        crate_types,
         cg: options.codegen_options.clone(),
         externs: options.externs.clone(),
         unstable_features: UnstableFeatures::from_environment(),
index d2cdeb8f8f50e8d110b884464e8b15611830bf0e..fcbd7cabc69003f4d4dc7f0fc37e9f3e97e02e0c 100644 (file)
@@ -3,6 +3,7 @@
 // adapted to use that, and that normalize line can go away
 
 // compile-flags:--test
+// rustc-env:RUST_BACKTRACE=0
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
 // failure-status: 101
 
index e362ecf349e459fb2ed40181613dd29c5328f3f3..ef1b419f52895699554e36cb1b0cde478a1da9e1 100644 (file)
@@ -1,13 +1,13 @@
 
 running 2 tests
-test $DIR/failed-doctest-output.rs - OtherStruct (line 20) ... FAILED
-test $DIR/failed-doctest-output.rs - SomeStruct (line 10) ... FAILED
+test $DIR/failed-doctest-output.rs - OtherStruct (line 21) ... FAILED
+test $DIR/failed-doctest-output.rs - SomeStruct (line 11) ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-output.rs - OtherStruct (line 20) stdout ----
+---- $DIR/failed-doctest-output.rs - OtherStruct (line 21) stdout ----
 error[E0425]: cannot find value `no` in this scope
- --> $DIR/failed-doctest-output.rs:21:1
+ --> $DIR/failed-doctest-output.rs:22:1
   |
 3 | no
   | ^^ not found in this scope
@@ -16,7 +16,7 @@ error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0425`.
 Couldn't compile the test.
----- $DIR/failed-doctest-output.rs - SomeStruct (line 10) stdout ----
+---- $DIR/failed-doctest-output.rs - SomeStruct (line 11) stdout ----
 Test executable failed (exit code 101).
 
 stdout:
@@ -32,8 +32,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
 
 failures:
-    $DIR/failed-doctest-output.rs - OtherStruct (line 20)
-    $DIR/failed-doctest-output.rs - SomeStruct (line 10)
+    $DIR/failed-doctest-output.rs - OtherStruct (line 21)
+    $DIR/failed-doctest-output.rs - SomeStruct (line 11)
 
 test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out
 
index c99ef744333583726280a0a283559395f1c4d5e5..37465ccf1c27e23b5a9b86679a51bc7e202efb74 100644 (file)
@@ -1,5 +1,6 @@
 // force-host
 // no-prefer-dynamic
+// compile-flags: --crate-type proc-macro
 
 #![crate_type="proc-macro"]
 #![crate_name="some_macros"]
@@ -25,3 +26,9 @@ pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream {
 pub fn some_derive(_item: TokenStream) -> TokenStream {
     TokenStream::new()
 }
+
+/// Doc comment from the original crate
+#[proc_macro]
+pub fn reexported_macro(_input: TokenStream) -> TokenStream {
+    TokenStream::new()
+}
index e1cdcf494024417da37f432ebd03601f507891ae..6880e303df90bea5f77baeb631b12a4c27b8f142 100644 (file)
@@ -1,16 +1,17 @@
 // aux-build:proc_macro.rs
 // build-aux-docs
 
-// FIXME: if/when proc-macros start exporting their doc attributes across crates, we can turn on
-// cross-crate inlining for them
-
 extern crate some_macros;
 
 // @has proc_macro/index.html
-// @has - '//a/@href' '../some_macros/macro.some_proc_macro.html'
-// @has - '//a/@href' '../some_macros/attr.some_proc_attr.html'
-// @has - '//a/@href' '../some_macros/derive.SomeDerive.html'
-// @!has proc_macro/macro.some_proc_macro.html
-// @!has proc_macro/attr.some_proc_attr.html
-// @!has proc_macro/derive.SomeDerive.html
+// @has - '//a/@href' 'macro.some_proc_macro.html'
+// @has - '//a/@href' 'attr.some_proc_attr.html'
+// @has - '//a/@href' 'derive.SomeDerive.html'
+// @has proc_macro/macro.some_proc_macro.html
+// @has proc_macro/attr.some_proc_attr.html
+// @has proc_macro/derive.SomeDerive.html
 pub use some_macros::{some_proc_macro, some_proc_attr, SomeDerive};
+
+// @has proc_macro/macro.reexported_macro.html
+// @has - 'Doc comment from the original crate'
+pub use some_macros::reexported_macro;
index 4bd0b092b55a718b2d9bf52c8b2ddbac40f7d80f..82196e413e94b856a267a4e1a78541a2835e94e5 100644 (file)
@@ -1,5 +1,6 @@
 // force-host
 // no-prefer-dynamic
+// compile-flags: --crate-type proc-macro --document-private-items
 
 #![crate_type="proc-macro"]
 #![crate_name="some_macros"]
@@ -58,7 +59,7 @@ pub fn some_derive(_item: TokenStream) -> TokenStream {
 }
 
 // @has some_macros/foo/index.html
-pub mod foo {
+mod foo {
     // @has - '//code' 'pub use some_proc_macro;'
     // @has - '//a/@href' '../../some_macros/macro.some_proc_macro.html'
     pub use some_proc_macro;
index 2f6308b20c2eed81021539761e724853b69559ec..dd5edc984dafaa645bb2e87616a50c66a4428235 100644 (file)
@@ -1,5 +1,6 @@
 // force-host
 // no-prefer-dynamic
+// compile-flags: --crate-type proc-macro
 
 #![crate_type = "proc-macro"]