about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume.gomez@huawei.com>2023-09-17 14:52:45 +0200
committerGuillaume Gomez <guillaume.gomez@huawei.com>2023-09-17 15:11:44 +0200
commite1294b26af2d7f731381ef18623f78f39a67f5d7 (patch)
tree9cdac3dbf803e7ad7b1a4e0b79b7be802936f06b
parentcdd182cbb2d11bb25d2dabdd752cc5980e0ac059 (diff)
downloadrust-e1294b26af2d7f731381ef18623f78f39a67f5d7.tar.gz
rust-e1294b26af2d7f731381ef18623f78f39a67f5d7.zip
Don't emit an error if the `custom_code_classes_in_docs` feature is disabled when its syntax is used.
-rw-r--r--src/librustdoc/doctest.rs1
-rw-r--r--src/librustdoc/externalfiles.rs4
-rw-r--r--src/librustdoc/html/markdown.rs95
-rw-r--r--src/librustdoc/html/render/mod.rs9
-rw-r--r--src/librustdoc/markdown.rs14
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs9
-rw-r--r--src/librustdoc/passes/check_custom_code_classes.rs31
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs9
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs4
9 files changed, 144 insertions, 32 deletions
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index ea87268877f..24597c3aca3 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1243,6 +1243,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
                     def_id.to_def_id(),
                     span_of_fragments(&attrs.doc_strings).unwrap_or(sp),
                 )),
+                self.tcx.features().custom_code_classes_in_docs,
             );
         }
 
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index f0ebb8e5a39..b34b69b1f15 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -46,6 +46,8 @@ impl ExternalHtml {
                 edition,
                 playground,
                 heading_offset: HeadingOffset::H2,
+                // For external files, it'll be disabled until the feature is enabled by default.
+                custom_code_classes_in_docs: false,
             }
             .into_string()
         );
@@ -61,6 +63,8 @@ impl ExternalHtml {
                 edition,
                 playground,
                 heading_offset: HeadingOffset::H2,
+                // For external files, it'll be disabled until the feature is enabled by default.
+                custom_code_classes_in_docs: false,
             }
             .into_string()
         );
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 177fb1a9426..59958fbaef9 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -20,6 +20,7 @@
 //!     edition: Edition::Edition2015,
 //!     playground: &None,
 //!     heading_offset: HeadingOffset::H2,
+//!     custom_code_classes_in_docs: true,
 //! };
 //! let html = md.into_string();
 //! // ... something using html
@@ -95,6 +96,8 @@ pub struct Markdown<'a> {
     /// Offset at which we render headings.
     /// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `<h2>`.
     pub heading_offset: HeadingOffset,
+    /// `true` if the `custom_code_classes_in_docs` feature is enabled.
+    pub custom_code_classes_in_docs: bool,
 }
 /// A struct like `Markdown` that renders the markdown with a table of contents.
 pub(crate) struct MarkdownWithToc<'a> {
@@ -103,6 +106,8 @@ pub(crate) struct MarkdownWithToc<'a> {
     pub(crate) error_codes: ErrorCodes,
     pub(crate) edition: Edition,
     pub(crate) playground: &'a Option<Playground>,
+    /// `true` if the `custom_code_classes_in_docs` feature is enabled.
+    pub(crate) custom_code_classes_in_docs: bool,
 }
 /// A tuple struct like `Markdown` that renders the markdown escaping HTML tags
 /// and includes no paragraph tags.
@@ -203,6 +208,7 @@ struct CodeBlocks<'p, 'a, I: Iterator<Item = Event<'a>>> {
     // Information about the playground if a URL has been specified, containing an
     // optional crate name and the URL.
     playground: &'p Option<Playground>,
+    custom_code_classes_in_docs: bool,
 }
 
 impl<'p, 'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'p, 'a, I> {
@@ -211,8 +217,15 @@ impl<'p, 'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'p, 'a, I> {
         error_codes: ErrorCodes,
         edition: Edition,
         playground: &'p Option<Playground>,
+        custom_code_classes_in_docs: bool,
     ) -> Self {
-        CodeBlocks { inner: iter, check_error_codes: error_codes, edition, playground }
+        CodeBlocks {
+            inner: iter,
+            check_error_codes: error_codes,
+            edition,
+            playground,
+            custom_code_classes_in_docs,
+        }
     }
 }
 
