diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 5377ebde1683f..2cbf348f13a1b 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -221,6 +221,8 @@ declare_features! (
     (active, rustc_private, "1.0.0", Some(27812), None),
     /// Allows using internal rustdoc features like `doc(primitive)` or `doc(keyword)`.
     (active, rustdoc_internals, "1.58.0", Some(90418), None),
+    /// Allows using the `rustdoc::missing_doc_code_examples` lint
+    (active, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None),
     /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
     (active, start, "1.0.0", Some(29633), None),
     /// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index f1d8ef2e47d31..1e16ac51e9e5d 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -440,8 +440,10 @@ impl<'s> LintLevelsBuilder<'s> {
                                     sp,
                                     reason,
                                 );
-                                for id in ids {
-                                    self.insert_spec(*id, (level, src));
+                                for &id in ids {
+                                    if self.check_gated_lint(id, attr.span) {
+                                        self.insert_spec(id, (level, src));
+                                    }
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations.push((
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 9c6530c8a0843..11b2d057a0769 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -658,18 +658,21 @@ macro_rules! declare_lint {
 macro_rules! declare_tool_lint {
     (
         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
+        $(, @feature_gate = $gate:expr;)?
     ) => (
-        $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false}
+        $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?}
     );
     (
         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
         report_in_external_macro: $rep:expr
+        $(, @feature_gate = $gate:expr;)?
     ) => (
-         $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep}
+         $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?}
     );
     (
         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
         $external:expr
+        $(, @feature_gate = $gate:expr;)?
     ) => (
         $(#[$attr])*
         $vis static $NAME: &$crate::Lint = &$crate::Lint {
@@ -680,8 +683,9 @@ macro_rules! declare_tool_lint {
             report_in_external_macro: $external,
             future_incompatible: None,
             is_plugin: true,
-            feature_gate: None,
+            $(feature_gate: Some($gate),)?
             crate_level_only: false,
+            ..$crate::Lint::default_fields_for_macro()
         };
     );
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 871bc5c1cdb06..1779ff4bcf1dc 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1292,6 +1292,7 @@ symbols! {
         rustc_variance,
         rustdoc,
         rustdoc_internals,
+        rustdoc_missing_doc_code_examples,
         rustfmt,
         rvalue_static_promotion,
         s,
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index 240aec52cff02..e76c19a61c541 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -64,9 +64,13 @@ where
 }
 
 macro_rules! declare_rustdoc_lint {
-    ($(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)?) => {
+    (
+        $(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)?
+        $(@feature_gate = $gate:expr;)?
+    ) => {
         declare_tool_lint! {
             $(#[$attr])* pub rustdoc::$name, $level, $descr
+            $(, @feature_gate = $gate;)?
         }
     }
 }
@@ -123,7 +127,8 @@ declare_rustdoc_lint! {
     /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples
     MISSING_DOC_CODE_EXAMPLES,
     Allow,
-    "detects publicly-exported items without code samples in their documentation"
+    "detects publicly-exported items without code samples in their documentation",
+    @feature_gate = rustc_span::symbol::sym::rustdoc_missing_doc_code_examples;
 }
 
 declare_rustdoc_lint! {
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index e86f9083394cf..55d5f303d3452 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -117,7 +117,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item
 
     find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);
 
-    if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() {
+    if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples {
         if should_have_doc_example(cx, item) {
             debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
             let sp = item.attr_span(cx.tcx);
diff --git a/src/test/rustdoc-ui/check-fail.rs b/src/test/rustdoc-ui/check-fail.rs
index 2355d6a3d6cbc..c5e1759ee2d1d 100644
--- a/src/test/rustdoc-ui/check-fail.rs
+++ b/src/test/rustdoc-ui/check-fail.rs
@@ -1,5 +1,6 @@
 // compile-flags: -Z unstable-options --check
 
+#![feature(rustdoc_missing_doc_code_examples)]
 #![deny(missing_docs)]
 #![deny(rustdoc::all)]
 
diff --git a/src/test/rustdoc-ui/check-fail.stderr b/src/test/rustdoc-ui/check-fail.stderr
index 5d46dc7201409..217b89d935bf9 100644
--- a/src/test/rustdoc-ui/check-fail.stderr
+++ b/src/test/rustdoc-ui/check-fail.stderr
@@ -1,30 +1,30 @@
 error: missing documentation for a function
-  --> $DIR/check-fail.rs:11:1
+  --> $DIR/check-fail.rs:12:1
    |
 LL | pub fn foo() {}
    | ^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/check-fail.rs:3:9
+  --> $DIR/check-fail.rs:4:9
    |
 LL | #![deny(missing_docs)]
    |         ^^^^^^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/check-fail.rs:11:1
+  --> $DIR/check-fail.rs:12:1
    |
 LL | pub fn foo() {}
    | ^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/check-fail.rs:4:9
+  --> $DIR/check-fail.rs:5:9
    |
 LL | #![deny(rustdoc::all)]
    |         ^^^^^^^^^^^^
    = note: `#[deny(rustdoc::missing_doc_code_examples)]` implied by `#[deny(rustdoc::all)]`
 
 error: unknown attribute `testharness`. Did you mean `test_harness`?
-  --> $DIR/check-fail.rs:6:1
+  --> $DIR/check-fail.rs:7:1
    |
 LL | / //! ```rust,testharness
 LL | |
@@ -36,7 +36,7 @@ LL | | //! ```
    = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
 
 error: unknown attribute `testharness`. Did you mean `test_harness`?
-  --> $DIR/check-fail.rs:15:1
+  --> $DIR/check-fail.rs:16:1
    |
 LL | / /// hello
 LL | |
diff --git a/src/test/rustdoc-ui/check.rs b/src/test/rustdoc-ui/check.rs
index 2b44ba24b4426..f70b033615139 100644
--- a/src/test/rustdoc-ui/check.rs
+++ b/src/test/rustdoc-ui/check.rs
@@ -2,9 +2,11 @@
 // compile-flags: -Z unstable-options --check
 // normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
 
-#![warn(missing_docs)]
+#![feature(rustdoc_missing_doc_code_examples)]
 //~^ WARN
 //~^^ WARN
+
+#![warn(missing_docs)]
 #![warn(rustdoc::all)]
 
 pub fn foo() {}
diff --git a/src/test/rustdoc-ui/check.stderr b/src/test/rustdoc-ui/check.stderr
index 06e607fbe55fa..78ae65d313a70 100644
--- a/src/test/rustdoc-ui/check.stderr
+++ b/src/test/rustdoc-ui/check.stderr
@@ -1,22 +1,23 @@
 warning: missing documentation for the crate
   --> $DIR/check.rs:5:1
    |
-LL | / #![warn(missing_docs)]
+LL | / #![feature(rustdoc_missing_doc_code_examples)]
 LL | |
 LL | |
-LL | | #![warn(rustdoc::all)]
+LL | |
+...  |
 LL | |
 LL | | pub fn foo() {}
    | |_______________^
    |
 note: the lint level is defined here
-  --> $DIR/check.rs:5:9
+  --> $DIR/check.rs:9:9
    |
 LL | #![warn(missing_docs)]
    |         ^^^^^^^^^^^^
 
 warning: missing documentation for a function
-  --> $DIR/check.rs:10:1
+  --> $DIR/check.rs:12:1
    |
 LL | pub fn foo() {}
    | ^^^^^^^^^^^^
@@ -24,7 +25,7 @@ LL | pub fn foo() {}
 warning: no documentation found for this crate's top-level module
    |
 note: the lint level is defined here
-  --> $DIR/check.rs:8:9
+  --> $DIR/check.rs:10:9
    |
 LL | #![warn(rustdoc::all)]
    |         ^^^^^^^^^^^^
@@ -35,10 +36,11 @@ LL | #![warn(rustdoc::all)]
 warning: missing code example in this documentation
   --> $DIR/check.rs:5:1
    |
-LL | / #![warn(missing_docs)]
+LL | / #![feature(rustdoc_missing_doc_code_examples)]
+LL | |
 LL | |
 LL | |
-LL | | #![warn(rustdoc::all)]
+...  |
 LL | |
 LL | | pub fn foo() {}
    | |_______________^
@@ -46,7 +48,7 @@ LL | | pub fn foo() {}
    = note: `#[warn(rustdoc::missing_doc_code_examples)]` implied by `#[warn(rustdoc::all)]`
 
 warning: missing code example in this documentation
-  --> $DIR/check.rs:10:1
+  --> $DIR/check.rs:12:1
    |
 LL | pub fn foo() {}
    | ^^^^^^^^^^^^^^^
diff --git a/src/test/rustdoc-ui/doc-without-codeblock.rs b/src/test/rustdoc-ui/doc-without-codeblock.rs
index 315fca195873a..86d7c83d33598 100644
--- a/src/test/rustdoc-ui/doc-without-codeblock.rs
+++ b/src/test/rustdoc-ui/doc-without-codeblock.rs
@@ -1,4 +1,5 @@
-#![deny(rustdoc::missing_doc_code_examples)] //~ ERROR missing code example in this documentation
+#![feature(rustdoc_missing_doc_code_examples)] //~ ERROR missing code example in this documentation
+#![deny(rustdoc::missing_doc_code_examples)]
 
 /// Some docs.
 //~^ ERROR missing code example in this documentation
diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr
index 1c138044165f2..ebf2a2d54f75c 100644
--- a/src/test/rustdoc-ui/doc-without-codeblock.stderr
+++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr
@@ -1,35 +1,35 @@
 error: missing code example in this documentation
   --> $DIR/doc-without-codeblock.rs:1:1
    |
-LL | / #![deny(rustdoc::missing_doc_code_examples)]
+LL | / #![feature(rustdoc_missing_doc_code_examples)]
+LL | | #![deny(rustdoc::missing_doc_code_examples)]
 LL | |
 LL | | /// Some docs.
-LL | |
 ...  |
 LL | |     }
 LL | | }
    | |_^
    |
 note: the lint level is defined here
-  --> $DIR/doc-without-codeblock.rs:1:9
+  --> $DIR/doc-without-codeblock.rs:2:9
    |
 LL | #![deny(rustdoc::missing_doc_code_examples)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/doc-without-codeblock.rs:7:1
+  --> $DIR/doc-without-codeblock.rs:8:1
    |
 LL | /// And then, the princess died.
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/doc-without-codeblock.rs:10:5
+  --> $DIR/doc-without-codeblock.rs:11:5
    |
 LL |     /// Or maybe not because she saved herself!
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/doc-without-codeblock.rs:3:1
+  --> $DIR/doc-without-codeblock.rs:4:1
    |
 LL | /// Some docs.
    | ^^^^^^^^^^^^^^
diff --git a/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.rs b/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.rs
new file mode 100644
index 0000000000000..daba698686408
--- /dev/null
+++ b/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.rs
@@ -0,0 +1,10 @@
+#![deny(unknown_lints)]
+//~^ NOTE defined here
+
+#![allow(rustdoc::missing_doc_code_examples)]
+//~^ ERROR unknown lint
+//~| ERROR unknown lint
+//~| NOTE lint is unstable
+//~| NOTE lint is unstable
+//~| NOTE see issue
+//~| NOTE see issue
diff --git a/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.stderr b/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.stderr
new file mode 100644
index 0000000000000..517e08aa7c974
--- /dev/null
+++ b/src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.stderr
@@ -0,0 +1,29 @@
+error: unknown lint: `rustdoc::missing_doc_code_examples`
+  --> $DIR/feature-gate-rustdoc_missing_doc_code_examples.rs:4:1
+   |
+LL | #![allow(rustdoc::missing_doc_code_examples)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/feature-gate-rustdoc_missing_doc_code_examples.rs:1:9
+   |
+LL | #![deny(unknown_lints)]
+   |         ^^^^^^^^^^^^^
+   = note: the `rustdoc::missing_doc_code_examples` lint is unstable
+   = note: see issue #101730 <https://github.com/rust-lang/rust/issues/101730> for more information
+   = help: add `#![feature(rustdoc_missing_doc_code_examples)]` to the crate attributes to enable
+
+error: unknown lint: `rustdoc::missing_doc_code_examples`
+  --> $DIR/feature-gate-rustdoc_missing_doc_code_examples.rs:4:1
+   |
+LL | #![allow(rustdoc::missing_doc_code_examples)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `rustdoc::missing_doc_code_examples` lint is unstable
+   = note: see issue #101730 <https://github.com/rust-lang/rust/issues/101730> for more information
+   = help: add `#![feature(rustdoc_missing_doc_code_examples)]` to the crate attributes to enable
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/rustdoc-ui/lint-group.rs b/src/test/rustdoc-ui/lint-group.rs
index 61555a6e68617..09aca6d2b2742 100644
--- a/src/test/rustdoc-ui/lint-group.rs
+++ b/src/test/rustdoc-ui/lint-group.rs
@@ -1,3 +1,5 @@
+#![feature(rustdoc_missing_doc_code_examples)]
+
 //! Documenting the kinds of lints emitted by rustdoc.
 //!
 //! ```
diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr
index e28600160b1fd..5336c0445747a 100644
--- a/src/test/rustdoc-ui/lint-group.stderr
+++ b/src/test/rustdoc-ui/lint-group.stderr
@@ -1,18 +1,18 @@
 error: missing code example in this documentation
-  --> $DIR/lint-group.rs:16:1
+  --> $DIR/lint-group.rs:18:1
    |
 LL | /// wait, this doesn't have a doctest?
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-group.rs:7:9
+  --> $DIR/lint-group.rs:9:9
    |
 LL | #![deny(rustdoc::all)]
    |         ^^^^^^^^^^^^
    = note: `#[deny(rustdoc::missing_doc_code_examples)]` implied by `#[deny(rustdoc::all)]`
 
 error: documentation test in private item
-  --> $DIR/lint-group.rs:19:1
+  --> $DIR/lint-group.rs:21:1
    |
 LL | / /// wait, this *does* have a doctest?
 LL | | ///
@@ -24,13 +24,13 @@ LL | | /// ```
    = note: `#[deny(rustdoc::private_doc_tests)]` implied by `#[deny(rustdoc::all)]`
 
 error: missing code example in this documentation
-  --> $DIR/lint-group.rs:26:1
+  --> $DIR/lint-group.rs:28:1
    |
 LL | /// <unknown>
    | ^^^^^^^^^^^^^
 
 error: unresolved link to `error`
-  --> $DIR/lint-group.rs:9:29
+  --> $DIR/lint-group.rs:11:29
    |
 LL | /// what up, let's make an [error]
    |                             ^^^^^ no item named `error` in scope
@@ -39,7 +39,7 @@ LL | /// what up, let's make an [error]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 error: unclosed HTML tag `unknown`
-  --> $DIR/lint-group.rs:26:5
+  --> $DIR/lint-group.rs:28:5
    |
 LL | /// <unknown>
    |     ^^^^^^^^^
diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs
index fac6342cd24b9..40f35728d79b0 100644
--- a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs
+++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs
@@ -1,3 +1,4 @@
+#![feature(rustdoc_missing_doc_code_examples)]
 #![deny(missing_docs)]
 #![deny(rustdoc::missing_doc_code_examples)]
 
diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
index 9e51ecd2ba017..f9331250154d7 100644
--- a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
+++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
@@ -1,35 +1,35 @@
 error: missing code example in this documentation
-  --> $DIR/lint-missing-doc-code-example.rs:19:1
+  --> $DIR/lint-missing-doc-code-example.rs:20:1
    |
 LL | pub mod module1 {
    | ^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-missing-doc-code-example.rs:2:9
+  --> $DIR/lint-missing-doc-code-example.rs:3:9
    |
 LL | #![deny(rustdoc::missing_doc_code_examples)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/lint-missing-doc-code-example.rs:37:3
+  --> $DIR/lint-missing-doc-code-example.rs:38:3
    |
 LL |   /// doc
    |   ^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/lint-missing-doc-code-example.rs:49:1
+  --> $DIR/lint-missing-doc-code-example.rs:50:1
    |
 LL | /// Doc
    | ^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/lint-missing-doc-code-example.rs:56:1
+  --> $DIR/lint-missing-doc-code-example.rs:57:1
    |
 LL | /// Doc
    | ^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/lint-missing-doc-code-example.rs:63:1
+  --> $DIR/lint-missing-doc-code-example.rs:64:1
    |
 LL | /// Doc
    | ^^^^^^^