about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2018-09-22 09:56:30 +0200
committerGitHub <noreply@github.com>2018-09-22 09:56:30 +0200
commit23636e3f99ea8dba2d5e91637d818ebfbe6c1b96 (patch)
treed25f86f367b740a63971e965a2e819106aba593a /src
parente59df621a85e40a1c99d134f3f0d1a7d17db4ff5 (diff)
parent06b197582e1974e925925d28196b1ed867208ebf (diff)
downloadrust-23636e3f99ea8dba2d5e91637d818ebfbe6c1b96.tar.gz
rust-23636e3f99ea8dba2d5e91637d818ebfbe6c1b96.zip
Rollup merge of #54350 - Munksgaard:support-edition-in-doc-test, r=steveklabnik
Support specifying edition in doc test

Fixes #52623

r? @QuietMisdreavus
Diffstat (limited to 'src')
-rw-r--r--src/doc/rustdoc/src/documentation-tests.md16
-rw-r--r--src/doc/unstable-book/src/language-features/try-blocks.md4
-rw-r--r--src/librustdoc/html/markdown.rs107
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/libsyntax_pos/edition.rs2
-rw-r--r--src/test/rustdoc/edition-doctest.rs54
6 files changed, 149 insertions, 36 deletions
diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md
index e4af122d0cb..dd8dcb7ff9b 100644
--- a/src/doc/rustdoc/src/documentation-tests.md
+++ b/src/doc/rustdoc/src/documentation-tests.md
@@ -323,6 +323,22 @@ compiles, then the test will fail. However please note that code failing
 with the current Rust release may work in a future release, as new features
 are added.
 