@@ -242,8 +255,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
 
         let parse_result = match kind {
             CodeBlockKind::Fenced(ref lang) => {
-                let parse_result =
-                    LangString::parse_without_check(lang, self.check_error_codes, false);
+                let parse_result = LangString::parse_without_check(
+                    lang,
+                    self.check_error_codes,
+                    false,
+                    self.custom_code_classes_in_docs,
+                );
                 if !parse_result.rust {
                     let added_classes = parse_result.added_classes;
                     let lang_string = if let Some(lang) = parse_result.unknown.first() {
@@ -725,8 +742,17 @@ pub(crate) fn find_testable_code<T: doctest::Tester>(
     error_codes: ErrorCodes,
     enable_per_target_ignores: bool,
     extra_info: Option<&ExtraInfo<'_>>,
+    custom_code_classes_in_docs: bool,
 ) {
-    find_codes(doc, tests, error_codes, enable_per_target_ignores, extra_info, false)
+    find_codes(
+        doc,
+        tests,
+        error_codes,
+        enable_per_target_ignores,
+        extra_info,
+        false,
+        custom_code_classes_in_docs,
+    )
 }
 
 pub(crate) fn find_codes<T: doctest::Tester>(
@@ -736,6 +762,7 @@ pub(crate) fn find_codes<T: doctest::Tester>(
     enable_per_target_ignores: bool,
     extra_info: Option<&ExtraInfo<'_>>,
     include_non_rust: bool,
+    custom_code_classes_in_docs: bool,
 ) {
     let mut parser = Parser::new(doc).into_offset_iter();
     let mut prev_offset = 0;
@@ -754,6 +781,7 @@ pub(crate) fn find_codes<T: doctest::Tester>(
                                 error_codes,
                                 enable_per_target_ignores,
                                 extra_info,
+                                custom_code_classes_in_docs,
                             )
                         }
                     }
@@ -1153,8 +1181,15 @@ impl LangString {
         string: &str,
         allow_error_code_check: ErrorCodes,
         enable_per_target_ignores: bool,
+        custom_code_classes_in_docs: bool,
     ) -> Self {
-        Self::parse(string, allow_error_code_check, enable_per_target_ignores, None)
+        Self::parse(
+            string,
+            allow_error_code_check,
+            enable_per_target_ignores,
+            None,
+            custom_code_classes_in_docs,
+        )
     }
 
     fn parse(
@@ -1162,6 +1197,7 @@ impl LangString {
         allow_error_code_check: ErrorCodes,
         enable_per_target_ignores: bool,
         extra: Option<&ExtraInfo<'_>>,
+        custom_code_classes_in_docs: bool,
     ) -> Self {
         let allow_error_code_check = allow_error_code_check.as_bool();
         let mut seen_rust_tags = false;
@@ -1197,7 +1233,11 @@ impl LangString {
                     seen_rust_tags = true;
                 }
                 LangStringToken::LangToken("custom") => {
-                    seen_custom_tag = true;
+                    if custom_code_classes_in_docs {
+                        seen_custom_tag = true;
+                    } else {
+                        seen_other_tags = true;
+                    }
                 }
                 LangStringToken::LangToken("test_harness") => {
                     data.test_harness = true;
@@ -1268,11 +1308,16 @@ impl LangString {
                     data.unknown.push(x.to_owned());
                 }
                 LangStringToken::KeyValueAttribute(key, value) => {
-                    if key == "class" {
-                        data.added_classes.push(value.to_owned());
-                    } else if let Some(extra) = extra {
-                        extra
-                            .error_invalid_codeblock_attr(format!("unsupported attribute `{key}`"));
+                    if custom_code_classes_in_docs {
+                        if key == "class" {
+                            data.added_classes.push(value.to_owned());
+                        } else if let Some(extra) = extra {
+                            extra.error_invalid_codeblock_attr(format!(
+                                "unsupported attribute `{key}`"
+                            ));
+                        }
+                    } else {
+                        seen_other_tags = true;
                     }
                 }
                 LangStringToken::ClassAttribute(class) => {
@@ -1302,6 +1347,7 @@ impl Markdown<'_> {
             edition,
             playground,
             heading_offset,
+            custom_code_classes_in_docs,
         } = self;
 
         // This is actually common enough to special-case
@@ -1324,7 +1370,7 @@ impl Markdown<'_> {
         let p = Footnotes::new(p);
         let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
         let p = TableWrapper::new(p);
-        let p = CodeBlocks::new(p, codes, edition, playground);
+        let p = CodeBlocks::new(p, codes, edition, playground, custom_code_classes_in_docs);
         html::push_html(&mut s, p);
 
         s
@@ -1333,7 +1379,14 @@ impl Markdown<'_> {
 
 impl MarkdownWithToc<'_> {
     pub(crate) fn into_string(self) -> String {
-        let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self;
+        let MarkdownWithToc {
+            content: md,
+            ids,
+            error_codes: codes,
+            edition,
+            playground,
+            custom_code_classes_in_docs,
+        } = self;
 
         let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
 
@@ -1345,7 +1398,7 @@ impl MarkdownWithToc<'_> {
             let p = HeadingLinks::new(p, Some(&mut toc), ids, HeadingOffset::H1);
             let p = Footnotes::new(p);
             let p = TableWrapper::new(p.map(|(ev, _)| ev));
-            let p = CodeBlocks::new(p, codes, edition, playground);
+            let p = CodeBlocks::new(p, codes, edition, playground, custom_code_classes_in_docs);
             html::push_html(&mut s, p);
         }
 
@@ -1786,7 +1839,11 @@ pub(crate) struct RustCodeBlock {
 
 /// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or
 /// untagged (and assumed to be rust).
-pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeBlock> {
+pub(crate) fn rust_code_blocks(
+    md: &str,
+    extra_info: &ExtraInfo<'_>,
+    custom_code_classes_in_docs: bool,
+) -> Vec<RustCodeBlock> {
     let mut code_blocks = vec![];
 
     if md.is_empty() {
@@ -1803,7 +1860,13 @@ pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<Rust
                     let lang_string = if syntax.is_empty() {
                         Default::default()
                     } else {
-                        LangString::parse(&*syntax, ErrorCodes::Yes, false, Some(extra_info))
+                        LangString::parse(
+                            &*syntax,
+                            ErrorCodes::Yes,
+                            false,
+                            Some(extra_info),
+                            custom_code_classes_in_docs,
+                        )
                     };
                     if !lang_string.rust {
                         continue;
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 5adbecd6d04..f70f59d3be3 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -403,7 +403,8 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
             error_codes: shared.codes,
             edition: shared.edition(),
             playground: &shared.playground,
-            heading_offset: HeadingOffset::H1
+            heading_offset: HeadingOffset::H1,
+            custom_code_classes_in_docs: false,
         }
         .into_string()
     )
@@ -437,6 +438,7 @@ fn render_markdown<'a, 'cx: 'a>(
     heading_offset: HeadingOffset,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
     display_fn(move |f| {
+        let custom_code_classes_in_docs = cx.tcx().features().custom_code_classes_in_docs;
         write!(
             f,
             "<div class=\"docblock\">{}</div>",
@@ -448,6 +450,7 @@ fn render_markdown<'a, 'cx: 'a>(
                 edition: cx.shared.edition(),
                 playground: &cx.shared.playground,
                 heading_offset,
+                custom_code_classes_in_docs,
             }
             .into_string()
         )
@@ -1778,6 +1781,7 @@ fn render_impl(
                      </div>",
                 );
             }
+            let custom_code_classes_in_docs = cx.tcx().features().custom_code_classes_in_docs;
             write!(
                 w,
                 "<div class=\"docblock\">{}</div>",
@@ -1788,7 +1792,8 @@ fn render_impl(
                     error_codes: cx.shared.codes,
                     edition: cx.shared.edition(),
                     playground: &cx.shared.playground,
-                    heading_offset: HeadingOffset::H4
+                    heading_offset: HeadingOffset::H4,
+                    custom_code_classes_in_docs,
                 }
                 .into_string()
             );
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 526eea30478..1ac3163b2cd 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -80,6 +80,8 @@ pub(crate) fn render<P: AsRef<Path>>(
             error_codes,
             edition,
             playground: &playground,
+            // For markdown files, it'll be disabled until the feature is enabled by default.
+            custom_code_classes_in_docs: false,
         }
         .into_string()
     } else {
@@ -91,6 +93,8 @@ pub(crate) fn render<P: AsRef<Path>>(
             edition,
             playground: &playground,
             heading_offset: HeadingOffset::H1,
+            // For markdown files, it'll be disabled until the feature is enabled by default.
+            custom_code_classes_in_docs: false,
         }
         .into_string()
     };
@@ -154,7 +158,15 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
     collector.set_position(DUMMY_SP);
     let codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
 
-    find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None);
+    // For markdown files, it'll be disabled until the feature is enabled by default.
+    find_testable_code(
+        &input_str,
+        &mut collector,
+        codes,
+        options.enable_per_target_ignores,
+        None,
+        false,
+    );
 
     crate::doctest::run_tests(options.test_args, options.nocapture, collector.tests);
     Ok(())
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 592dd0a145c..60def40588a 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -208,7 +208,14 @@ impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
                 let has_docs = !i.attrs.doc_strings.is_empty();
                 let mut tests = Tests { found_tests: 0 };
 
-                find_testable_code(&i.doc_value(), &mut tests, ErrorCodes::No, false, None);
+                find_testable_code(
+                    &i.doc_value(),
+                    &mut tests,
+                    ErrorCodes::No,
+                    false,
+                    None,
+                    self.ctx.tcx.features().custom_code_classes_in_docs,
+                );
 
                 let has_doc_example = tests.found_tests != 0;
                 let hir_id = DocContext::as_local_hir_id(self.ctx.tcx, i.item_id).unwrap();
diff --git a/src/librustdoc/passes/check_custom_code_classes.rs b/src/librustdoc/passes/check_custom_code_classes.rs
index 73e80372e4a..1a703a4e967 100644
--- a/src/librustdoc/passes/check_custom_code_classes.rs
+++ b/src/librustdoc/passes/check_custom_code_classes.rs
@@ -9,7 +9,9 @@ use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::html::markdown::{find_codes, ErrorCodes, LangString};
 
-use rustc_session::parse::feature_err;
+use rustc_errors::StashKey;
+use rustc_feature::GateIssue;
+use rustc_session::parse::add_feature_diagnostics_for_issue;
 use rustc_span::symbol::sym;
 
 pub(crate) const CHECK_CUSTOM_CODE_CLASSES: Pass = Pass {
@@ -55,23 +57,32 @@ pub(crate) fn look_for_custom_classes<'tcx>(cx: &DocContext<'tcx>, item: &Item)
     let mut tests = TestsWithCustomClasses { custom_classes_found: vec![] };
 
     let dox = item.attrs.doc_value();
-    find_codes(&dox, &mut tests, ErrorCodes::No, false, None, true);
+    find_codes(&dox, &mut tests, ErrorCodes::No, false, None, true, true);
 
     if !tests.custom_classes_found.is_empty() && !cx.tcx.features().custom_code_classes_in_docs {
-        feature_err(
-            &cx.tcx.sess.parse_sess,
+        let span = item.attr_span(cx.tcx);
+        let sess = &cx.tcx.sess.parse_sess;
+        let mut err = sess
+            .span_diagnostic
+            .struct_span_warn(span, "custom classes in code blocks will change behaviour");
+        add_feature_diagnostics_for_issue(
+            &mut err,
+            sess,
             sym::custom_code_classes_in_docs,
-            item.attr_span(cx.tcx),
-            "custom classes in code blocks are unstable",
-        )
-        .note(
+            GateIssue::Language,
+            false,
+        );
+
+        err.note(
             // This will list the wrong items to make them more easily searchable.
             // To ensure the most correct hits, it adds back the 'class:' that was stripped.
             format!(
                 "found these custom classes: class={}",
                 tests.custom_classes_found.join(",class=")
             ),
-        )
-        .emit();
+        );
+
+        // A later feature_err call can steal and cancel this warning.
+        err.stash(span, StashKey::EarlySyntaxWarning);
     }
 }
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 96224d7c6e2..d1c4cc1f595 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -113,7 +113,14 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item
 
     let mut tests = Tests { found_tests: 0 };
 
-    find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);
+    find_testable_code(
+        dox,
+        &mut tests,
+        ErrorCodes::No,
+        false,
+        None,
+        cx.tcx.features().custom_code_classes_in_docs,
+    );
 
     if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples {
         if should_have_doc_example(cx, item) {
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index 316b1a41c7d..ac8a75a4f18 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -20,7 +20,9 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) {
     if let Some(dox) = &item.opt_doc_value() {
         let sp = item.attr_span(cx.tcx);
         let extra = crate::html::markdown::ExtraInfo::new(cx.tcx, item.item_id.expect_def_id(), sp);
-        for code_block in markdown::rust_code_blocks(dox, &extra) {
+        for code_block in
+            markdown::rust_code_blocks(dox, &extra, cx.tcx.features().custom_code_classes_in_docs)
+        {
             check_rust_syntax(cx, item, dox, code_block);
         }
     }