about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-03-24 19:43:42 +0000
committerbors <bors@rust-lang.org>2025-03-24 19:43:42 +0000
commitf8c27dfe1a2e7fb538fd91dad53de06992c7c967 (patch)
treec453df3f38612e8b1cbd7714e78dffaadba831ff
parent4510e86a41388733675465a8647d4235f3bf2023 (diff)
parent4202bf96698125785719a061dec561a8ab70ba9c (diff)
downloadrust-f8c27dfe1a2e7fb538fd91dad53de06992c7c967.tar.gz
rust-f8c27dfe1a2e7fb538fd91dad53de06992c7c967.zip
Auto merge of #138901 - matthiaskrgr:rollup-qbbanhr, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #138662 (Implement some basics in UEFI fs)
 - #138800 (remove remnants of const_box feature)
 - #138821 (match lowering cleanup: remove unused unsizing logic from `non_scalar_compare`)
 - #138864 (Rework `--print` options documentation)
 - #138868 (Add do_not_recommend typo help)
 - #138882 (`with_scope` is only ever used for ast modules)
 - #138894 (Update books)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_middle/src/thir.rs6
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/test.rs108
-rw-r--r--compiler/rustc_resolve/src/late.rs25
-rw-r--r--compiler/rustc_resolve/src/macros.rs14
-rw-r--r--library/alloc/src/boxed.rs12
-rw-r--r--library/std/src/sys/fs/uefi.rs74
m---------src/doc/book0
m---------src/doc/reference0
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/command-line-arguments.md53
-rw-r--r--src/doc/rustc/src/command-line-arguments/print-options.md212
-rw-r--r--tests/ui/diagnostic_namespace/suggest_typos.rs5
-rw-r--r--tests/ui/diagnostic_namespace/suggest_typos.stderr14
14 files changed, 340 insertions, 188 deletions
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index bbcd509c558..6783bbf8bf4 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -800,9 +800,9 @@ pub enum PatKind<'tcx> {
     },
 
     /// One of the following:
-    /// * `&str`/`&[u8]` (represented as a valtree), which will be handled as a string/slice pattern
-    ///   and thus exhaustiveness checking will detect if you use the same string/slice twice in
-    ///   different patterns.
+    /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
+    ///   exhaustiveness checking will detect if you use the same string twice in different
+    ///   patterns.
     /// * integer, bool, char or float (represented as a valtree), which will be handled by
     ///   exhaustiveness to cover exactly its own value, similar to `&str`, but these values are
     ///   much simpler.
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index ea341b604e0..710538ef4b8 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -1326,8 +1326,8 @@ enum TestKind<'tcx> {
     Eq {
         value: Const<'tcx>,
         // Integer types are handled by `SwitchInt`, and constants with ADT
-        // types are converted back into patterns, so this can only be `&str`,
-        // `&[T]`, `f32` or `f64`.
+        // types and `&[T]` types are converted back into patterns, so this can
+        // only be `&str`, `f32` or `f64`.
         ty: Ty<'tcx>,
     },
 
diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs
index e5d61bc9e55..7ef9e48326f 100644
--- a/compiler/rustc_mir_build/src/builder/matches/test.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/test.rs
@@ -11,7 +11,6 @@ use std::sync::Arc;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::{LangItem, RangeEnd};
 use rustc_middle::mir::*;
-use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -178,21 +177,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     _ => {}
                 }
 