+```text
+/// Only runs on the 2018 edition.
+///
+/// ```edition2018
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "2".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// ```
+```
+
+`edition2018` tells `rustdoc` that the code sample should be compiled the 2018
+edition of Rust. Similarly, you can specify `edition2015` to compile the code
+with the 2015 edition.
+
 ## Syntax reference
 
 The *exact* syntax for code blocks, including the edge cases, can be found
diff --git a/src/doc/unstable-book/src/language-features/try-blocks.md b/src/doc/unstable-book/src/language-features/try-blocks.md
index 866b37a39a7..e342c260a73 100644
--- a/src/doc/unstable-book/src/language-features/try-blocks.md
+++ b/src/doc/unstable-book/src/language-features/try-blocks.md
@@ -9,9 +9,7 @@ The tracking issue for this feature is: [#31436]
 The `try_blocks` feature adds support for `try` blocks. A `try`
 block creates a new scope one can use the `?` operator in.
 
-```rust,ignore
-// This code needs the 2018 edition
-
+```rust,edition2018
 #![feature(try_blocks)]
 
 use std::num::ParseIntError;
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 18ad862c11b..d14275aeb6b 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -37,6 +37,7 @@ use std::fmt::{self, Write};
 use std::borrow::Cow;
 use std::ops::Range;
 use std::str;
+use syntax::edition::Edition;
 
 use html::toc::TocBuilder;
 use html::highlight;
@@ -170,6 +171,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
         let event = self.inner.next();
         let compile_fail;
         let ignore;
+        let edition;
         if let Some(Event::Start(Tag::CodeBlock(lang))) = event {
             let parse_result = LangString::parse(&lang, self.check_error_codes);
             if !parse_result.rust {
@@ -177,6 +179,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
             }
             compile_fail = parse_result.compile_fail;
             ignore = parse_result.ignore;
+            edition = parse_result.edition;
         } else {
             return event;
         }
@@ -212,6 +215,17 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
                 } else {
                     ""
                 };
+
+                let edition_string = if let Some(e @ Edition::Edition2018) = edition {
+                    format!("&amp;edition={}{}", e,
+                            if channel == "&amp;version=nightly" { "" }
+                            else { "&amp;version=nightly" })
+                } else if let Some(e) = edition {
+                    format!("&amp;edition={}", e)
+                } else {
+                    "".to_owned()
+                };
+
                 // These characters don't need to be escaped in a URI.
                 // FIXME: use a library function for percent encoding.
                 fn dont_escape(c: u8) -> bool {
@@ -231,26 +245,44 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
                     }
                 }
                 Some(format!(
-                    r#"<a class="test-arrow" target="_blank" href="{}?code={}{}">Run</a>"#,
-                    url, test_escaped, channel
+                    r#"<a class="test-arrow" target="_blank" href="{}?code={}{}{}">Run</a>"#,
+                    url, test_escaped, channel, edition_string
                 ))
             });
+
             let tooltip = if ignore {
-                Some(("This example is not tested", "ignore"))
+                Some(("This example is not tested".to_owned(), "ignore"))
             } else if compile_fail {
-                Some(("This example deliberately fails to compile", "compile_fail"))
+                Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
+            } else if let Some(e) = edition {
+                Some((format!("This code runs with edition {}", e), "edition"))
             } else {
                 None
             };
-            s.push_str(&highlight::render_with_highlighting(
-                        &text,
-                        Some(&format!("rust-example-rendered{}",
-                                      if ignore { " ignore" }
-                                      else if compile_fail { " compile_fail" }
-                                      else { "" })),
-                        playground_button.as_ref().map(String::as_str),
-                        tooltip));
-            Some(Event::Html(s.into()))
+
+            if let Some((s1, s2)) = tooltip {
+                s.push_str(&highlight::render_with_highlighting(
+                    &text,
+                    Some(&format!("rust-example-rendered{}",
+                                  if ignore { " ignore" }
+                                  else if compile_fail { " compile_fail" }
+                                  else if edition.is_some() { " edition " }
+                                  else { "" })),
+                    playground_button.as_ref().map(String::as_str),
+                    Some((s1.as_str(), s2))));
+                Some(Event::Html(s.into()))
+            } else {
+                s.push_str(&highlight::render_with_highlighting(
+                    &text,
+                    Some(&format!("rust-example-rendered{}",
+                                  if ignore { " ignore" }
+                                  else if compile_fail { " compile_fail" }
+                                  else if edition.is_some() { " edition " }
+                                  else { "" })),
+                    playground_button.as_ref().map(String::as_str),
+                    None));
+                Some(Event::Html(s.into()))
+            }
         })
     }
 }
@@ -577,6 +609,7 @@ pub struct LangString {
     pub compile_fail: bool,
     pub error_codes: Vec<String>,
     pub allow_fail: bool,
+    pub edition: Option<Edition>
 }
 
 impl LangString {
@@ -591,6 +624,7 @@ impl LangString {
             compile_fail: false,
             error_codes: Vec::new(),
             allow_fail: false,
+            edition: None,
         }
     }
 
@@ -625,6 +659,11 @@ impl LangString {
                     seen_rust_tags = !seen_other_tags || seen_rust_tags;
                     data.no_run = true;
                 }
+                x if allow_error_code_check && x.starts_with("edition") => {
+                    // allow_error_code_check is true if we're on nightly, which
+                    // is needed for edition support
+                    data.edition = x[7..].parse::<Edition>().ok();
+                }
                 x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => {
                     if x[1..].parse::<u32>().is_ok() {
                         data.error_codes.push(x.to_owned());
@@ -925,12 +964,14 @@ mod tests {
     use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap};
     use super::plain_summary_line;
     use std::cell::RefCell;
+    use syntax::edition::Edition;
 
     #[test]
     fn test_lang_string_parse() {
         fn t(s: &str,
             should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool,
-            compile_fail: bool, allow_fail: bool, error_codes: Vec<String>) {
+            compile_fail: bool, allow_fail: bool, error_codes: Vec<String>,
+             edition: Option<Edition>) {
             assert_eq!(LangString::parse(s, ErrorCodes::Yes), LangString {
                 should_panic,
                 no_run,
@@ -941,6 +982,7 @@ mod tests {
                 error_codes,
                 original: s.to_owned(),
                 allow_fail,
+                edition,
             })
         }
 
@@ -948,23 +990,26 @@ mod tests {
             Vec::new()
         }
 
-        // marker                | should_panic| no_run| ignore| rust | test_harness| compile_fail
-        //                       | allow_fail | error_codes
-        t("",                      false,        false,  false,  true,  false, false, false, v());
-        t("rust",                  false,        false,  false,  true,  false, false, false, v());
-        t("sh",                    false,        false,  false,  false, false, false, false, v());
-        t("ignore",                false,        false,  true,   true,  false, false, false, v());
-        t("should_panic",          true,         false,  false,  true,  false, false, false, v());
-        t("no_run",                false,        true,   false,  true,  false, false, false, v());
-        t("test_harness",          false,        false,  false,  true,  true,  false, false, v());
-        t("compile_fail",          false,        true,   false,  true,  false, true,  false, v());
-        t("allow_fail",            false,        false,  false,  true,  false, false, true,  v());
-        t("{.no_run .example}",    false,        true,   false,  true,  false, false, false, v());
-        t("{.sh .should_panic}",   true,         false,  false,  false, false, false, false, v());
-        t("{.example .rust}",      false,        false,  false,  true,  false, false, false, v());
-        t("{.test_harness .rust}", false,        false,  false,  true,  true,  false, false, v());
-        t("text, no_run",          false,        true,   false,  false, false, false, false, v());
-        t("text,no_run",           false,        true,   false,  false, false, false, false, v());
+        // ignore-tidy-linelength
+        // marker                | should_panic | no_run | ignore | rust | test_harness
+        //                       | compile_fail | allow_fail | error_codes | edition
+        t("",                      false,         false,   false,   true,  false, false, false, v(), None);
+        t("rust",                  false,         false,   false,   true,  false, false, false, v(), None);
+        t("sh",                    false,         false,   false,   false, false, false, false, v(), None);
+        t("ignore",                false,         false,   true,    true,  false, false, false, v(), None);
+        t("should_panic",          true,          false,   false,   true,  false, false, false, v(), None);
+        t("no_run",                false,         true,    false,   true,  false, false, false, v(), None);
+        t("test_harness",          false,         false,   false,   true,  true,  false, false, v(), None);
+        t("compile_fail",          false,         true,    false,   true,  false, true,  false, v(), None);
+        t("allow_fail",            false,         false,   false,   true,  false, false, true,  v(), None);
+        t("{.no_run .example}",    false,         true,    false,   true,  false, false, false, v(), None);
+        t("{.sh .should_panic}",   true,          false,   false,   false, false, false, false, v(), None);
+        t("{.example .rust}",      false,         false,   false,   true,  false, false, false, v(), None);
+        t("{.test_harness .rust}", false,         false,   false,   true,  true,  false, false, v(), None);
+        t("text, no_run",          false,         true,    false,   false, false, false, false, v(), None);
+        t("text,no_run",           false,         true,    false,   false, false, false, false, v(), None);
+        t("edition2015",           false,         false,   false,   true,  false, false, false, v(), Some(Edition::Edition2015));
+        t("edition2018",           false,         false,   false,   true,  false, false, false, v(), Some(Edition::Edition2018));
     }
 
     #[test]
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 8a9ca924ee1..dbebc3ab393 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -545,7 +545,7 @@ impl Collector {
         let opts = self.opts.clone();
         let maybe_sysroot = self.maybe_sysroot.clone();
         let linker = self.linker.clone();
-        let edition = self.edition;
+        let edition = config.edition.unwrap_or(self.edition);
         debug!("Creating test {}: {}", name, test);
         self.tests.push(testing::TestDescAndFn {
             desc: testing::TestDesc {
diff --git a/src/libsyntax_pos/edition.rs b/src/libsyntax_pos/edition.rs
index 7709db72a02..5819cd7f480 100644
--- a/src/libsyntax_pos/edition.rs
+++ b/src/libsyntax_pos/edition.rs
@@ -12,7 +12,7 @@ use std::fmt;
 use std::str::FromStr;
 
 /// The edition of the compiler (RFC 2052)
-#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, RustcEncodable, RustcDecodable, Eq)]
 #[non_exhaustive]
 pub enum Edition {
     // editions must be kept in order, oldest to newest
diff --git a/src/test/rustdoc/edition-doctest.rs b/src/test/rustdoc/edition-doctest.rs
new file mode 100644
index 00000000000..322d461f854
--- /dev/null
+++ b/src/test/rustdoc/edition-doctest.rs
@@ -0,0 +1,54 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:--test
+
+/// ```rust,edition2018
+/// #![feature(try_blocks)]
+///
+/// use std::num::ParseIntError;
+///
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "2".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// assert_eq!(result, Ok(6));
+///
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "foo".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// assert!(result.is_err());
+/// ```
+
+
+/// ```rust,edition2015,compile_fail,E0574
+/// #![feature(try_blocks)]
+///
+/// use std::num::ParseIntError;
+///
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "2".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// assert_eq!(result, Ok(6));
+///
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "foo".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// assert!(result.is_err());
+/// ```
+
+pub fn foo() {}