Rollup merge of #62213 - QuietMisdreavus:cfg-doctest, r=GuillaumeGomez

rustdoc: set cfg(doctest) when collecting doctests

Note: This PR builds on top of https://github.com/rust-lang/rust/pull/61199; only the last commit is specific to this PR.

As discussed in https://github.com/rust-lang/rust/pull/61199, we want the ability to isolate items to only when rustdoc is collecting doctests, but we can't use `cfg(test)` because of libcore's `#![cfg(not(test))]`. This PR proposes a new cfg flag, `cfg(doctest)`, specific to this situation, rather than reusing an existing flag. I've isolated it behind a feature gate so that we can contain the effects to nightly only. (A stable workaround that can be used in lieu of `#[cfg(doctest)]` is `#[cfg(rustdoc)] #[doc(hidden)]`, at least once https://github.com/rust-lang/rust/pull/61351 lands.)

Tracking issue: https://github.com/rust-lang/rust/issues/62210
This commit is contained in:
Mazdak Farrokhzad 2019-07-07 17:00:18 +02:00 committed by GitHub
commit fe807fcf3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 78 additions and 4 deletions

View File

@ -212,6 +212,36 @@ pub struct BigX;
Then, when looking for it through the `rustdoc` search, if you enter "x" or Then, when looking for it through the `rustdoc` search, if you enter "x" or
"big", search will show the `BigX` struct first. "big", search will show the `BigX` struct first.
### Include items only when collecting doctests
Rustdoc's [documentation tests] can do some things that regular unit tests can't, so it can
sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in
documentation. To this end, Rustdoc allows you to have certain items only appear when it's
collecting doctests, so you can utilize doctest functionality without forcing the test to appear in
docs, or to find an arbitrary private item to include it on.
If you add `#![feature(cfg_doctest)]` to your crate, Rustdoc will set `cfg(doctest)` when collecting
doctests. Note that they will still link against only the public items of your crate; if you need to
test private items, unit tests are still the way to go.
In this example, we're adding doctests that we know won't compile, to verify that our struct can
only take in valid data:
```rust
#![feature(cfg_doctest)]
/// We have a struct here. Remember it doesn't accept negative numbers!
pub struct MyStruct(usize);
/// ```compile_fail
/// let x = my_crate::MyStruct(-5);
/// ```
#[cfg(doctest)]
pub struct MyStructOnlyTakesUsize;
```
[documentation tests]: documentation-tests.html
## Unstable command-line arguments ## Unstable command-line arguments
These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are

View File

@ -351,6 +351,9 @@ impl Options {
.unwrap_or_else(|| PathBuf::from("doc")); .unwrap_or_else(|| PathBuf::from("doc"));
let mut cfgs = matches.opt_strs("cfg"); let mut cfgs = matches.opt_strs("cfg");
cfgs.push("rustdoc".to_string()); cfgs.push("rustdoc".to_string());
if should_test {
cfgs.push("doctest".to_string());
}
let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s)); let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s));

View File

@ -577,6 +577,9 @@ declare_features! (
// Allows `async || body` closures. // Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None), (active, async_closure, "1.37.0", Some(62290), None),
// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests
(active, cfg_doctest, "1.37.0", Some(62210), None),
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// feature-group-end: actual feature gates // feature-group-end: actual feature gates
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -1592,6 +1595,7 @@ const GATED_CFGS: &[(Symbol, Symbol, fn(&Features) -> bool)] = &[
(sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)),
(sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
(sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)), (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)),
(sym::doctest, sym::cfg_doctest, cfg_fn!(cfg_doctest)),
]; ];
#[derive(Debug)] #[derive(Debug)]

View File

@ -171,6 +171,7 @@ symbols! {
cfg, cfg,
cfg_attr, cfg_attr,
cfg_attr_multi, cfg_attr_multi,
cfg_doctest,
cfg_target_feature, cfg_target_feature,
cfg_target_has_atomic, cfg_target_has_atomic,
cfg_target_thread_local, cfg_target_thread_local,
@ -241,6 +242,7 @@ symbols! {
doc_keyword, doc_keyword,
doc_masked, doc_masked,
doc_spotlight, doc_spotlight,
doctest,
document_private_items, document_private_items,
dotdoteq_in_patterns, dotdoteq_in_patterns,
dotdot_in_tuple_patterns, dotdot_in_tuple_patterns,

View File

@ -1,10 +1,12 @@
// build-pass (FIXME(62277): could be check-pass?) // build-pass (FIXME(62277): could be check-pass?)
// compile-flags:--test // compile-flags:--test --test-args --test-threads=1
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
// Crates like core have doctests gated on `cfg(not(test))` so we need to make // Crates like core have doctests gated on `cfg(not(test))` so we need to make
// sure `cfg(test)` is not active when running `rustdoc --test`. // sure `cfg(test)` is not active when running `rustdoc --test`.
#![feature(cfg_doctest)]
/// this doctest will be ignored: /// this doctest will be ignored:
/// ///
/// ``` /// ```
@ -20,3 +22,11 @@ pub struct Foo;
/// ``` /// ```
#[cfg(not(test))] #[cfg(not(test))]
pub struct Foo; pub struct Foo;
/// this doctest will be tested, but will not appear in documentation:
///
/// ```
/// assert!(true)
/// ```
#[cfg(doctest)]
pub struct Bar;

View File

@ -1,6 +1,7 @@
running 1 test running 2 tests
test $DIR/cfg-test.rs - Foo (line 18) ... ok test $DIR/cfg-test.rs - Bar (line 28) ... ok
test $DIR/cfg-test.rs - Foo (line 20) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

View File

@ -0,0 +1,8 @@
#![feature(cfg_doctest)]
// @!has cfg_doctest/struct.SomeStruct.html
// @!has cfg_doctest/index.html '//a/@href' 'struct.SomeStruct.html'
/// Sneaky, this isn't actually part of docs.
#[cfg(doctest)]
pub struct SomeStruct;

View File

@ -0,0 +1,4 @@
#[cfg(doctest)] //~ ERROR
pub struct SomeStruct;
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0658]: `cfg(doctest)` is experimental and subject to change
--> $DIR/feature-gate-cfg_doctest.rs:1:7
|
LL | #[cfg(doctest)]
| ^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/62210
= help: add #![feature(cfg_doctest)] to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.