+                assert_eq!(expect_ty, ty);
                 if !ty.is_scalar() {
                     // Use `PartialEq::eq` instead of `BinOp::Eq`
                     // (the binop can only handle primitives)
-                    self.non_scalar_compare(
+                    // Make sure that we do *not* call any user-defined code here.
+                    // The only type that can end up here is string literals, which have their
+                    // comparison defined in `core`.
+                    // (Interestingly this means that exhaustiveness analysis relies, for soundness,
+                    // on the `PartialEq` impl for `str` to b correct!)
+                    match *ty.kind() {
+                        ty::Ref(_, deref_ty, _) if deref_ty == self.tcx.types.str_ => {}
+                        _ => {
+                            span_bug!(source_info.span, "invalid type for non-scalar compare: {ty}")
+                        }
+                    };
+                    self.string_compare(
                         block,
                         success_block,
                         fail_block,
                         source_info,
                         expect,
-                        expect_ty,
                         Operand::Copy(place),
-                        ty,
                     );
                 } else {
-                    assert_eq!(expect_ty, ty);
                     self.compare(
                         block,
                         success_block,
@@ -370,97 +378,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         );
     }
 
-    /// Compare two values using `<T as std::compare::PartialEq>::eq`.
-    /// If the values are already references, just call it directly, otherwise
-    /// take a reference to the values first and then call it.
-    fn non_scalar_compare(
+    /// Compare two values of type `&str` using `<str as std::cmp::PartialEq>::eq`.
+    fn string_compare(
         &mut self,
         block: BasicBlock,
         success_block: BasicBlock,
         fail_block: BasicBlock,
         source_info: SourceInfo,
-        mut expect: Operand<'tcx>,
-        expect_ty: Ty<'tcx>,
-        mut val: Operand<'tcx>,
-        mut ty: Ty<'tcx>,
+        expect: Operand<'tcx>,
+        val: Operand<'tcx>,
     ) {
-        // If we're using `b"..."` as a pattern, we need to insert an
-        // unsizing coercion, as the byte string has the type `&[u8; N]`.
-        //
-        // We want to do this even when the scrutinee is a reference to an
-        // array, so we can call `<[u8]>::eq` rather than having to find an
-        // `<[u8; N]>::eq`.
-        let unsize = |ty: Ty<'tcx>| match ty.kind() {
-            ty::Ref(region, rty, _) => match rty.kind() {
-                ty::Array(inner_ty, n) => Some((region, inner_ty, n)),
-                _ => None,
-            },
-            _ => None,
-        };
-        let opt_ref_ty = unsize(ty);
-        let opt_ref_test_ty = unsize(expect_ty);
-        match (opt_ref_ty, opt_ref_test_ty) {
-            // nothing to do, neither is an array
-            (None, None) => {}
-            (Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => {
-                let tcx = self.tcx;
-                // make both a slice
-                ty = Ty::new_imm_ref(tcx, *region, Ty::new_slice(tcx, *elem_ty));
-                if opt_ref_ty.is_some() {
-                    let temp = self.temp(ty, source_info.span);
-                    self.cfg.push_assign(
-                        block,
-                        source_info,
-                        temp,
-                        Rvalue::Cast(
-                            CastKind::PointerCoercion(
-                                PointerCoercion::Unsize,
-                                CoercionSource::Implicit,
-                            ),
-                            val,
-                            ty,
-                        ),
-                    );
-                    val = Operand::Copy(temp);
-                }
-                if opt_ref_test_ty.is_some() {
-                    let slice = self.temp(ty, source_info.span);
-                    self.cfg.push_assign(
-                        block,
-                        source_info,
-                        slice,
-                        Rvalue::Cast(
-                            CastKind::PointerCoercion(
-                                PointerCoercion::Unsize,
-                                CoercionSource::Implicit,
-                            ),
-                            expect,
-                            ty,
-                        ),
-                    );
-                    expect = Operand::Move(slice);
-                }
-            }
-        }
-
-        // Figure out the type on which we are calling `PartialEq`. This involves an extra wrapping
-        // reference: we can only compare two `&T`, and then compare_ty will be `T`.
-        // Make sure that we do *not* call any user-defined code here.
-        // The only types that can end up here are string and byte literals,
-        // which have their comparison defined in `core`.
-        // (Interestingly this means that exhaustiveness analysis relies, for soundness,
-        // on the `PartialEq` impls for `str` and `[u8]` to b correct!)
-        let compare_ty = match *ty.kind() {
-            ty::Ref(_, deref_ty, _)
-                if deref_ty == self.tcx.types.str_ || deref_ty != self.tcx.types.u8 =>
-            {
-                deref_ty
-            }
-            _ => span_bug!(source_info.span, "invalid type for non-scalar compare: {}", ty),
-        };
-
+        let str_ty = self.tcx.types.str_;
         let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
-        let method = trait_method(self.tcx, eq_def_id, sym::eq, [compare_ty, compare_ty]);
+        let method = trait_method(self.tcx, eq_def_id, sym::eq, [str_ty, str_ty]);
 
         let bool_ty = self.tcx.types.bool;
         let eq_result = self.temp(bool_ty, source_info.span);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 6056a69ee71..e04d0083548 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1544,20 +1544,17 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         ret
     }
 
-    fn with_scope<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
-        if let Some(module) = self.r.get_module(self.r.local_def_id(id).to_def_id()) {
-            // Move down in the graph.
-            let orig_module = replace(&mut self.parent_scope.module, module);
-            self.with_rib(ValueNS, RibKind::Module(module), |this| {
-                this.with_rib(TypeNS, RibKind::Module(module), |this| {
-                    let ret = f(this);
-                    this.parent_scope.module = orig_module;
-                    ret
-                })
+    fn with_mod_rib<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
+        let module = self.r.expect_module(self.r.local_def_id(id).to_def_id());
+        // Move down in the graph.
+        let orig_module = replace(&mut self.parent_scope.module, module);
+        self.with_rib(ValueNS, RibKind::Module(module), |this| {
+            this.with_rib(TypeNS, RibKind::Module(module), |this| {
+                let ret = f(this);
+                this.parent_scope.module = orig_module;
+                ret
             })
-        } else {
-            f(self)
-        }
+        })
     }
 
     fn visit_generic_params(&mut self, params: &'ast [GenericParam], add_self_upper: bool) {
@@ -2738,7 +2735,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             }
 
             ItemKind::Mod(..) => {
-                self.with_scope(item.id, |this| {
+                self.with_mod_rib(item.id, |this| {
                     if mod_inner_docs {
                         this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
                     }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index c4304a7a6df..34441d313f5 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -28,7 +28,7 @@ use rustc_session::lint::builtin::{
     UNUSED_MACRO_RULES, UNUSED_MACROS,
 };
 use rustc_session::parse::feature_err;
-use rustc_span::edit_distance::edit_distance;
+use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{self, AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind};
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
@@ -652,13 +652,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
             && let [namespace, attribute, ..] = &*path.segments
             && namespace.ident.name == sym::diagnostic
-            && !(attribute.ident.name == sym::on_unimplemented
-                || attribute.ident.name == sym::do_not_recommend)
+            && ![sym::on_unimplemented, sym::do_not_recommend].contains(&attribute.ident.name)
         {
-            let distance =
-                edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5);
-
-            let typo_name = distance.map(|_| sym::on_unimplemented);
+            let typo_name = find_best_match_for_name(
+                &[sym::on_unimplemented, sym::do_not_recommend],
+                attribute.ident.name,
+                Some(5),
+            );
 
             self.tcx.sess.psess.buffer_lint(
                 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index e77caad6540..4644e37f809 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1149,9 +1149,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     ///
     /// [memory layout]: self#memory-layout
     #[unstable(feature = "allocator_api", issue = "32838")]
-    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
+    pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
     }
 
@@ -1203,9 +1202,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// [memory layout]: self#memory-layout
     #[unstable(feature = "allocator_api", issue = "32838")]
     // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
-    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub const unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
+    pub unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
         // SAFETY: guaranteed by the caller.
         unsafe { Box::from_raw_in(raw.as_ptr(), alloc) }
     }
@@ -1550,9 +1548,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This
     /// is so that there is no conflict with a method on the inner type.
     #[unstable(feature = "allocator_api", issue = "32838")]
-    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub const fn allocator(b: &Self) -> &A {
+    pub fn allocator(b: &Self) -> &A {
         &b.1
     }
 
@@ -1639,8 +1636,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// let bar = Pin::from(foo);
     /// ```
     #[stable(feature = "box_into_pin", since = "1.63.0")]
-    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
-    pub const fn into_pin(boxed: Self) -> Pin<Self>
+    pub fn into_pin(boxed: Self) -> Pin<Self>
     where
         A: 'static,
     {
diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs
index 54acd4c27b3..d6ae86bd3d2 100644
--- a/library/std/src/sys/fs/uefi.rs
+++ b/library/std/src/sys/fs/uefi.rs
@@ -1,3 +1,5 @@
+use r_efi::protocols::file;
+
 use crate::ffi::OsString;
 use crate::fmt;
 use crate::hash::Hash;
@@ -22,7 +24,12 @@ pub struct ReadDir(!);
 pub struct DirEntry(!);
 
 #[derive(Clone, Debug)]
-pub struct OpenOptions {}
+pub struct OpenOptions {
+    mode: u64,
+    append: bool,
+    truncate: bool,
+    create_new: bool,
+}
 
 #[derive(Copy, Clone, Debug, Default)]
 pub struct FileTimes {}
@@ -141,15 +148,58 @@ impl DirEntry {
 
 impl OpenOptions {
     pub fn new() -> OpenOptions {
-        OpenOptions {}
+        OpenOptions { mode: 0, append: false, create_new: false, truncate: false }
+    }
+
+    pub fn read(&mut self, read: bool) {
+        if read {
+            self.mode |= file::MODE_READ;
+        } else {
+            self.mode &= !file::MODE_READ;
+        }
+    }
+
+    pub fn write(&mut self, write: bool) {
+        if write {
+            // Valid Combinations: Read, Read/Write, Read/Write/Create
+            self.read(true);
+            self.mode |= file::MODE_WRITE;
+        } else {
+            self.mode &= !file::MODE_WRITE;
+        }
+    }
+
+    pub fn append(&mut self, append: bool) {
+        // Docs state that `.write(true).append(true)` has the same effect as `.append(true)`
+        if append {
+            self.write(true);
+        }
+        self.append = append;
     }
 
-    pub fn read(&mut self, _read: bool) {}
-    pub fn write(&mut self, _write: bool) {}
-    pub fn append(&mut self, _append: bool) {}
-    pub fn truncate(&mut self, _truncate: bool) {}
-    pub fn create(&mut self, _create: bool) {}
-    pub fn create_new(&mut self, _create_new: bool) {}
+    pub fn truncate(&mut self, truncate: bool) {
+        self.truncate = truncate;
+    }
+
+    pub fn create(&mut self, create: bool) {
+        if create {
+            self.mode |= file::MODE_CREATE;
+        } else {
+            self.mode &= !file::MODE_CREATE;
+        }
+    }
+
+    pub fn create_new(&mut self, create_new: bool) {
+        self.create_new = create_new;
+    }
+
+    #[expect(dead_code)]
+    const fn is_mode_valid(&self) -> bool {
+        // Valid Combinations: Read, Read/Write, Read/Write/Create
+        self.mode == file::MODE_READ
+            || self.mode == (file::MODE_READ | file::MODE_WRITE)
+            || self.mode == (file::MODE_READ | file::MODE_WRITE | file::MODE_CREATE)
+    }
 }
 
 impl File {
@@ -311,12 +361,12 @@ pub fn stat(_p: &Path) -> io::Result<FileAttr> {
     unsupported()
 }
 
-pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
-    unsupported()
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+    stat(p)
 }
 
-pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
-    unsupported()
+pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+    crate::path::absolute(p)
 }
 
 pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
diff --git a/src/doc/book b/src/doc/book
-Subproject 81a976a237f84b8392c4ce1bd5fd076eb757a2e
+Subproject 45f05367360f033f89235eacbbb54e8d73ce6b7
diff --git a/src/doc/reference b/src/doc/reference
-Subproject dda31c85f2ef2e5d2f0f2f643c9231690a30a62
+Subproject e95ebdfee02514d93f79ec92ae310a804e87f01
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 542ee9fffce..e258b0a76ff 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -2,6 +2,7 @@
 
 - [What is rustc?](what-is-rustc.md)
 - [Command-line Arguments](command-line-arguments.md)
+    - [Print Options](command-line-arguments/print-options.md)
     - [Codegen Options](codegen-options/index.md)
 - [Jobserver](jobserver.md)
 - [Lints](lints/index.md)
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 9dd2e7de1b3..b704cee705b 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -247,58 +247,7 @@ types to stdout at the same time will result in an error.
 <a id="option-print"></a>
 ## `--print`: print compiler information
 
-This flag prints out various information about the compiler. This flag may be
-specified multiple times, and the information is printed in the order the
-flags are specified. Specifying a `--print` flag will usually disable the
-[`--emit`](#option-emit) step and will only print the requested information.
-The valid types of print values are:
-
-- `crate-name` — The name of the crate.
-- `file-names` — The names of the files created by the `link` emit kind.
-- `sysroot` — Path to the sysroot.
-- `target-libdir` — Path to the target libdir.
-- `host-tuple` — The target-tuple string of the host compiler (e.g. `x86_64-unknown-linux-gnu`)
-- `cfg` — List of cfg values. See [conditional compilation] for more
-  information about cfg values.
-- `target-list` — List of known targets. The target may be selected with the
-  `--target` flag.
-- `target-cpus` — List of available CPU values for the current target. The
-  target CPU may be selected with the [`-C target-cpu=val`
-  flag](codegen-options/index.md#target-cpu).
-- `target-features` — List of available target features for the current
-  target. Target features may be enabled with the [`-C target-feature=val`
-  flag](codegen-options/index.md#target-feature).  This flag is unsafe. See
-  [known issues](targets/known-issues.md) for more details.
-- `relocation-models` — List of relocation models. Relocation models may be
-  selected with the [`-C relocation-model=val`
-  flag](codegen-options/index.md#relocation-model).
-- `code-models` — List of code models. Code models may be selected with the
-  [`-C code-model=val` flag](codegen-options/index.md#code-model).
-- `tls-models` — List of Thread Local Storage models supported. The model may
-  be selected with the `-Z tls-model=val` flag.
-- `native-static-libs` — This may be used when creating a `staticlib` crate
-  type. If this is the only flag, it will perform a full compilation and
-  include a diagnostic note that indicates the linker flags to use when
-  linking the resulting static library. The note starts with the text
-  `native-static-libs:` to make it easier to fetch the output.
-- `link-args` — This flag does not disable the `--emit` step. When linking,
-  this flag causes `rustc` to print the full linker invocation in a
-  human-readable form. This can be useful when debugging linker options. The
-  exact format of this debugging output is not a stable guarantee, other than
-  that it will include the linker executable and the text of each command-line
-  argument passed to the linker.
-- `deployment-target` — The currently selected [deployment target] (or minimum OS version)
-  for the selected Apple platform target. This value can be used or passed along to other
-  components alongside a Rust build that need this information, such as C compilers.
-  This returns rustc's minimum supported deployment target if no `*_DEPLOYMENT_TARGET` variable
-  is present in the environment, or otherwise returns the variable's parsed value.
-
-A filepath may optionally be specified for each requested information kind, in
-the format `--print KIND=PATH`, just like for `--emit`. When a path is
-specified, information will be written there instead of to stdout.
-
-[conditional compilation]: ../reference/conditional-compilation.html
-[deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html
+This flag will allow you to set [print options](command-line-arguments/print-options.md).
 
 <a id="option-g-debug"></a>
 ## `-g`: include debug information
diff --git a/src/doc/rustc/src/command-line-arguments/print-options.md b/src/doc/rustc/src/command-line-arguments/print-options.md
new file mode 100644
index 00000000000..1f33e91e5d1
--- /dev/null
+++ b/src/doc/rustc/src/command-line-arguments/print-options.md
@@ -0,0 +1,212 @@
+# Print Options
+
+All of these options are passed to `rustc` via the `--print` flag.
+
+Those options prints out various information about the compiler. Multiple options can be
+specified, and the information is printed in the order the options are specified.
+
+Specifying an option will usually disable the [`--emit`](../command-line-arguments.md#option-emit)
+step and will only print the requested information.
+
+A filepath may optionally be specified for each requested information kind, in the format
+`--print KIND=PATH`, just like for `--emit`. When a path is specified, information will be
+written there instead of to stdout.
+
+## `crate-name`
+
+The name of the crate.
+
+Generally coming from either from the `#![crate_name = "..."]` attribute,
+[`--crate-name` flag](../command-line-arguments.md#option-crate-name) or the filename.
+
+Example:
+
+```bash
+$ rustc --print crate-name --crate-name my_crate a.rs
+my_crate
+```
+
+## `file-names`
+
+The names of the files created by the `link` emit kind.
+
+## `sysroot`
+
+Abosulte path to the sysroot.
+
+Example (with rustup and the stable toolchain):
+
+```bash
+$ rustc --print sysroot a.rs
+/home/[REDACTED]/.rustup/toolchains/stable-x86_64-unknown-linux-gnu
+```
+
+## `target-libdir`
+
+Path to the target libdir.
+
+Example (with rustup and the stable toolchain):
+
+```bash
+$ rustc --print target-libdir a.rs
+/home/[REDACTED]/.rustup/toolchains/beta-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib
+```
+
+## `host-tuple`
+
+The target-tuple string of the host compiler.
+
+Example:
+
+```bash
+$ rustc --print host-tuple a.rs
+x86_64-unknown-linux-gnu
+```
+
+Example with the `--target` flag:
+
+```bash
+$ rustc --print host-tuple --target "armv7-unknown-linux-gnueabihf" a.rs
+x86_64-unknown-linux-gnu
+```
+
+## `cfg`
+
+List of cfg values. See [conditional compilation] for more information about cfg values.
+
+Example (for `x86_64-unknown-linux-gnu`):
+
+```bash
+$ rustc --print cfg a.rs
+debug_assertions
+panic="unwind"
+target_abi=""
+target_arch="x86_64"
+target_endian="little"
+target_env="gnu"
+target_family="unix"
+target_feature="fxsr"
+target_feature="sse"
+target_feature="sse2"
+target_has_atomic="16"
+target_has_atomic="32"
+target_has_atomic="64"
+target_has_atomic="8"
+target_has_atomic="ptr"
+target_os="linux"
+target_pointer_width="64"
+target_vendor="unknown"
+unix
+```
+
+## `target-list`
+
+List of known targets. The target may be selected with the `--target` flag.
+
+## `target-cpus`
+
+List of available CPU values for the current target. The target CPU may be selected with
+the [`-C target-cpu=val` flag](../codegen-options/index.md#target-cpu).
+
+## `target-features`
+
+List of available target features for the *current target*.
+
+Target features may be enabled with the **unsafe**
+[`-C target-feature=val` flag](../codegen-options/index.md#target-feature).
+
+See [known issues](../targets/known-issues.md) for more details.
+
+## `relocation-models`
+
+List of relocation models. Relocation models may be selected with the
+[`-C relocation-model=val` flag](../codegen-options/index.md#relocation-model).
+
+Example:
+
+```bash
+$ rustc --print relocation-models a.rs
+Available relocation models:
+    static
+    pic
+    pie
+    dynamic-no-pic
+    ropi
+    rwpi
+    ropi-rwpi
+    default
+```
+
+## `code-models`
+
+List of code models. Code models may be selected with the
+[`-C code-model=val` flag](../codegen-options/index.md#code-model).
+
+Example:
+
+```bash
+$ rustc --print code-models a.rs
+Available code models:
+    tiny
+    small
+    kernel
+    medium
+    large
+```
+
+## `tls-models`
+
+List of Thread Local Storage models supported. The model may be selected with the
+`-Z tls-model=val` flag.
+
+Example:
+
+```bash
+$ rustc --print tls-models a.rs
+Available TLS models:
+    global-dynamic
+    local-dynamic
+    initial-exec
+    local-exec
+    emulated
+```
+
+## `native-static-libs`
+
+This may be used when creating a `staticlib` crate type.
+
+If this is the only flag, it will perform a full compilation and include a diagnostic note
+that indicates the linker flags to use when linking the resulting static library.
+
+The note starts with the text `native-static-libs:` to make it easier to fetch the output.
+
+Example:
+
+```bash
+$ rustc --print native-static-libs --crate-type staticlib a.rs
+note: Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
+
+note: native-static-libs: -lgcc_s -lutil [REDACTED] -lpthread -lm -ldl -lc
+```
+
+## `link-args`
+
+This flag does not disable the `--emit` step. This can be useful when debugging linker options.
+
+When linking, this flag causes `rustc` to print the full linker invocation in a human-readable
+form. The exact format of this debugging output is not a stable guarantee, other than that it
+will include the linker executable and the text of each command-line argument passed to the
+linker.
+
+## `deployment-target`
+
+The currently selected [deployment target] (or minimum OS version) for the selected Apple
+platform target.
+
+This value can be used or passed along to other components alongside a Rust build that need
+this information, such as C compilers. This returns rustc's minimum supported deployment target
+if no `*_DEPLOYMENT_TARGET` variable is present in the environment, or otherwise returns the
+variable's parsed value.
+
+[conditional compilation]: ../../reference/conditional-compilation.html
+[deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html
diff --git a/tests/ui/diagnostic_namespace/suggest_typos.rs b/tests/ui/diagnostic_namespace/suggest_typos.rs
index 6fa4f800462..8d1dc6f59da 100644
--- a/tests/ui/diagnostic_namespace/suggest_typos.rs
+++ b/tests/ui/diagnostic_namespace/suggest_typos.rs
@@ -16,4 +16,9 @@ trait Y{}
 //~^^HELP an attribute with a similar name exists
 trait Z{}
 
+#[diagnostic::dont_recommend]
+//~^ERROR unknown diagnostic attribute
+//~^^HELP an attribute with a similar name exists
+impl X for u8 {}
+
 fn main(){}
diff --git a/tests/ui/diagnostic_namespace/suggest_typos.stderr b/tests/ui/diagnostic_namespace/suggest_typos.stderr
index 86d778c6ec0..1f19fd4bbcf 100644
--- a/tests/ui/diagnostic_namespace/suggest_typos.stderr
+++ b/tests/ui/diagnostic_namespace/suggest_typos.stderr
@@ -37,5 +37,17 @@ help: an attribute with a similar name exists
 LL | #[diagnostic::on_unimplemented]
    |                  ++
 
-error: aborting due to 3 previous errors
+error: unknown diagnostic attribute
+  --> $DIR/suggest_typos.rs:19:15
+   |
+LL | #[diagnostic::dont_recommend]
+   |               ^^^^^^^^^^^^^^
+   |
+help: an attribute with a similar name exists
+   |
+LL - #[diagnostic::dont_recommend]
+LL + #[diagnostic::do_not_recommend]
+   |
+
+error: aborting due to 4 previous errors