about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs3
-rw-r--r--compiler/rustc_ast/src/token.rs7
-rw-r--r--compiler/rustc_ast/src/util/literal.rs63
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs4
-rw-r--r--compiler/rustc_attr/src/builtin.rs39
-rw-r--r--compiler/rustc_builtin_macros/src/concat.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs5
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs9
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs6
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs4
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs5
-rw-r--r--compiler/rustc_interface/src/interface.rs76
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_lexer/src/lib.rs90
-rw-r--r--compiler/rustc_lexer/src/unescape.rs278
-rw-r--r--compiler/rustc_lint/src/builtin.rs20
-rw-r--r--compiler/rustc_lint/src/context.rs70
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp17
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs18
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs6
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs63
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs22
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs1
-rw-r--r--compiler/rustc_session/messages.ftl2
-rw-r--r--compiler/rustc_session/src/config.rs233
-rw-r--r--compiler/rustc_session/src/errors.rs15
-rw-r--r--compiler/rustc_session/src/options.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/alloc/src/collections/btree/map.rs4
-rw-r--r--library/alloc/src/collections/btree/map/tests.rs19
-rw-r--r--library/core/src/ffi/c_str.rs2
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/ptr/mod.rs14
-rw-r--r--library/proc_macro/src/bridge/mod.rs4
-rw-r--r--library/std/src/sys/hermit/time.rs12
-rw-r--r--library/std/src/sys/sgx/abi/entry.S6
-rw-r--r--library/std/src/sys/solid/time.rs4
-rw-r--r--library/std/src/sys/unix/thread.rs19
-rw-r--r--library/std/src/sys/unix/time.rs16
-rw-r--r--library/std/src/time/tests.rs27
-rw-r--r--src/doc/rustc/src/codegen-options/index.md11
-rw-r--r--src/doc/unstable-book/src/language-features/raw-dylib.md34
-rw-r--r--src/librustdoc/html/highlight.rs4
-rw-r--r--src/librustdoc/html/render/search_index.rs30
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs1
-rw-r--r--src/tools/compiletest/src/header/needs.rs36
-rw-r--r--src/tools/compiletest/src/runtest.rs87
-rw-r--r--src/tools/miropt-test-tools/src/lib.rs19
-rw-r--r--tests/codegen/align-offset.rs78
-rw-r--r--tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir32
-rw-r--r--tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir36
-rw-r--r--tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir30
-rw-r--r--tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir32
-rw-r--r--tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir16
-rw-r--r--tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir14
-rw-r--r--tests/run-make/raw-dylib-alt-calling-convention/lib.rs1
-rw-r--r--tests/run-make/raw-dylib-c/lib.rs2
-rw-r--r--tests/run-make/raw-dylib-cross-compilation/lib.rs1
-rw-r--r--tests/run-make/raw-dylib-custom-dlltool/Makefile11
-rw-r--r--tests/run-make/raw-dylib-custom-dlltool/lib.rs10
-rw-r--r--tests/run-make/raw-dylib-custom-dlltool/output.txt1
-rw-r--r--tests/run-make/raw-dylib-custom-dlltool/script.cmd2
-rw-r--r--tests/run-make/raw-dylib-import-name-type/driver.rs1
-rw-r--r--tests/run-make/raw-dylib-inline-cross-dylib/driver.rs2
-rw-r--r--tests/run-make/raw-dylib-inline-cross-dylib/lib.rs2
-rw-r--r--tests/run-make/raw-dylib-link-ordinal/lib.rs2
-rw-r--r--tests/run-make/raw-dylib-stdcall-ordinal/lib.rs2
-rw-r--r--tests/rustdoc-js/slice-array.js65
-rw-r--r--tests/rustdoc-js/slice-array.rs16
-rw-r--r--tests/rustdoc-ui/check-cfg/check-cfg.stderr2
-rw-r--r--tests/rustdoc-ui/doctest/check-cfg-test.stderr2
-rw-r--r--tests/ui/check-cfg/compact-values.stderr2
-rw-r--r--tests/ui/check-cfg/diagnotics.rs31
-rw-r--r--tests/ui/check-cfg/diagnotics.stderr62
-rw-r--r--tests/ui/check-cfg/invalid-cfg-name.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-cfg-value.stderr6
-rw-r--r--tests/ui/check-cfg/mix.rs4
-rw-r--r--tests/ui/check-cfg/mix.stderr82
-rw-r--r--tests/ui/check-cfg/no-values.stderr4
-rw-r--r--tests/ui/check-cfg/values-target-json.stderr4
-rw-r--r--tests/ui/check-cfg/well-known-names.stderr6
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr8
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib-2.rs12
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr21
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs8
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr21
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib.rs7
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib.stderr12
-rw-r--r--tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs19
-rw-r--r--tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr5
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs13
-rw-r--r--tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr8
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr6
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs1
-rw-r--r--tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs1
-rw-r--r--tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr2
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs7
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs13
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr21
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rsbin0 -> 565 bytes
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderrbin0 -> 674 bytes
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs10
-rw-r--r--tests/ui/specialization/issue-111232.rs11
-rw-r--r--tests/ui/specialization/issue-111232.stderr11
142 files changed, 1554 insertions, 755 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index b5dba0713bf..e3ac8a8784a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1821,6 +1821,8 @@ pub enum LitKind {
     /// A byte string (`b"foo"`). Not stored as a symbol because it might be
     /// non-utf8, and symbols only allow utf8 strings.
     ByteStr(Lrc<[u8]>, StrStyle),
+    /// A C String (`c"foo"`). Guaranteed to only have `\0` at the end.
+    CStr(Lrc<[u8]>, StrStyle),
     /// A byte char (`b'f'`).
     Byte(u8),
     /// A character literal (`'a'`).
@@ -1875,6 +1877,7 @@ impl LitKind {
             // unsuffixed variants
             LitKind::Str(..)
             | LitKind::ByteStr(..)
+            | LitKind::CStr(..)
             | LitKind::Byte(..)
             | LitKind::Char(..)
             | LitKind::Int(_, LitIntType::Unsuffixed)
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index f947ae4d057..42b843482a3 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -74,6 +74,8 @@ pub enum LitKind {
     StrRaw(u8), // raw string delimited by `n` hash symbols
     ByteStr,
     ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols
+    CStr,
+    CStrRaw(u8),
     Err,
 }
 
@@ -141,6 +143,10 @@ impl fmt::Display for Lit {
                 delim = "#".repeat(n as usize),
                 string = symbol
             )?,
+            CStr => write!(f, "c\"{symbol}\"")?,
+            CStrRaw(n) => {
+                write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))?
+            }
             Integer | Float | Bool | Err => write!(f, "{symbol}")?,
         }
 
@@ -170,6 +176,7 @@ impl LitKind {
             Float => "float",
             Str | StrRaw(..) => "string",
             ByteStr | ByteStrRaw(..) => "byte string",
+            CStr | CStrRaw(..) => "C string",
             Err => "error",
         }
     }
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 74b842ac96e..15a54fe13d0 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -2,9 +2,13 @@
 
 use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
 use crate::token::{self, Token};
-use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};
+use rustc_lexer::unescape::{
+    byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit,
+    Mode,
+};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
+use std::ops::Range;
 use std::{ascii, fmt, str};
 
 // Escapes a string, represented as a symbol. Reuses the original symbol,
@@ -35,6 +39,7 @@ pub enum LitError {
     InvalidFloatSuffix,
     NonDecimalFloat(u32),
     IntTooLarge(u32),
+    NulInCStr(Range<usize>),
 }
 
 impl LitKind {
@@ -158,6 +163,52 @@ impl LitKind {
 
                 LitKind::ByteStr(bytes.into(), StrStyle::Raw(n))
             }
+            token::CStr => {
+                let s = symbol.as_str();
+                let mut buf = Vec::with_capacity(s.len());
+                let mut error = Ok(());
+                unescape_c_string(s, Mode::CStr, &mut |span, c| match c {
+                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
+                        error = Err(LitError::NulInCStr(span));
+                    }
+                    Ok(CStrUnit::Byte(b)) => buf.push(b),
+                    Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),
+                    Ok(CStrUnit::Char(c)) => {
+                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+                    }
+                    Err(err) => {
+                        if err.is_fatal() {
+                            error = Err(LitError::LexerError);
+                        }
+                    }
+                });
+                error?;
+                buf.push(0);
+                LitKind::CStr(buf.into(), StrStyle::Cooked)
+            }
+            token::CStrRaw(n) => {
+                let s = symbol.as_str();
+                let mut buf = Vec::with_capacity(s.len());
+                let mut error = Ok(());
+                unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {
+                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
+                        error = Err(LitError::NulInCStr(span));
+                    }
+                    Ok(CStrUnit::Byte(b)) => buf.push(b),
+                    Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),
+                    Ok(CStrUnit::Char(c)) => {
+                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+                    }
+                    Err(err) => {
+                        if err.is_fatal() {
+                            error = Err(LitError::LexerError);
+                        }
+                    }
+                });
+                error?;
+                buf.push(0);
+                LitKind::CStr(buf.into(), StrStyle::Raw(n))
+            }
             token::Err => LitKind::Err,
         })
     }
@@ -191,6 +242,14 @@ impl fmt::Display for LitKind {
                     string = symbol
                 )?;
             }
+            LitKind::CStr(ref bytes, StrStyle::Cooked) => {
+                write!(f, "c\"{}\"", escape_byte_str_symbol(bytes))?
+            }
+            LitKind::CStr(ref bytes, StrStyle::Raw(n)) => {
+                // This can only be valid UTF-8.
+                let symbol = str::from_utf8(bytes).unwrap();
+                write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?;
+            }
             LitKind::Int(n, ty) => {
                 write!(f, "{n}")?;
                 match ty {
@@ -237,6 +296,8 @@ impl MetaItemLit {
             LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n),
             LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr,
             LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n),
+            LitKind::CStr(_, ast::StrStyle::Cooked) => token::CStr,
+            LitKind::CStr(_, ast::StrStyle::Raw(n)) => token::CStrRaw(n),
             LitKind::Byte(_) => token::Byte,
             LitKind::Char(_) => token::Char,
             LitKind::Int(..) => token::Integer,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index a46fe9e898f..b960671bf6e 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -572,6 +572,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
             }
         };
     }
+    gate_all!(c_str_literals, "`c\"..\"` literals are experimental");
     gate_all!(
         if_let_guard,
         "`if let` guards are experimental",
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index ae346510ccc..3f80728a260 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -210,6 +210,10 @@ pub fn literal_to_string(lit: token::Lit) -> String {
         token::ByteStrRaw(n) => {
             format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
         }
+        token::CStr => format!("c\"{symbol}\""),
+        token::CStrRaw(n) => {
+            format!("cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))
+        }
         token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
     };
 
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index d2d3792345f..2a3092d3c7b 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -5,6 +5,7 @@ use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedM
 use rustc_ast_pretty::pprust;
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
 use rustc_macros::HashStable_Generic;
+use rustc_session::config::ExpectedValues;
 use rustc_session::lint::builtin::UNEXPECTED_CFGS;
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::parse::{feature_err, ParseSess};
@@ -581,32 +582,32 @@ pub fn cfg_matches(
 ) -> bool {
     eval_condition(cfg, sess, features, &mut |cfg| {
         try_gate_cfg(cfg.name, cfg.span, sess, features);
-        if let Some(names_valid) = &sess.check_config.names_valid {
-            if !names_valid.contains(&cfg.name) {
+        match sess.check_config.expecteds.get(&cfg.name) {
+            Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
                 sess.buffer_lint_with_diagnostic(
                     UNEXPECTED_CFGS,
                     cfg.span,
                     lint_node_id,
-                    "unexpected `cfg` condition name",
-                    BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None),
+                    "unexpected `cfg` condition value",
+                    BuiltinLintDiagnostics::UnexpectedCfgValue(
+                        (cfg.name, cfg.name_span),
+                        cfg.value.map(|v| (v, cfg.value_span.unwrap())),
+                    ),
                 );
             }
-        }
-        if let Some(value) = cfg.value {
-            if let Some(values) = &sess.check_config.values_valid.get(&cfg.name) {
-                if !values.contains(&value) {
-                    sess.buffer_lint_with_diagnostic(
-                        UNEXPECTED_CFGS,
-                        cfg.span,
-                        lint_node_id,
-                        "unexpected `cfg` condition value",
-                        BuiltinLintDiagnostics::UnexpectedCfg(
-                            (cfg.name, cfg.name_span),
-                            cfg.value_span.map(|vs| (value, vs)),
-                        ),
-                    );
-                }
+            None if sess.check_config.exhaustive_names => {
+                sess.buffer_lint_with_diagnostic(
+                    UNEXPECTED_CFGS,
+                    cfg.span,
+                    lint_node_id,
+                    "unexpected `cfg` condition name",
+                    BuiltinLintDiagnostics::UnexpectedCfgName(
+                        (cfg.name, cfg.name_span),
+                        cfg.value.map(|v| (v, cfg.value_span.unwrap())),
+                    ),
+                );
             }
+            _ => { /* not unexpected */ }
         }
         sess.config.contains(&(cfg.name, cfg.value))
     })
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index b92964d03e9..50e88ae2eee 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -32,6 +32,10 @@ pub fn expand_concat(
                 Ok(ast::LitKind::Bool(b)) => {
                     accumulator.push_str(&b.to_string());
                 }
+                Ok(ast::LitKind::CStr(..)) => {
+                    cx.span_err(e.span, "cannot concatenate a C string literal");
+                    has_errors = true;
+                }
                 Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
                     cx.emit_err(errors::ConcatBytestr { span: e.span });
                     has_errors = true;
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index ba639c0a9fe..5ef35af0a05 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -18,6 +18,11 @@ fn invalid_type_err(
     };
     let snippet = cx.sess.source_map().span_to_snippet(span).ok();
     match ast::LitKind::from_token_lit(token_lit) {
+        Ok(ast::LitKind::CStr(_, _)) => {
+            // FIXME(c_str_literals): should concatenation of C string literals
+            // include the null bytes in the end?
+            cx.span_err(span, "cannot concatenate C string literals");
+        }
         Ok(ast::LitKind::Char(_)) => {
             let sugg =
                 snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index b6d7484bcce..2e3adc08669 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -24,7 +24,7 @@ codegen_llvm_error_writing_def_file =
     Error writing .DEF file: {$error}
 
 codegen_llvm_error_calling_dlltool =
-    Error calling dlltool: {$error}
+    Error calling dlltool '{$dlltool_path}': {$error}
 
 codegen_llvm_dlltool_fail_import_library =
     Dlltool could not create import library: {$stdout}
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 12da21dc477..a6416e9540c 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -198,7 +198,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                 "arm" => ("arm", "--32"),
                 _ => panic!("unsupported arch {}", sess.target.arch),
             };
-            let result = std::process::Command::new(dlltool)
+            let result = std::process::Command::new(&dlltool)
                 .args([
                     "-d",
                     def_file_path.to_str().unwrap(),
@@ -218,9 +218,13 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
 
             match result {
                 Err(e) => {
-                    sess.emit_fatal(ErrorCallingDllTool { error: e });
+                    sess.emit_fatal(ErrorCallingDllTool {
+                        dlltool_path: dlltool.to_string_lossy(),
+                        error: e,
+                    });
                 }
-                Ok(output) if !output.status.success() => {
+                // dlltool returns '0' on failure, so check for error output instead.
+                Ok(output) if !output.stderr.is_empty() => {
                     sess.emit_fatal(DlltoolFailImportLibrary {
                         stdout: String::from_utf8_lossy(&output.stdout),
                         stderr: String::from_utf8_lossy(&output.stderr),
@@ -431,7 +435,7 @@ fn string_to_io_error(s: String) -> io::Error {
 
 fn find_binutils_dlltool(sess: &Session) -> OsString {
     assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
-    if let Some(dlltool_path) = &sess.opts.unstable_opts.dlltool {
+    if let Some(dlltool_path) = &sess.opts.cg.dlltool {
         return dlltool_path.clone().into_os_string();
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index bae88d94293..672087de315 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -67,7 +67,8 @@ pub(crate) struct ErrorWritingDEFFile {
 
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_error_calling_dlltool)]
-pub(crate) struct ErrorCallingDllTool {
+pub(crate) struct ErrorCallingDllTool<'a> {
+    pub dlltool_path: Cow<'a, str>,
     pub error: std::io::Error,
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index c95148013eb..53d97f35201 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2249,7 +2249,7 @@ extern "C" {
 
     pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
 
-    pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine);
+    pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine, cpu: *const c_char);
     pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t;
     pub fn LLVMRustGetTargetFeature(
         T: &TargetMachine,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 46692fd5e8b..2fbdab9f8ce 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -329,7 +329,14 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) {
     require_inited();
     let tm = create_informational_target_machine(sess);
     match req {
-        PrintRequest::TargetCPUs => unsafe { llvm::LLVMRustPrintTargetCPUs(tm) },
+        PrintRequest::TargetCPUs => {
+            // SAFETY generate a C compatible string from a byte slice to pass
+            // the target CPU name into LLVM, the lifetime of the reference is
+            // at least as long as the C function
+            let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref()))
+                .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e));
+            unsafe { llvm::LLVMRustPrintTargetCPUs(tm, cpu_cstring.as_ptr()) };
+        }
         PrintRequest::TargetFeatures => print_target_features(sess, tm),
         _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
     }
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 5cc87d1e56c..8dae5dab429 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -592,15 +592,6 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 
 fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
     use rustc_ast::{LitIntType, LitKind, MetaItemLit};
-    if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
-        feature_err(
-            &tcx.sess.parse_sess,
-            sym::raw_dylib,
-            attr.span,
-            "`#[link_ordinal]` is unstable on x86",
-        )
-        .emit();
-    }
     let meta_item_list = attr.meta_item_list();
     let meta_item_list = meta_item_list.as_deref();
     let sole_meta_list = match meta_item_list {
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 1e7d07bc22d..891e84a2f30 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -61,6 +61,8 @@ impl FromInternal<token::LitKind> for LitKind {
             token::StrRaw(n) => LitKind::StrRaw(n),
             token::ByteStr => LitKind::ByteStr,
             token::ByteStrRaw(n) => LitKind::ByteStrRaw(n),
+            token::CStr => LitKind::CStr,
+            token::CStrRaw(n) => LitKind::CStrRaw(n),
             token::Err => LitKind::Err,
             token::Bool => unreachable!(),
         }
@@ -78,6 +80,8 @@ impl ToInternal<token::LitKind> for LitKind {
             LitKind::StrRaw(n) => token::StrRaw(n),
             LitKind::ByteStr => token::ByteStr,
             LitKind::ByteStrRaw(n) => token::ByteStrRaw(n),
+            LitKind::CStr => token::CStr,
+            LitKind::CStrRaw(n) => token::CStrRaw(n),
             LitKind::Err => token::Err,
         }
     }
@@ -436,6 +440,8 @@ impl server::FreeFunctions for Rustc<'_, '_> {
                 | token::LitKind::StrRaw(_)
                 | token::LitKind::ByteStr
                 | token::LitKind::ByteStrRaw(_)
+                | token::LitKind::CStr
+                | token::LitKind::CStrRaw(_)
                 | token::LitKind::Err => return Err(()),
                 token::LitKind::Integer | token::LitKind::Float => {}
             }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 70d608a5ea4..5b2e4d15dfe 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -280,6 +280,8 @@ declare_features! (
     (accepted, pub_restricted, "1.18.0", Some(32409), None),
     /// Allows use of the postfix `?` operator in expressions.
     (accepted, question_mark, "1.13.0", Some(31436), None),
+    /// Allows the use of raw-dylibs (RFC 2627).
+    (accepted, raw_dylib, "CURRENT_RUSTC_VERSION", Some(58713), None),
     /// Allows keywords to be escaped for use as identifiers.
     (accepted, raw_identifiers, "1.30.0", Some(48589), None),
     /// Allows relaxing the coherence rules such that
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index dc5dc4608a0..27d30c315af 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -313,6 +313,8 @@ declare_features! (
     (active, async_closure, "1.37.0", Some(62290), None),
     /// Allows async functions to be declared, implemented, and used in traits.
     (active, async_fn_in_trait, "1.66.0", Some(91611), None),
+    /// Allows `c"foo"` literals.
+    (active, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723), None),
     /// Treat `extern "C"` function as nounwind.
     (active, c_unwind, "1.52.0", Some(74990), None),
     /// Allows using C-variadics.
@@ -487,8 +489,6 @@ declare_features! (
     (active, precise_pointer_size_matching, "1.32.0", Some(56354), None),
     /// Allows macro attributes on expressions, statements and non-inline modules.
     (active, proc_macro_hygiene, "1.30.0", Some(54727), None),
-    /// Allows the use of raw-dylibs (RFC 2627).
-    (active, raw_dylib, "1.65.0", Some(58713), None),
     /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
     (active, raw_ref_op, "1.41.0", Some(64490), None),
     /// Allows using the `#[register_tool]` attribute.
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 0a8bd1d6123..1f08befb180 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -333,6 +333,7 @@ language_item_table! {
     RangeTo,                 sym::RangeTo,             range_to_struct,            Target::Struct,         GenericRequirement::None;
 
     String,                  sym::String,              string,                     Target::Struct,         GenericRequirement::None;
+    CStr,                    sym::CStr,                c_str,                      Target::Struct,         GenericRequirement::None;
 }
 
 pub enum GenericRequirement {
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index c0ee777722e..30e2c675f59 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -657,7 +657,6 @@ pub enum ImplNotMarkedDefault {
     #[note]
     Err {
         #[primary_span]
-        #[label]
         span: Span,
         cname: Symbol,
         ident: Symbol,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 78bd489a44b..4b8fc7303a2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1300,6 +1300,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 opt_ty.unwrap_or_else(|| self.next_float_var())
             }
             ast::LitKind::Bool(_) => tcx.types.bool,
+            ast::LitKind::CStr(_, _) => tcx.mk_imm_ref(
+                tcx.lifetimes.re_static,
+                tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span)))
+                    .skip_binder(),
+            ),
             ast::LitKind::Err => tcx.ty_error_misc(),
         }
     }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 8e9150ba8ad..9d9f4ee13f4 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -9,11 +9,12 @@ use rustc_data_structures::OnDrop;
 use rustc_errors::registry::Registry;
 use rustc_errors::{ErrorGuaranteed, Handler};
 use rustc_lint::LintStore;
-use rustc_middle::ty;
+use rustc_middle::{bug, ty};
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_query_impl::QueryCtxt;
 use rustc_query_system::query::print_query_stack;
-use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames};
+use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
+use rustc_session::config::{CheckCfg, ExpectedValues};
 use rustc_session::lint;
 use rustc_session::parse::{CrateConfig, ParseSess};
 use rustc_session::Session;
@@ -121,9 +122,9 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
 /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
 pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
     rustc_span::create_default_session_if_not_set_then(move |_| {
-        let mut cfg = CheckCfg::default();
+        let mut check_cfg = CheckCfg::default();
 
-        'specs: for s in specs {
+        for s in specs {
             let sess = ParseSess::with_silent_emitter(Some(format!(
                 "this error occurred on the command line: `--check-cfg={s}`"
             )));
@@ -137,40 +138,54 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
                             concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
                             s
                         ),
-                    );
+                    )
                 };
             }
 
+            let expected_error = || {
+                error!(
+                    "expected `names(name1, name2, ... nameN)` or \
+                        `values(name, \"value1\", \"value2\", ... \"valueN\")`"
+                )
+            };
+
             match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
                 Ok(mut parser) => match parser.parse_meta_item() {
                     Ok(meta_item) if parser.token == token::Eof => {
                         if let Some(args) = meta_item.meta_item_list() {
                             if meta_item.has_name(sym::names) {
-                                let names_valid =
-                                    cfg.names_valid.get_or_insert_with(|| FxHashSet::default());
+                                check_cfg.exhaustive_names = true;
                                 for arg in args {
                                     if arg.is_word() && arg.ident().is_some() {
                                         let ident = arg.ident().expect("multi-segment cfg key");
-                                        names_valid.insert(ident.name.to_string());
+                                        check_cfg
+                                            .expecteds
+                                            .entry(ident.name.to_string())
+                                            .or_insert(ExpectedValues::Any);
                                     } else {
                                         error!("`names()` arguments must be simple identifiers");
                                     }
                                 }
-                                continue 'specs;
                             } else if meta_item.has_name(sym::values) {
                                 if let Some((name, values)) = args.split_first() {
                                     if name.is_word() && name.ident().is_some() {
                                         let ident = name.ident().expect("multi-segment cfg key");
-                                        let ident_values = cfg
-                                            .values_valid
+                                        let expected_values = check_cfg
+                                            .expecteds
                                             .entry(ident.name.to_string())
-                                            .or_insert_with(|| FxHashSet::default());
+                                            .or_insert_with(|| {
+                                                ExpectedValues::Some(FxHashSet::default())
+                                            });
+
+                                        let ExpectedValues::Some(expected_values) = expected_values else {
+                                            bug!("shoudn't be possible")
+                                        };
 
                                         for val in values {
                                             if let Some(LitKind::Str(s, _)) =
                                                 val.lit().map(|lit| &lit.kind)
                                             {
-                                                ident_values.insert(s.to_string());
+                                                expected_values.insert(Some(s.to_string()));
                                             } else {
                                                 error!(
                                                     "`values()` arguments must be string literals"
@@ -178,35 +193,40 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
                                             }
                                         }
 
-                                        continue 'specs;
+                                        if values.is_empty() {
+                                            expected_values.insert(None);
+                                        }
                                     } else {
                                         error!(
                                             "`values()` first argument must be a simple identifier"
                                         );
                                     }
                                 } else if args.is_empty() {
-                                    cfg.well_known_values = true;
-                                    continue 'specs;
+                                    check_cfg.exhaustive_values = true;
+                                } else {
+                                    expected_error();
                                 }
+                            } else {
+                                expected_error();
                             }
+                        } else {
+                            expected_error();
                         }
                     }
-                    Ok(..) => {}
-                    Err(err) => err.cancel(),
+                    Ok(..) => expected_error(),
+                    Err(err) => {
+                        err.cancel();
+                        expected_error();
+                    }
                 },
-                Err(errs) => drop(errs),
+                Err(errs) => {
+                    drop(errs);
+                    expected_error();
+                }
             }
-
-            error!(
-                "expected `names(name1, name2, ... nameN)` or \
-                `values(name, \"value1\", \"value2\", ... \"valueN\")`"
-            );
         }
 
-        if let Some(names_valid) = &mut cfg.names_valid {
-            names_valid.extend(cfg.values_valid.keys().cloned());
-        }
-        cfg
+        check_cfg
     })
 }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index a0c576234f9..ea576b6ec5d 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -547,6 +547,7 @@ fn test_codegen_options_tracking_hash() {
     untracked!(ar, String::from("abc"));
     untracked!(codegen_units, Some(42));
     untracked!(default_linker_libraries, true);
+    untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
     untracked!(extra_filename, String::from("extra-filename"));
     untracked!(incremental, Some(String::from("abc")));
     // `link_arg` is omitted because it just forwards to `link_args`.
@@ -651,7 +652,6 @@ fn test_unstable_options_tracking_hash() {
     untracked!(assert_incr_state, Some(String::from("loaded")));
     untracked!(deduplicate_diagnostics, false);
     untracked!(dep_tasks, true);
-    untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
     untracked!(dont_buffer_diagnostics, true);
     untracked!(dump_dep_graph, true);
     untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string()));
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index b3f4b5cd5e5..c07dc19a0ac 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -186,12 +186,16 @@ pub enum LiteralKind {
     Str { terminated: bool },
     /// "b"abc"", "b"abc"
     ByteStr { terminated: bool },
+    /// `c"abc"`, `c"abc`
+    CStr { terminated: bool },
     /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a". `None` indicates
     /// an invalid literal.
     RawStr { n_hashes: Option<u8> },
     /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a". `None`
     /// indicates an invalid literal.
     RawByteStr { n_hashes: Option<u8> },
+    /// `cr"abc"`, "cr#"abc"#", `cr#"a`. `None` indicates an invalid literal.
+    RawCStr { n_hashes: Option<u8> },
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -357,39 +361,18 @@ impl Cursor<'_> {
             },
 
             // Byte literal, byte string literal, raw byte string literal or identifier.
-            'b' => match (self.first(), self.second()) {
-                ('\'', _) => {
-                    self.bump();
-                    let terminated = self.single_quoted_string();
-                    let suffix_start = self.pos_within_token();
-                    if terminated {
-                        self.eat_literal_suffix();
-                    }
-                    let kind = Byte { terminated };
-                    Literal { kind, suffix_start }
-                }
-                ('"', _) => {
-                    self.bump();
-                    let terminated = self.double_quoted_string();
-                    let suffix_start = self.pos_within_token();
-                    if terminated {
-                        self.eat_literal_suffix();
-                    }
-                    let kind = ByteStr { terminated };
-                    Literal { kind, suffix_start }
-                }
-                ('r', '"') | ('r', '#') => {
-                    self.bump();
-                    let res = self.raw_double_quoted_string(2);
-                    let suffix_start = self.pos_within_token();
-                    if res.is_ok() {
-                        self.eat_literal_suffix();
-                    }
-                    let kind = RawByteStr { n_hashes: res.ok() };
-                    Literal { kind, suffix_start }
-                }
-                _ => self.ident_or_unknown_prefix(),
-            },
+            'b' => self.c_or_byte_string(
+                |terminated| ByteStr { terminated },
+                |n_hashes| RawByteStr { n_hashes },
+                Some(|terminated| Byte { terminated }),
+            ),
+
+            // c-string literal, raw c-string literal or identifier.
+            'c' => self.c_or_byte_string(
+                |terminated| CStr { terminated },
+                |n_hashes| RawCStr { n_hashes },
+                None,
+            ),
 
             // Identifier (this should be checked after other variant that can
             // start as identifier).
@@ -553,6 +536,47 @@ impl Cursor<'_> {
         }
     }
 
+    fn c_or_byte_string(
+        &mut self,
+        mk_kind: impl FnOnce(bool) -> LiteralKind,
+        mk_kind_raw: impl FnOnce(Option<u8>) -> LiteralKind,
+        single_quoted: Option<fn(bool) -> LiteralKind>,
+    ) -> TokenKind {
+        match (self.first(), self.second(), single_quoted) {
+            ('\'', _, Some(mk_kind)) => {
+                self.bump();
+                let terminated = self.single_quoted_string();
+                let suffix_start = self.pos_within_token();
+                if terminated {
+                    self.eat_literal_suffix();
+                }
+                let kind = mk_kind(terminated);
+                Literal { kind, suffix_start }
+            }
+            ('"', _, _) => {
+                self.bump();
+                let terminated = self.double_quoted_string();
+                let suffix_start = self.pos_within_token();
+                if terminated {
+                    self.eat_literal_suffix();
+                }
+                let kind = mk_kind(terminated);
+                Literal { kind, suffix_start }
+            }
+            ('r', '"', _) | ('r', '#', _) => {
+                self.bump();
+                let res = self.raw_double_quoted_string(2);
+                let suffix_start = self.pos_within_token();
+                if res.is_ok() {
+                    self.eat_literal_suffix();
+                }
+                let kind = mk_kind_raw(res.ok());
+                Literal { kind, suffix_start }
+            }
+            _ => self.ident_or_unknown_prefix(),
+        }
+    }
+
     fn number(&mut self, first_digit: char) -> LiteralKind {
         debug_assert!('0' <= self.prev() && self.prev() <= '9');
         let mut base = Base::Decimal;
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index bb4d91247b8..c9ad54d8d98 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -86,10 +86,45 @@ where
             let res = unescape_char_or_byte(&mut chars, mode == Mode::Byte);
             callback(0..(src.len() - chars.as_str().len()), res);
         }
-        Mode::Str | Mode::ByteStr => unescape_str_or_byte_str(src, mode == Mode::ByteStr, callback),
+        Mode::Str | Mode::ByteStr => unescape_str_common(src, mode, callback),
+
         Mode::RawStr | Mode::RawByteStr => {
             unescape_raw_str_or_raw_byte_str(src, mode == Mode::RawByteStr, callback)
         }
+        Mode::CStr | Mode::RawCStr => unreachable!(),
+    }
+}
+
+/// A unit within CStr. Must not be a nul character.
+pub enum CStrUnit {
+    Byte(u8),
+    Char(char),
+}
+
+impl From<u8> for CStrUnit {
+    fn from(value: u8) -> Self {
+        CStrUnit::Byte(value)
+    }
+}
+
+impl From<char> for CStrUnit {
+    fn from(value: char) -> Self {
+        CStrUnit::Char(value)
+    }
+}
+
+pub fn unescape_c_string<F>(src: &str, mode: Mode, callback: &mut F)
+where
+    F: FnMut(Range<usize>, Result<CStrUnit, EscapeError>),
+{
+    if mode == Mode::RawCStr {
+        unescape_raw_str_or_raw_byte_str(
+            src,
+            mode.characters_should_be_ascii(),
+            &mut |r, result| callback(r, result.map(CStrUnit::Char)),
+        );
+    } else {
+        unescape_str_common(src, mode, callback);
     }
 }
 
@@ -114,34 +149,69 @@ pub enum Mode {
     ByteStr,
     RawStr,
     RawByteStr,
+    CStr,
+    RawCStr,
 }
 
 impl Mode {
     pub fn in_double_quotes(self) -> bool {
         match self {
-            Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => true,
+            Mode::Str
+            | Mode::ByteStr
+            | Mode::RawStr
+            | Mode::RawByteStr
+            | Mode::CStr
+            | Mode::RawCStr => true,
             Mode::Char | Mode::Byte => false,
         }
     }
 
-    pub fn is_byte(self) -> bool {
+    /// Non-byte literals should have `\xXX` escapes that are within the ASCII range.
+    pub fn ascii_escapes_should_be_ascii(self) -> bool {
+        match self {
+            Mode::Char | Mode::Str | Mode::RawStr => true,
+            Mode::Byte | Mode::ByteStr | Mode::RawByteStr | Mode::CStr | Mode::RawCStr => false,
+        }
+    }
+
+    /// Whether characters within the literal must be within the ASCII range
+    pub fn characters_should_be_ascii(self) -> bool {
+        match self {
+            Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
+            Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
+        }
+    }
+
+    /// Byte literals do not allow unicode escape.
+    pub fn is_unicode_escape_disallowed(self) -> bool {
         match self {
             Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
-            Mode::Char | Mode::Str | Mode::RawStr => false,
+            Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
+        }
+    }
+
+    pub fn prefix_noraw(self) -> &'static str {
+        match self {
+            Mode::Byte | Mode::ByteStr | Mode::RawByteStr => "b",
+            Mode::CStr | Mode::RawCStr => "c",
+            Mode::Char | Mode::Str | Mode::RawStr => "",
         }
     }
 }
 
-fn scan_escape(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
+fn scan_escape<T: From<u8> + From<char>>(
+    chars: &mut Chars<'_>,
+    mode: Mode,
+) -> Result<T, EscapeError> {
     // Previous character was '\\', unescape what follows.
     let res = match chars.next().ok_or(EscapeError::LoneSlash)? {
-        '"' => '"',
-        'n' => '\n',
-        'r' => '\r',
-        't' => '\t',
-        '\\' => '\\',
-        '\'' => '\'',
-        '0' => '\0',
+        '"' => b'"',
+        'n' => b'\n',
+        'r' => b'\r',
+        't' => b'\t',
+        '\\' => b'\\',
+        '\'' => b'\'',
+        '0' => b'\0',
 
         'x' => {
             // Parse hexadecimal character code.
@@ -154,76 +224,78 @@ fn scan_escape(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError
 
             let value = hi * 16 + lo;
 
-            // For a non-byte literal verify that it is within ASCII range.
-            if !is_byte && !is_ascii(value) {
+            if mode.ascii_escapes_should_be_ascii() && !is_ascii(value) {
                 return Err(EscapeError::OutOfRangeHexEscape);
             }
-            let value = value as u8;
 
-            value as char
+            value as u8
         }
 
-        'u' => {
-            // We've parsed '\u', now we have to parse '{..}'.
+        'u' => return scan_unicode(chars, mode.is_unicode_escape_disallowed()).map(Into::into),
+        _ => return Err(EscapeError::InvalidEscape),
+    };
+    Ok(res.into())
+}
+
+fn scan_unicode(
+    chars: &mut Chars<'_>,
+    is_unicode_escape_disallowed: bool,
+) -> Result<char, EscapeError> {
+    // We've parsed '\u', now we have to parse '{..}'.
 
-            if chars.next() != Some('{') {
-                return Err(EscapeError::NoBraceInUnicodeEscape);
-            }
+    if chars.next() != Some('{') {
+        return Err(EscapeError::NoBraceInUnicodeEscape);
+    }
 
-            // First character must be a hexadecimal digit.
-            let mut n_digits = 1;
-            let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
-                '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
-                '}' => return Err(EscapeError::EmptyUnicodeEscape),
-                c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
-            };
-
-            // First character is valid, now parse the rest of the number
-            // and closing brace.
-            loop {
-                match chars.next() {
-                    None => return Err(EscapeError::UnclosedUnicodeEscape),
-                    Some('_') => continue,
-                    Some('}') => {
-                        if n_digits > 6 {
-                            return Err(EscapeError::OverlongUnicodeEscape);
-                        }
-
-                        // Incorrect syntax has higher priority for error reporting
-                        // than unallowed value for a literal.
-                        if is_byte {
-                            return Err(EscapeError::UnicodeEscapeInByte);
-                        }
-
-                        break std::char::from_u32(value).ok_or_else(|| {
-                            if value > 0x10FFFF {
-                                EscapeError::OutOfRangeUnicodeEscape
-                            } else {
-                                EscapeError::LoneSurrogateUnicodeEscape
-                            }
-                        })?;
-                    }
-                    Some(c) => {
-                        let digit: u32 =
-                            c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
-                        n_digits += 1;
-                        if n_digits > 6 {
-                            // Stop updating value since we're sure that it's incorrect already.
-                            continue;
-                        }
-                        value = value * 16 + digit;
+    // First character must be a hexadecimal digit.
+    let mut n_digits = 1;
+    let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
+        '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
+        '}' => return Err(EscapeError::EmptyUnicodeEscape),
+        c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
+    };
+
+    // First character is valid, now parse the rest of the number
+    // and closing brace.
+    loop {
+        match chars.next() {
+            None => return Err(EscapeError::UnclosedUnicodeEscape),
+            Some('_') => continue,
+            Some('}') => {
+                if n_digits > 6 {
+                    return Err(EscapeError::OverlongUnicodeEscape);
+                }
+
+                // Incorrect syntax has higher priority for error reporting
+                // than unallowed value for a literal.
+                if is_unicode_escape_disallowed {
+                    return Err(EscapeError::UnicodeEscapeInByte);
+                }
+
+                break std::char::from_u32(value).ok_or_else(|| {
+                    if value > 0x10FFFF {
+                        EscapeError::OutOfRangeUnicodeEscape
+                    } else {
+                        EscapeError::LoneSurrogateUnicodeEscape
                     }
-                };
+                });
             }
-        }
-        _ => return Err(EscapeError::InvalidEscape),
-    };
-    Ok(res)
+            Some(c) => {
+                let digit: u32 = c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
+                n_digits += 1;
+                if n_digits > 6 {
+                    // Stop updating value since we're sure that it's incorrect already.
+                    continue;
+                }
+                value = value * 16 + digit;
+            }
+        };
+    }
 }
 
 #[inline]
-fn ascii_check(c: char, is_byte: bool) -> Result<char, EscapeError> {
-    if is_byte && !c.is_ascii() {
+fn ascii_check(c: char, characters_should_be_ascii: bool) -> Result<char, EscapeError> {
+    if characters_should_be_ascii && !c.is_ascii() {
         // Byte literal can't be a non-ascii character.
         Err(EscapeError::NonAsciiCharInByte)
     } else {
@@ -234,7 +306,7 @@ fn ascii_check(c: char, is_byte: bool) -> Result<char, EscapeError> {
 fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
     let c = chars.next().ok_or(EscapeError::ZeroChars)?;
     let res = match c {
-        '\\' => scan_escape(chars, is_byte),
+        '\\' => scan_escape(chars, if is_byte { Mode::Byte } else { Mode::Char }),
         '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar),
         '\r' => Err(EscapeError::BareCarriageReturn),
         _ => ascii_check(c, is_byte),
@@ -247,9 +319,9 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, E
 
 /// Takes a contents of a string literal (without quotes) and produces a
 /// sequence of escaped characters or errors.
-fn unescape_str_or_byte_str<F>(src: &str, is_byte: bool, callback: &mut F)
+fn unescape_str_common<F, T: From<u8> + From<char>>(src: &str, mode: Mode, callback: &mut F)
 where
-    F: FnMut(Range<usize>, Result<char, EscapeError>),
+    F: FnMut(Range<usize>, Result<T, EscapeError>),
 {
     let mut chars = src.chars();
 
@@ -266,47 +338,49 @@ where
                         // if unescaped '\' character is followed by '\n'.
                         // For details see [Rust language reference]
                         // (https://doc.rust-lang.org/reference/tokens.html#string-literals).
-                        skip_ascii_whitespace(&mut chars, start, callback);
+                        skip_ascii_whitespace(&mut chars, start, &mut |range, err| {
+                            callback(range, Err(err))
+                        });
                         continue;
                     }
-                    _ => scan_escape(&mut chars, is_byte),
+                    _ => scan_escape::<T>(&mut chars, mode),
                 }
             }
-            '\n' => Ok('\n'),
-            '\t' => Ok('\t'),
+            '\n' => Ok(b'\n'.into()),
+            '\t' => Ok(b'\t'.into()),
             '"' => Err(EscapeError::EscapeOnlyChar),
             '\r' => Err(EscapeError::BareCarriageReturn),
-            _ => ascii_check(c, is_byte),
+            _ => ascii_check(c, mode.characters_should_be_ascii()).map(Into::into),
         };
         let end = src.len() - chars.as_str().len();
-        callback(start..end, res);
+        callback(start..end, res.map(Into::into));
     }
+}
 
-    fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
-    where
-        F: FnMut(Range<usize>, Result<char, EscapeError>),
-    {
-        let tail = chars.as_str();
-        let first_non_space = tail
-            .bytes()
-            .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
-            .unwrap_or(tail.len());
-        if tail[1..first_non_space].contains('\n') {
-            // The +1 accounts for the escaping slash.
-            let end = start + first_non_space + 1;
-            callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
-        }
-        let tail = &tail[first_non_space..];
-        if let Some(c) = tail.chars().nth(0) {
-            if c.is_whitespace() {
-                // For error reporting, we would like the span to contain the character that was not
-                // skipped. The +1 is necessary to account for the leading \ that started the escape.
-                let end = start + first_non_space + c.len_utf8() + 1;
-                callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning));
-            }
+fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
+where
+    F: FnMut(Range<usize>, EscapeError),
+{
+    let tail = chars.as_str();
+    let first_non_space = tail
+        .bytes()
+        .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
+        .unwrap_or(tail.len());
+    if tail[1..first_non_space].contains('\n') {
+        // The +1 accounts for the escaping slash.
+        let end = start + first_non_space + 1;
+        callback(start..end, EscapeError::MultipleSkippedLinesWarning);
+    }
+    let tail = &tail[first_non_space..];
+    if let Some(c) = tail.chars().nth(0) {
+        if c.is_whitespace() {
+            // For error reporting, we would like the span to contain the character that was not
+            // skipped. The +1 is necessary to account for the leading \ that started the escape.
+            let end = start + first_non_space + c.len_utf8() + 1;
+            callback(start..end, EscapeError::UnskippedWhitespaceWarning);
         }
-        *chars = tail.chars();
     }
+    *chars = tail.chars();
 }
 
 /// Takes a contents of a string literal (without quotes) and produces a
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index aeb791901bd..01052698850 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -63,6 +63,7 @@ use rustc_middle::ty::layout::{LayoutError, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
+use rustc_session::config::ExpectedValues;
 use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
@@ -3306,16 +3307,15 @@ impl EarlyLintPass for UnexpectedCfgs {
         let cfg = &cx.sess().parse_sess.config;
         let check_cfg = &cx.sess().parse_sess.check_config;
         for &(name, value) in cfg {
-            if let Some(names_valid) = &check_cfg.names_valid && !names_valid.contains(&name){
-                cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName {
-                    name,
-                });
-            }
-            if let Some(value) = value && let Some(values) = check_cfg.values_valid.get(&name) && !values.contains(&value) {
-                cx.emit_lint(
-                    UNEXPECTED_CFGS,
-                    BuiltinUnexpectedCliConfigValue { name, value },
-                );
+            match check_cfg.expecteds.get(&name) {
+                Some(ExpectedValues::Some(values)) if !values.contains(&value) => {
+                    let value = value.unwrap_or(kw::Empty);
+                    cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigValue { name, value });
+                }
+                None if check_cfg.exhaustive_names => {
+                    cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName { name });
+                }
+                _ => { /* expected */ }
             }
         }
     }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index d4898ffe883..53d7cf74cde 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -36,6 +36,7 @@ use rustc_middle::middle::stability;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
+use rustc_session::config::ExpectedValues;
 use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId};
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
@@ -768,22 +769,52 @@ pub trait LintContext: Sized {
                     db.help(help);
                     db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
                 },
-                BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), None) => {
-                    let Some(names_valid) = &sess.parse_sess.check_config.names_valid else {
-                        bug!("it shouldn't be possible to have a diagnostic on a name if name checking is not enabled");
-                    };
-                    let possibilities: Vec<Symbol> = names_valid.iter().map(|s| *s).collect();
+                BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => {
+                    let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().map(|s| *s).collect();
 
                     // Suggest the most probable if we found one
                     if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
-                        db.span_suggestion(name_span, "did you mean", best_match, Applicability::MaybeIncorrect);
+                        if let Some(ExpectedValues::Some(best_match_values)) =
+                            sess.parse_sess.check_config.expecteds.get(&best_match) {
+                            let mut possibilities = best_match_values.iter()
+                                .flatten()
+                                .map(Symbol::as_str)
+                                .collect::<Vec<_>>();
+                            possibilities.sort();
+
+                            if let Some((value, value_span)) = value {
+                                if best_match_values.contains(&Some(value)) {
+                                    db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect);
+                                } else if best_match_values.contains(&None) {
+                                    db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect);
+                                } else if let Some(first_value) = possibilities.first() {
+                                    db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect);
+                                } else {
+                                    db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", best_match, Applicability::MaybeIncorrect);
+                                };
+                            } else {
+                                db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
+                            }
+
+                            if !possibilities.is_empty() {
+                                let possibilities = possibilities.join("`, `");
+                                db.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
+                            }
+                        } else {
+                            db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
+                        }
                     }
                 },
-                BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), Some((value, value_span))) => {
-                    let Some(values) = &sess.parse_sess.check_config.values_valid.get(&name) else {
+                BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => {
+                    let Some(ExpectedValues::Some(values)) = &sess.parse_sess.check_config.expecteds.get(&name) else {
                         bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values");
                     };
-                    let possibilities: Vec<Symbol> = values.iter().map(|&s| s).collect();
+                    let mut have_none_possibility = false;
+                    let possibilities: Vec<Symbol> = values.iter()
+                        .inspect(|a| have_none_possibility |= a.is_none())
+                        .copied()
+                        .flatten()
+                        .collect();
 
                     // Show the full list if all possible values for a given name, but don't do it
                     // for names as the possibilities could be very long
@@ -792,17 +823,24 @@ pub trait LintContext: Sized {
                             let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
                             possibilities.sort();
 
-                            let possibilities = possibilities.join(", ");
-                            db.note(format!("expected values for `{name}` are: {possibilities}"));
+                            let possibilities = possibilities.join("`, `");
+                            let none = if have_none_possibility { "(none), " } else { "" };
+
+                            db.note(format!("expected values for `{name}` are: {none}`{possibilities}`"));
                         }
 
-                        // Suggest the most probable if we found one
-                        if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
-                            db.span_suggestion(value_span, "did you mean", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+                        if let Some((value, value_span)) = value {
+                            // Suggest the most probable if we found one
+                            if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
+                                db.span_suggestion(value_span, "there is a expected value with a similar name", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+
+                            }
+                        } else if let &[first_possibility] = &possibilities[..] {
+                            db.span_suggestion(name_span.shrink_to_hi(), "specify a config value", format!(" = \"{first_possibility}\""), Applicability::MaybeIncorrect);
                         }
-                    } else {
+                    } else if have_none_possibility {
                         db.note(format!("no expected value for `{name}`"));
-                        if name != sym::feature {
+                        if let Some((_value, value_span)) = value {
                             db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", "", Applicability::MaybeIncorrect);
                         }
                     }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 7ea472ed504..e27e322db88 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -496,7 +496,8 @@ pub enum BuiltinLintDiagnostics {
     BreakWithLabelAndLoop(Span),
     NamedAsmLabel(String),
     UnicodeTextFlow(Span, String),
-    UnexpectedCfg((Symbol, Span), Option<(Symbol, Span)>),
+    UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
+    UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
     DeprecatedWhereclauseLocation(Span, String),
     SingleUseLifetime {
         /// Span of the parameter which declares this lifetime.
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 1acdc95ca8d..e88a3cdf620 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -307,7 +307,7 @@ static size_t getLongestEntryLength(ArrayRef<KV> Table) {
   return MaxLen;
 }
 
-extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) {
+extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, const char* TargetCPU) {
   const TargetMachine *Target = unwrap(TM);
   const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
   const Triple::ArchType HostArch = Triple(sys::getDefaultTargetTriple()).getArch();
@@ -323,9 +323,18 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) {
     printf("    %-*s - Select the CPU of the current host (currently %.*s).\n",
       MaxCPULen, "native", (int)HostCPU.size(), HostCPU.data());
   }
-  for (auto &CPU : CPUTable)
-    printf("    %-*s\n", MaxCPULen, CPU.Key);
-  printf("\n");
+  for (auto &CPU : CPUTable) {
+    // Compare cpu against current target to label the default
+    if (strcmp(CPU.Key, TargetCPU) == 0) {
+      printf("    %-*s - This is the default target CPU"
+      " for the current build target (currently %s).",
+        MaxCPULen, CPU.Key, Target->getTargetTriple().str().c_str());
+    }
+    else {
+      printf("    %-*s", MaxCPULen, CPU.Key);
+    }
+    printf("\n");
+  }
 }
 
 extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) {
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index b43dcf3e5a1..c83c47e722b 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -161,14 +161,6 @@ impl<'tcx> Collector<'tcx> {
                             "raw-dylib" => {
                                 if !sess.target.is_like_windows {
                                     sess.emit_err(errors::FrameworkOnlyWindows { span });
-                                } else if !features.raw_dylib && sess.target.arch == "x86" {
-                                    feature_err(
-                                        &sess.parse_sess,
-                                        sym::raw_dylib,
-                                        span,
-                                        "link kind `raw-dylib` is unstable on x86",
-                                    )
-                                    .emit();
                                 }
                                 NativeLibKind::RawDylib
                             }
@@ -251,16 +243,6 @@ impl<'tcx> Collector<'tcx> {
                                 continue;
                             }
                         };
-                        if !features.raw_dylib {
-                            let span = item.name_value_literal_span().unwrap();
-                            feature_err(
-                                &sess.parse_sess,
-                                sym::raw_dylib,
-                                span,
-                                "import name type is unstable",
-                            )
-                            .emit();
-                        }
                         import_name_type = Some((link_import_name_type, item.span()));
                     }
                     _ => {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index fbcfd433724..59549435233 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -146,6 +146,12 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
             let id = tcx.allocate_bytes(data);
             ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
         }
+        (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) =>
+        {
+            let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
+            let allocation = tcx.mk_const_alloc(allocation);
+            ConstValue::Slice { data: allocation, start: 0, end: data.len() }
+        }
         (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
             ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
         }
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index b1c0dedd3c7..51e90489002 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,3 +1,5 @@
+use std::ops::Range;
+
 use crate::errors;
 use crate::lexer::unicode_chars::UNICODE_ARRAY;
 use crate::make_unclosed_delims_error;
@@ -6,7 +8,7 @@ use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
 use rustc_errors::{error_code, Applicability, Diagnostic, DiagnosticBuilder, StashKey};
-use rustc_lexer::unescape::{self, Mode};
+use rustc_lexer::unescape::{self, EscapeError, Mode};
 use rustc_lexer::Cursor;
 use rustc_lexer::{Base, DocStyle, RawStrError};
 use rustc_session::lint::builtin::{
@@ -204,6 +206,9 @@ impl<'a> StringReader<'a> {
                 rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
                     let suffix_start = start + BytePos(suffix_start);
                     let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
+                    if let token::LitKind::CStr | token::LitKind::CStrRaw(_) = kind {
+                        self.sess.gated_spans.gate(sym::c_str_literals, self.mk_sp(start, self.pos));
+                    }
                     let suffix = if suffix_start < self.pos {
                         let string = self.str_from(suffix_start);
                         if string == "_" {
@@ -415,6 +420,16 @@ impl<'a> StringReader<'a> {
                 }
                 self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" "
             }
+            rustc_lexer::LiteralKind::CStr { terminated } => {
+                if !terminated {
+                    self.sess.span_diagnostic.span_fatal_with_code(
+                        self.mk_sp(start + BytePos(1), end),
+                        "unterminated C string",
+                        error_code!(E0767),
+                    )
+                }
+                self.cook_c_string(token::CStr, Mode::CStr, start, end, 2, 1) // c" "
+            }
             rustc_lexer::LiteralKind::RawStr { n_hashes } => {
                 if let Some(n_hashes) = n_hashes {
                     let n = u32::from(n_hashes);
@@ -433,6 +448,15 @@ impl<'a> StringReader<'a> {
                     self.report_raw_str_error(start, 2);
                 }
             }
+            rustc_lexer::LiteralKind::RawCStr { n_hashes } => {
+                if let Some(n_hashes) = n_hashes {
+                    let n = u32::from(n_hashes);
+                    let kind = token::CStrRaw(n_hashes);
+                    self.cook_c_string(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "##
+                } else {
+                    self.report_raw_str_error(start, 2);
+                }
+            }
             rustc_lexer::LiteralKind::Int { base, empty_int } => {
                 if empty_int {
                     let span = self.mk_sp(start, end);
@@ -648,7 +672,7 @@ impl<'a> StringReader<'a> {
         self.sess.emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num });
     }
 
-    fn cook_quoted(
+    fn cook_common(
         &self,
         kind: token::LitKind,
         mode: Mode,
@@ -656,12 +680,13 @@ impl<'a> StringReader<'a> {
         end: BytePos,
         prefix_len: u32,
         postfix_len: u32,
+        unescape: fn(&str, Mode, &mut dyn FnMut(Range<usize>, Result<(), EscapeError>)),
     ) -> (token::LitKind, Symbol) {
         let mut has_fatal_err = false;
         let content_start = start + BytePos(prefix_len);
         let content_end = end - BytePos(postfix_len);
         let lit_content = self.str_from_to(content_start, content_end);
-        unescape::unescape_literal(lit_content, mode, &mut |range, result| {
+        unescape(lit_content, mode, &mut |range, result| {
             // Here we only check for errors. The actual unescaping is done later.
             if let Err(err) = result {
                 let span_with_quotes = self.mk_sp(start, end);
@@ -692,6 +717,38 @@ impl<'a> StringReader<'a> {
             (token::Err, self.symbol_from_to(start, end))
         }
     }
+
+    fn cook_quoted(
+        &self,
+        kind: token::LitKind,
+        mode: Mode,
+        start: BytePos,
+        end: BytePos,
+        prefix_len: u32,
+        postfix_len: u32,
+    ) -> (token::LitKind, Symbol) {
+        self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
+            unescape::unescape_literal(src, mode, &mut |span, result| {
+                callback(span, result.map(drop))
+            })
+        })
+    }
+
+    fn cook_c_string(
+        &self,
+        kind: token::LitKind,
+        mode: Mode,
+        start: BytePos,
+        end: BytePos,
+        prefix_len: u32,
+        postfix_len: u32,
+    ) -> (token::LitKind, Symbol) {
+        self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
+            unescape::unescape_c_string(src, mode, &mut |span, result| {
+                callback(span, result.map(drop))
+            })
+        })
+    }
 }
 
 pub fn nfc_normalize(string: &str) -> Symbol {
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index d8bcf816fb2..eb9625f923a 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -78,8 +78,7 @@ pub(crate) fn emit_unescape_error(
                 }
             };
             let sugg = sugg.unwrap_or_else(|| {
-                let is_byte = mode.is_byte();
-                let prefix = if is_byte { "b" } else { "" };
+                let prefix = mode.prefix_noraw();
                 let mut escaped = String::with_capacity(lit.len());
                 let mut chrs = lit.chars().peekable();
                 while let Some(first) = chrs.next() {
@@ -97,7 +96,11 @@ pub(crate) fn emit_unescape_error(
                     };
                 }
                 let sugg = format!("{prefix}\"{escaped}\"");
-                MoreThanOneCharSugg::Quotes { span: span_with_quotes, is_byte, sugg }
+                MoreThanOneCharSugg::Quotes {
+                    span: span_with_quotes,
+                    is_byte: mode == Mode::Byte,
+                    sugg,
+                }
             });
             handler.emit_err(UnescapeError::MoreThanOneChar {
                 span: span_with_quotes,
@@ -112,7 +115,7 @@ pub(crate) fn emit_unescape_error(
                 char_span,
                 escaped_sugg: c.escape_default().to_string(),
                 escaped_msg: escaped_char(c),
-                byte: mode.is_byte(),
+                byte: mode == Mode::Byte,
             });
         }
         EscapeError::BareCarriageReturn => {
@@ -126,12 +129,15 @@ pub(crate) fn emit_unescape_error(
         EscapeError::InvalidEscape => {
             let (c, span) = last_char();
 
-            let label =
-                if mode.is_byte() { "unknown byte escape" } else { "unknown character escape" };
+            let label = if mode == Mode::Byte || mode == Mode::ByteStr {
+                "unknown byte escape"
+            } else {
+                "unknown character escape"
+            };
             let ec = escaped_char(c);
             let mut diag = handler.struct_span_err(span, format!("{}: `{}`", label, ec));
             diag.span_label(span, label);
-            if c == '{' || c == '}' && !mode.is_byte() {
+            if c == '{' || c == '}' && matches!(mode, Mode::Str | Mode::RawStr) {
                 diag.help(
                     "if used in a formatting string, curly braces are escaped with `{{` and `}}`",
                 );
@@ -141,7 +147,7 @@ pub(crate) fn emit_unescape_error(
                      version control settings",
                 );
             } else {
-                if !mode.is_byte() {
+                if mode == Mode::Str || mode == Mode::Char {
                     diag.span_suggestion(
                         span_with_quotes,
                         "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal",
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index f58f8919e5c..61396ee0d4a 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1870,6 +1870,7 @@ impl<'a> Parser<'a> {
         let recovered = self.recover_after_dot();
         let token = recovered.as_ref().unwrap_or(&self.token);
         let span = token.span;
+
         token::Lit::from_token(token).map(|token_lit| {
             self.bump();
             (token_lit, span)
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index c897275bee2..a8fe560d1a7 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -101,3 +101,5 @@ session_invalid_int_literal_width = invalid width `{$width}` for integer literal
     .help = valid widths are 8, 16, 32, 64 and 128
 
 session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
+
+session_nul_in_c_str = null characters in C string literals are not supported
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index cfdba1120ec..18917120256 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1064,37 +1064,76 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig
 
 /// The parsed `--check-cfg` options
 pub struct CheckCfg<T = String> {
-    /// The set of all `names()`, if None no name checking is performed
-    pub names_valid: Option<FxHashSet<T>>,
+    /// Is well known names activated
+    pub exhaustive_names: bool,
     /// Is well known values activated
-    pub well_known_values: bool,
-    /// The set of all `values()`
-    pub values_valid: FxHashMap<T, FxHashSet<T>>,
+    pub exhaustive_values: bool,
+    /// All the expected values for a config name
+    pub expecteds: FxHashMap<T, ExpectedValues<T>>,
 }
 
 impl<T> Default for CheckCfg<T> {
     fn default() -> Self {
         CheckCfg {
-            names_valid: Default::default(),
-            values_valid: Default::default(),
-            well_known_values: false,
+            exhaustive_names: false,
+            exhaustive_values: false,
+            expecteds: FxHashMap::default(),
         }
     }
 }
 
 impl<T> CheckCfg<T> {
-    fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
+    fn map_data<O: Eq + Hash>(self, f: impl Fn(T) -> O) -> CheckCfg<O> {
         CheckCfg {
-            names_valid: self
-                .names_valid
-                .as_ref()
-                .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
-            values_valid: self
-                .values_valid
-                .iter()
-                .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
+            exhaustive_names: self.exhaustive_names,
+            exhaustive_values: self.exhaustive_values,
+            expecteds: self
+                .expecteds
+                .into_iter()
+                .map(|(name, values)| {
+                    (
+                        f(name),
+                        match values {
+                            ExpectedValues::Some(values) => ExpectedValues::Some(
+                                values.into_iter().map(|b| b.map(|b| f(b))).collect(),
+                            ),
+                            ExpectedValues::Any => ExpectedValues::Any,
+                        },
+                    )
+                })
                 .collect(),
-            well_known_values: self.well_known_values,
+        }
+    }
+}
+
+pub enum ExpectedValues<T> {
+    Some(FxHashSet<Option<T>>),
+    Any,
+}
+
+impl<T: Eq + Hash> ExpectedValues<T> {
+    fn insert(&mut self, value: T) -> bool {
+        match self {
+            ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)),
+            ExpectedValues::Any => false,
+        }
+    }
+}
+
+impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> {
+    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+        match self {
+            ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)),
+            ExpectedValues::Any => {}
+        }
+    }
+}
+
+impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
+    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
+        match self {
+            ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))),
+            ExpectedValues::Any => {}
         }
     }
 }
@@ -1103,58 +1142,27 @@ impl<T> CheckCfg<T> {
 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
 /// but the symbol interner is not yet set up then, so we must convert it later.
 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
-    cfg.map_data(|s| Symbol::intern(s))
+    cfg.map_data(|s| Symbol::intern(&s))
 }
 
 impl CrateCheckConfig {
-    /// Fills a `CrateCheckConfig` with well-known configuration names.
-    fn fill_well_known_names(&mut self) {
-        // NOTE: This should be kept in sync with `default_configuration` and
-        // `fill_well_known_values`
-        const WELL_KNOWN_NAMES: &[Symbol] = &[
-            // rustc
-            sym::unix,
-            sym::windows,
-            sym::target_os,
-            sym::target_family,
-            sym::target_arch,
-            sym::target_endian,
-            sym::target_pointer_width,
-            sym::target_env,
-            sym::target_abi,
-            sym::target_vendor,
-            sym::target_thread_local,
-            sym::target_has_atomic_load_store,
-            sym::target_has_atomic,
-            sym::target_has_atomic_equal_alignment,
-            sym::target_feature,
-            sym::panic,
-            sym::sanitize,
-            sym::debug_assertions,
-            sym::proc_macro,
-            sym::test,
-            sym::feature,
-            // rustdoc
-            sym::doc,
-            sym::doctest,
-            // miri
-            sym::miri,
-        ];
-
-        // We only insert well-known names if `names()` was activated
-        if let Some(names_valid) = &mut self.names_valid {
-            names_valid.extend(WELL_KNOWN_NAMES);
-        }
-    }
-
-    /// Fills a `CrateCheckConfig` with well-known configuration values.
-    fn fill_well_known_values(&mut self, current_target: &Target) {
-        if !self.well_known_values {
+    pub fn fill_well_known(&mut self, current_target: &Target) {
+        if !self.exhaustive_values && !self.exhaustive_names {
             return;
         }
 
-        // NOTE: This should be kept in sync with `default_configuration` and
-        // `fill_well_known_names`
+        let no_values = || {
+            let mut values = FxHashSet::default();
+            values.insert(None);
+            ExpectedValues::Some(values)
+        };
+
+        let empty_values = || {
+            let values = FxHashSet::default();
+            ExpectedValues::Some(values)
+        };
+
+        // NOTE: This should be kept in sync with `default_configuration`
 
         let panic_values = &PanicStrategy::all();
 
@@ -1174,6 +1182,9 @@ impl CrateCheckConfig {
         // Unknown possible values:
         //  - `feature`
         //  - `target_feature`
+        for name in [sym::feature, sym::target_feature] {
+            self.expecteds.entry(name).or_insert(ExpectedValues::Any);
+        }
 
         // No-values
         for name in [
@@ -1187,20 +1198,23 @@ impl CrateCheckConfig {
             sym::debug_assertions,
             sym::target_thread_local,
         ] {
-            self.values_valid.entry(name).or_default();
+            self.expecteds.entry(name).or_insert_with(no_values);
         }
 
         // Pre-defined values
-        self.values_valid.entry(sym::panic).or_default().extend(panic_values);
-        self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
-        self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
-        self.values_valid
+        self.expecteds.entry(sym::panic).or_insert_with(empty_values).extend(panic_values);
+        self.expecteds.entry(sym::sanitize).or_insert_with(empty_values).extend(sanitize_values);
+        self.expecteds
+            .entry(sym::target_has_atomic)
+            .or_insert_with(no_values)
+            .extend(atomic_values);
+        self.expecteds
             .entry(sym::target_has_atomic_load_store)
-            .or_default()
+            .or_insert_with(no_values)
             .extend(atomic_values);
-        self.values_valid
+        self.expecteds
             .entry(sym::target_has_atomic_equal_alignment)
-            .or_default()
+            .or_insert_with(no_values)
             .extend(atomic_values);
 
         // Target specific values
@@ -1218,47 +1232,50 @@ impl CrateCheckConfig {
 
             // Initialize (if not already initialized)
             for &e in VALUES {
-                self.values_valid.entry(e).or_default();
+                let entry = self.expecteds.entry(e);
+                if !self.exhaustive_values {
+                    entry.or_insert(ExpectedValues::Any);
+                } else {
+                    entry.or_insert_with(empty_values);
+                }
             }
 
-            // Get all values map at once otherwise it would be costly.
-            // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
-            let [
-                values_target_os,
-                values_target_family,
-                values_target_arch,
-                values_target_endian,
-                values_target_env,
-                values_target_abi,
-                values_target_vendor,
-                values_target_pointer_width,
-            ] = self
-                .values_valid
-                .get_many_mut(VALUES)
-                .expect("unable to get all the check-cfg values buckets");
-
-            for target in TARGETS
-                .iter()
-                .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
-                .chain(iter::once(current_target.clone()))
-            {
-                values_target_os.insert(Symbol::intern(&target.options.os));
-                values_target_family
-                    .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
-                values_target_arch.insert(Symbol::intern(&target.arch));
-                values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
-                values_target_env.insert(Symbol::intern(&target.options.env));
-                values_target_abi.insert(Symbol::intern(&target.options.abi));
-                values_target_vendor.insert(Symbol::intern(&target.options.vendor));
-                values_target_pointer_width.insert(sym::integer(target.pointer_width));
+            if self.exhaustive_values {
+                // Get all values map at once otherwise it would be costly.
+                // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
+                let [
+                    values_target_os,
+                    values_target_family,
+                    values_target_arch,
+                    values_target_endian,
+                    values_target_env,
+                    values_target_abi,
+                    values_target_vendor,
+                    values_target_pointer_width,
+                ] = self
+                    .expecteds
+                    .get_many_mut(VALUES)
+                    .expect("unable to get all the check-cfg values buckets");
+
+                for target in TARGETS
+                    .iter()
+                    .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
+                    .chain(iter::once(current_target.clone()))
+                {
+                    values_target_os.insert(Symbol::intern(&target.options.os));
+                    values_target_family.extend(
+                        target.options.families.iter().map(|family| Symbol::intern(family)),
+                    );
+                    values_target_arch.insert(Symbol::intern(&target.arch));
+                    values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
+                    values_target_env.insert(Symbol::intern(&target.options.env));
+                    values_target_abi.insert(Symbol::intern(&target.options.abi));
+                    values_target_vendor.insert(Symbol::intern(&target.options.vendor));
+                    values_target_pointer_width.insert(sym::integer(target.pointer_width));
+                }
             }
         }
     }
-
-    pub fn fill_well_known(&mut self, current_target: &Target) {
-        self.fill_well_known_names();
-        self.fill_well_known_values(current_target);
-    }
 }
 
 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 0df62c2064e..546c0fa8e03 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_ast::token;
 use rustc_ast::util::literal::LitError;
 use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan};
 use rustc_macros::Diagnostic;
-use rustc_span::{Span, Symbol};
+use rustc_span::{BytePos, Span, Symbol};
 use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
 #[derive(Diagnostic)]
@@ -323,6 +323,13 @@ pub(crate) struct BinaryFloatLiteralNotSupported {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(session_nul_in_c_str)]
+pub(crate) struct NulInCStr {
+    #[primary_span]
+    pub span: Span,
+}
+
 pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) {
     // Checks if `s` looks like i32 or u1234 etc.
     fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
@@ -401,6 +408,12 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
             };
             sess.emit_err(IntLiteralTooLarge { span, limit });
         }
+        LitError::NulInCStr(range) => {
+            let lo = BytePos(span.lo().0 + range.start as u32 + 2);
+            let hi = BytePos(span.lo().0 + range.end as u32 + 2);
+            let span = span.with_lo(lo).with_hi(hi);
+            sess.emit_err(NulInCStr { span });
+        }
     }
 }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index d9e191c00c9..243da98c3c2 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1235,6 +1235,8 @@ options! {
         line-tables-only, limited, or full; default: 0)"),
     default_linker_libraries: bool = (false, parse_bool, [UNTRACKED],
         "allow the linker to link its default libraries (default: no)"),
+    dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+        "import library generation tool (ignored except when targeting windows-gnu)"),
     embed_bitcode: bool = (true, parse_bool, [TRACKED],
         "emit bitcode in rlibs (default: yes)"),
     extra_filename: String = (String::new(), parse_string, [UNTRACKED],
@@ -1391,8 +1393,6 @@ options! {
         (default: no)"),
     diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
         "set the current output width for diagnostic truncation"),
-    dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
-        "import library generation tool (windows-gnu only)"),
     dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
         "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
         (default: no)"),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 1140a922f9f..58015d5d502 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -441,6 +441,7 @@ symbols! {
         bridge,
         bswap,
         c_str,
+        c_str_literals,
         c_unwind,
         c_variadic,
         c_void,
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index efbbc1c2331..2daef82d6f1 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -3079,8 +3079,8 @@ impl<'a, K, V, A> CursorMut<'a, K, V, A> {
                 unsafe { self.root.reborrow() }
                     .as_mut()?
                     .borrow_mut()
-                    .first_leaf_edge()
-                    .next_kv()
+                    .last_leaf_edge()
+                    .next_back_kv()
                     .ok()?
                     .into_kv_valmut()
             }
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index da00d83bdbb..7ecffe3eef2 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -8,6 +8,7 @@ use crate::testing::crash_test::{CrashTestDummy, Panic};
 use crate::testing::ord_chaos::{Cyclic3, Governed, Governor};
 use crate::testing::rng::DeterministicRng;
 use crate::vec::Vec;
+use core::assert_matches::assert_matches;
 use std::cmp::Ordering;
 use std::iter;
 use std::mem;
@@ -2448,3 +2449,21 @@ fn test_cursor_mut_insert_after_4() {
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
     cur.insert_after(4, 'd');
 }
+
+#[test]
+fn cursor_peek_prev_agrees_with_cursor_mut() {
+    let mut map = BTreeMap::from([(1, 1), (2, 2), (3, 3)]);
+
+    let cursor = map.lower_bound(Bound::Excluded(&3));
+    assert!(cursor.key().is_none());
+
+    let prev = cursor.peek_prev();
+    assert_matches!(prev, Some((&3, _)));
+
+    // Shadow names so the two parts of this test match.
+    let mut cursor = map.lower_bound_mut(Bound::Excluded(&3));
+    assert!(cursor.key().is_none());
+
+    let prev = cursor.peek_prev();
+    assert_matches!(prev, Some((&3, _)));
+}
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index bd2b2c36c43..07b11814f96 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -79,9 +79,9 @@ use crate::str;
 ///
 /// [str]: prim@str "str"
 #[derive(Hash)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
 #[stable(feature = "core_c_str", since = "1.64.0")]
 #[rustc_has_incoherent_inherent_impls]
+#[cfg_attr(not(bootstrap), lang = "CStr")]
 // FIXME:
 // `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
 // on `CStr` being layout-compatible with `[u8]`.
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index a535a011aaf..ed0c05a6863 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -107,6 +107,7 @@
 #![feature(const_arguments_as_str)]
 #![feature(const_array_from_ref)]
 #![feature(const_array_into_iter_constructors)]
+#![feature(const_assume)]
 #![feature(const_bigint_helper_methods)]
 #![feature(const_black_box)]
 #![feature(const_caller_location)]
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 5f55f762ad5..4737ff5d756 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1632,8 +1632,8 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
     // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
     // 1, where the method versions of these operations are not inlined.
     use intrinsics::{
-        cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_shl, unchecked_shr,
-        unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub,
+        assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_shl,
+        unchecked_shr, unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub,
     };
 
     /// Calculate multiplicative modular inverse of `x` modulo `m`.
@@ -1724,12 +1724,18 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
         // in a branch-free way and then bitwise-OR it with whatever result the `-p mod a`
         // computation produces.
 
+        let aligned_address = wrapping_add(addr, a_minus_one) & wrapping_sub(0, a);
+        let byte_offset = wrapping_sub(aligned_address, addr);
+        // FIXME: Remove the assume after <https://github.com/llvm/llvm-project/issues/62502>
+        // SAFETY: Masking by `-a` can only affect the low bits, and thus cannot have reduced
+        // the value by more than `a-1`, so even though the intermediate values might have
+        // wrapped, the byte_offset is always in `[0, a)`.
+        unsafe { assume(byte_offset < a) };
+
         // SAFETY: `stride == 0` case has been handled by the special case above.
         let addr_mod_stride = unsafe { unchecked_rem(addr, stride) };
 
         return if addr_mod_stride == 0 {
-            let aligned_address = wrapping_add(addr, a_minus_one) & wrapping_sub(0, a);
-            let byte_offset = wrapping_sub(aligned_address, addr);
             // SAFETY: `stride` is non-zero. This is guaranteed to divide exactly as well, because
             // addr has been verified to be aligned to the original type’s alignment requirements.
             unsafe { exact_div(byte_offset, stride) }
diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs
index 54b11c543f1..caecda1bc63 100644
--- a/library/proc_macro/src/bridge/mod.rs
+++ b/library/proc_macro/src/bridge/mod.rs
@@ -337,6 +337,8 @@ pub enum LitKind {
     StrRaw(u8),
     ByteStr,
     ByteStrRaw(u8),
+    CStr,
+    CStrRaw(u8),
     Err,
 }
 
@@ -350,6 +352,8 @@ rpc_encode_decode!(
         StrRaw(n),
         ByteStr,
         ByteStrRaw(n),
+        CStr,
+        CStrRaw(n),
         Err,
     }
 );
diff --git a/library/std/src/sys/hermit/time.rs b/library/std/src/sys/hermit/time.rs
index 32ddc4346ee..5440d85df4a 100644
--- a/library/std/src/sys/hermit/time.rs
+++ b/library/std/src/sys/hermit/time.rs
@@ -40,11 +40,7 @@ impl Timespec {
     }
 
     fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
-            .ok()
-            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
+        let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
@@ -57,11 +53,7 @@ impl Timespec {
     }
 
     fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
-            .ok()
-            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
+        let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
         let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
diff --git a/library/std/src/sys/sgx/abi/entry.S b/library/std/src/sys/sgx/abi/entry.S
index ca79d1d796e..8a063b65dac 100644
--- a/library/std/src/sys/sgx/abi/entry.S
+++ b/library/std/src/sys/sgx/abi/entry.S
@@ -26,7 +26,7 @@ IMAGE_BASE:
 .Lxsave_clear:
 .org .+24
 .Lxsave_mxcsr:
-    .short 0x1f80
+    .short 0x1fbf
 
 /*  We can store a bunch of data in the gap between MXCSR and the XSAVE header */
 
@@ -178,6 +178,7 @@ sgx_entry:
     mov $-1, %rax
     mov $-1, %rdx
     xrstor .Lxsave_clear(%rip)
+    lfence
     mov %r10, %rdx
 
 /*  check if returning from usercall */
@@ -311,6 +312,9 @@ usercall:
     movq $0,%gs:tcsls_last_rsp
 /*  restore callee-saved state, cf. "save" above */
     mov %r11,%rsp
+    /* MCDT mitigation requires an lfence after ldmxcsr _before_ any of the affected  */
+    /* vector instructions is used. We omit the lfence here as one is required before */
+    /* the jmp instruction anyway. */
     ldmxcsr (%rsp)
     fldcw 4(%rsp)
     add $8, %rsp
diff --git a/library/std/src/sys/solid/time.rs b/library/std/src/sys/solid/time.rs
index ce31cb45a69..f83f1644fe8 100644
--- a/library/std/src/sys/solid/time.rs
+++ b/library/std/src/sys/solid/time.rs
@@ -47,10 +47,10 @@ impl SystemTime {
     }
 
     pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_add(other.as_secs().try_into().ok()?)?))
+        Some(SystemTime(self.0.checked_add_unsigned(other.as_secs())?))
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_sub(other.as_secs().try_into().ok()?)?))
+        Some(SystemTime(self.0.checked_sub_unsigned(other.as_secs())?))
     }
 }
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 15070b1f6a7..7307d9b2c86 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -326,6 +326,25 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
         } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
             use crate::ptr;
 
+            #[cfg(target_os = "freebsd")]
+            {
+                let mut set: libc::cpuset_t = unsafe { mem::zeroed() };
+                unsafe {
+                    if libc::cpuset_getaffinity(
+                        libc::CPU_LEVEL_WHICH,
+                        libc::CPU_WHICH_PID,
+                        -1,
+                        mem::size_of::<libc::cpuset_t>(),
+                        &mut set,
+                    ) == 0 {
+                        let count = libc::CPU_COUNT(&set) as usize;
+                        if count > 0 {
+                            return Ok(NonZeroUsize::new_unchecked(count));
+                        }
+                    }
+                }
+            }
+
             let mut cpus: libc::c_uint = 0;
             let mut cpus_size = crate::mem::size_of_val(&cpus);
 
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index a61d926ca8b..a9fbc7ab108 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -113,11 +113,7 @@ impl Timespec {
     }
 
     pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `i64`
-            .ok()
-            .and_then(|secs| self.tv_sec.checked_add(secs))?;
+        let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
@@ -126,15 +122,11 @@ impl Timespec {
             nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
         }
-        Some(Timespec::new(secs, nsec as i64))
+        Some(Timespec::new(secs, nsec.into()))
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `i64`
-            .ok()
-            .and_then(|secs| self.tv_sec.checked_sub(secs))?;
+        let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
         let mut nsec = self.tv_nsec.0 as i32 - other.subsec_nanos() as i32;
@@ -142,7 +134,7 @@ impl Timespec {
             nsec += NSEC_PER_SEC as i32;
             secs = secs.checked_sub(1)?;
         }
-        Some(Timespec::new(secs, nsec as i64))
+        Some(Timespec::new(secs, nsec.into()))
     }
 
     #[allow(dead_code)]
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
index 2e64ae59aff..6ed84806e6d 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/src/time/tests.rs
@@ -1,4 +1,5 @@
 use super::{Duration, Instant, SystemTime, UNIX_EPOCH};
+use core::fmt::Debug;
 #[cfg(not(target_arch = "wasm32"))]
 use test::{black_box, Bencher};
 
@@ -201,6 +202,32 @@ fn since_epoch() {
     assert!(a < hundred_twenty_years);
 }
 
+#[test]
+fn big_math() {
+    // Check that the same result occurs when adding/subtracting each duration one at a time as when
+    // adding/subtracting them all at once.
+    #[track_caller]
+    fn check<T: Eq + Copy + Debug>(start: Option<T>, op: impl Fn(&T, Duration) -> Option<T>) {
+        const DURATIONS: [Duration; 2] =
+            [Duration::from_secs(i64::MAX as _), Duration::from_secs(50)];
+        if let Some(start) = start {
+            assert_eq!(
+                op(&start, DURATIONS.into_iter().sum()),
+                DURATIONS.into_iter().try_fold(start, |t, d| op(&t, d))
+            )
+        }
+    }
+
+    check(SystemTime::UNIX_EPOCH.checked_sub(Duration::from_secs(100)), SystemTime::checked_add);
+    check(SystemTime::UNIX_EPOCH.checked_add(Duration::from_secs(100)), SystemTime::checked_sub);
+
+    let instant = Instant::now();
+    check(instant.checked_sub(Duration::from_secs(100)), Instant::checked_add);
+    check(instant.checked_sub(Duration::from_secs(i64::MAX as _)), Instant::checked_add);
+    check(instant.checked_add(Duration::from_secs(100)), Instant::checked_sub);
+    check(instant.checked_add(Duration::from_secs(i64::MAX as _)), Instant::checked_sub);
+}
+
 macro_rules! bench_instant_threaded {
     ($bench_name:ident, $thread_count:expr) => {
         #[bench]
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index d7c6a884fc8..1041d502669 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -90,6 +90,14 @@ It takes one of the following values:
 For example, for gcc flavor linkers, this issues the `-nodefaultlibs` flag to
 the linker.
 
+## dlltool
+
+On `windows-gnu` targets, this flag controls which dlltool `rustc` invokes to
+generate import libraries when using the [`raw-dylib` link kind](../../reference/items/external-blocks.md#the-link-attribute).
+It takes a path to [the dlltool executable](https://sourceware.org/binutils/docs/binutils/dlltool.html).
+If this flag is not specified, a dlltool executable will be inferred based on
+the host environment and target.
+
 ## embed-bitcode
 
 This flag controls whether or not the compiler embeds LLVM bitcode into object
@@ -574,7 +582,8 @@ change in the future.
 This instructs `rustc` to generate code specifically for a particular processor.
 
 You can run `rustc --print target-cpus` to see the valid options to pass
-here. Each target has a default base CPU. Special values include:
+and the default target CPU for the current buid target.
+Each target has a default base CPU. Special values include:
 
 * `native` can be passed to use the processor of the host machine.
 * `generic` refers to an LLVM target with minimal features but modern tuning.
diff --git a/src/doc/unstable-book/src/language-features/raw-dylib.md b/src/doc/unstable-book/src/language-features/raw-dylib.md
deleted file mode 100644
index 5fd208ae757..00000000000
--- a/src/doc/unstable-book/src/language-features/raw-dylib.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# `raw_dylib`
-
-The tracking issue for this feature is: [#58713]
-
-[#58713]: https://github.com/rust-lang/rust/issues/58713
-
-------------------------
-
-The `raw_dylib` feature allows you to link against the implementations of functions in an `extern`
-block without, on Windows, linking against an import library.
-
-```rust,ignore (partial-example)
-#![feature(raw_dylib)]
-
-#[link(name="library", kind="raw-dylib")]
-extern {
-    fn extern_function(x: i32);
-}
-
-fn main() {
-    unsafe {
-        extern_function(14);
-    }
-}
-```
-
-## Limitations
-
-This feature is unstable for the `x86` architecture, and stable for all other architectures.
-
-This feature is only supported on Windows.
-
-On the `x86` architecture, this feature supports only the `cdecl`, `stdcall`, `system`, `fastcall`, and
-`vectorcall` calling conventions.
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 946c85a205f..c94968b4817 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -811,7 +811,9 @@ impl<'src> Classifier<'src> {
                 | LiteralKind::Str { .. }
                 | LiteralKind::ByteStr { .. }
                 | LiteralKind::RawStr { .. }
-                | LiteralKind::RawByteStr { .. } => Class::String,
+                | LiteralKind::RawByteStr { .. }
+                | LiteralKind::CStr { .. }
+                | LiteralKind::RawCStr { .. } => Class::String,
                 // Number literals.
                 LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number,
             },
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index f5b4a3f5abd..a3be6dd5269 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -391,12 +391,14 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> {
         clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
             get_index_type_id(type_)
         }
+        // The type parameters are converted to generics in `add_generics_and_bounds_as_types`
+        clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
+        clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
+        // Not supported yet
         clean::BareFunction(_)
         | clean::Generic(_)
         | clean::ImplTrait(_)
         | clean::Tuple(_)
-        | clean::Slice(_)
-        | clean::Array(_, _)
         | clean::QPath { .. }
         | clean::Infer => None,
     }
@@ -563,6 +565,30 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
             }
         }
         insert_ty(res, arg.clone(), ty_generics);
+    } else if let Type::Slice(ref ty) = *arg {
+        let mut ty_generics = Vec::new();
+        add_generics_and_bounds_as_types(
+            self_,
+            generics,
+            &ty,
+            tcx,
+            recurse + 1,
+            &mut ty_generics,
+            cache,
+        );
+        insert_ty(res, arg.clone(), ty_generics);
+    } else if let Type::Array(ref ty, _) = *arg {
+        let mut ty_generics = Vec::new();
+        add_generics_and_bounds_as_types(
+            self_,
+            generics,
+            &ty,
+            tcx,
+            recurse + 1,
+            &mut ty_generics,
+            cache,
+        );
+        insert_ty(res, arg.clone(), ty_generics);
     } else {
         // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
         // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject ac84010322a31f4a581dafe26258aa4ac8dea9c
+Subproject 569b648b5831ae8a515e90c80843a5287c3304e
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 158e6caa4de..a48f4c77f85 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -284,6 +284,7 @@ impl<'a> NormalizedPat<'a> {
                     LitKind::Str(sym, _) => Self::LitStr(sym),
                     LitKind::ByteStr(ref bytes, _) => Self::LitBytes(bytes),
                     LitKind::Byte(val) => Self::LitInt(val.into()),
+                    LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
                     LitKind::Char(val) => Self::LitInt(val.into()),
                     LitKind::Int(val, _) => Self::LitInt(val),
                     LitKind::Bool(val) => Self::LitBool(val),
diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
index 03324c66e8e..2f2e84fa35a 100644
--- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::is_expr_unsafe;
 use clippy_utils::{get_parent_node, match_libc_symbol};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, UnsafeSource};
+use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
                 let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
                 let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) {
                     "as_bytes"
-                } else if is_type_diagnostic_item(cx, ty, sym::CStr) {
+                } else if is_type_lang_item(cx, ty, LangItem::CStr) {
                     "to_bytes"
                 } else {
                     return;
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 01927b6b5f1..f75dff46624 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -304,6 +304,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("ByteStr(ref {vec})");
                 chain!(self, "let [{:?}] = **{vec}", vec.value);
             },
+            LitKind::CStr(ref vec, _) => {
+                bind!(self, vec);
+                kind!("CStr(ref {vec})");
+                chain!(self, "let [{:?}] = **{vec}", vec.value);
+            }
             LitKind::Str(s, _) => {
                 bind!(self, s);
                 kind!("Str({s}, _)");
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 99bfc4b5717..7c7ec6d334d 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -211,6 +211,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
         LitKind::ByteStr(ref s, _) => Constant::Binary(Lrc::clone(s)),
+        LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)),
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 81179480ed8..4a57c61406c 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -116,6 +116,11 @@ pub(super) fn handle_needs(
             ignore_reason: "ignored when dlltool for x86_64 is not present",
         },
         Need {
+            name: "needs-dlltool",
+            condition: cache.dlltool,
+            ignore_reason: "ignored when dlltool for the current architecture is not present",
+        },
+        Need {
             name: "needs-git-hash",
             condition: config.git_hash,
             ignore_reason: "ignored when git hashes have been omitted for building",
@@ -183,6 +188,7 @@ pub(super) struct CachedNeedsConditions {
     rust_lld: bool,
     i686_dlltool: bool,
     x86_64_dlltool: bool,
+    dlltool: bool,
 }
 
 impl CachedNeedsConditions {
@@ -190,6 +196,17 @@ impl CachedNeedsConditions {
         let path = std::env::var_os("PATH").expect("missing PATH environment variable");
         let path = std::env::split_paths(&path).collect::<Vec<_>>();
 
+        // On Windows, dlltool.exe is used for all architectures.
+        #[cfg(windows)]
+        let dlltool = path.iter().any(|dir| dir.join("dlltool.exe").is_file());
+
+        // For non-Windows, there are architecture specific dlltool binaries.
+        #[cfg(not(windows))]
+        let i686_dlltool = path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file());
+        #[cfg(not(windows))]
+        let x86_64_dlltool =
+            path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file());
+
         let target = &&*config.target;
         Self {
             sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(),
@@ -225,17 +242,26 @@ impl CachedNeedsConditions {
                 .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" })
                 .exists(),
 
-            // On Windows, dlltool.exe is used for all architectures.
             #[cfg(windows)]
-            i686_dlltool: path.iter().any(|dir| dir.join("dlltool.exe").is_file()),
+            i686_dlltool: dlltool,
             #[cfg(windows)]
-            x86_64_dlltool: path.iter().any(|dir| dir.join("dlltool.exe").is_file()),
+            x86_64_dlltool: dlltool,
+            #[cfg(windows)]
+            dlltool,
 
             // For non-Windows, there are architecture specific dlltool binaries.
             #[cfg(not(windows))]
-            i686_dlltool: path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file()),
+            i686_dlltool,
+            #[cfg(not(windows))]
+            x86_64_dlltool,
             #[cfg(not(windows))]
-            x86_64_dlltool: path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file()),
+            dlltool: if config.matches_arch("x86") {
+                i686_dlltool
+            } else if config.matches_arch("x86_64") {
+                x86_64_dlltool
+            } else {
+                false
+            },
         }
     }
 }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index a4be7af886b..841f5b4f6ee 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -319,7 +319,8 @@ impl<'test> TestCx<'test> {
 
     fn run_cfail_test(&self) {
         let pm = self.pass_mode();
-        let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm));
+        let proc_res =
+            self.compile_test(WillExecute::No, self.should_emit_metadata(pm), Vec::new());
         self.check_if_test_should_compile(&proc_res, pm);
         self.check_no_compiler_crash(&proc_res, self.props.should_ice);
 
@@ -347,7 +348,7 @@ impl<'test> TestCx<'test> {
     fn run_rfail_test(&self) {
         let pm = self.pass_mode();
         let should_run = self.run_if_enabled();
-        let proc_res = self.compile_test(should_run, self.should_emit_metadata(pm));
+        let proc_res = self.compile_test(should_run, self.should_emit_metadata(pm), Vec::new());
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
@@ -395,7 +396,7 @@ impl<'test> TestCx<'test> {
 
     fn run_cpass_test(&self) {
         let emit_metadata = self.should_emit_metadata(self.pass_mode());
-        let proc_res = self.compile_test(WillExecute::No, emit_metadata);
+        let proc_res = self.compile_test(WillExecute::No, emit_metadata, Vec::new());
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
@@ -410,7 +411,7 @@ impl<'test> TestCx<'test> {
     fn run_rpass_test(&self) {
         let emit_metadata = self.should_emit_metadata(self.pass_mode());
         let should_run = self.run_if_enabled();
-        let proc_res = self.compile_test(should_run, emit_metadata);
+        let proc_res = self.compile_test(should_run, emit_metadata, Vec::new());
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
@@ -440,7 +441,7 @@ impl<'test> TestCx<'test> {
         }
 
         let should_run = self.run_if_enabled();
-        let mut proc_res = self.compile_test(should_run, Emit::None);
+        let mut proc_res = self.compile_test(should_run, Emit::None, Vec::new());
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
@@ -686,7 +687,7 @@ impl<'test> TestCx<'test> {
 
         // compile test file (it should have 'compile-flags:-g' in the header)
         let should_run = self.run_if_enabled();
-        let compile_result = self.compile_test(should_run, Emit::None);
+        let compile_result = self.compile_test(should_run, Emit::None, Vec::new());
         if !compile_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compile_result);
         }
@@ -806,7 +807,7 @@ impl<'test> TestCx<'test> {
 
         // compile test file (it should have 'compile-flags:-g' in the header)
         let should_run = self.run_if_enabled();
-        let compiler_run_result = self.compile_test(should_run, Emit::None);
+        let compiler_run_result = self.compile_test(should_run, Emit::None, Vec::new());
         if !compiler_run_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compiler_run_result);
         }
@@ -1043,7 +1044,7 @@ impl<'test> TestCx<'test> {
     fn run_debuginfo_lldb_test_no_opt(&self) {
         // compile test file (it should have 'compile-flags:-g' in the header)
         let should_run = self.run_if_enabled();
-        let compile_result = self.compile_test(should_run, Emit::None);
+        let compile_result = self.compile_test(should_run, Emit::None, Vec::new());
         if !compile_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compile_result);
         }
@@ -1482,8 +1483,8 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn compile_test(&self, will_execute: WillExecute, emit: Emit) -> ProcRes {
-        self.compile_test_general(will_execute, emit, self.props.local_pass_mode())
+    fn compile_test(&self, will_execute: WillExecute, emit: Emit, passes: Vec<String>) -> ProcRes {
+        self.compile_test_general(will_execute, emit, self.props.local_pass_mode(), passes)
     }
 
     fn compile_test_general(
@@ -1491,6 +1492,7 @@ impl<'test> TestCx<'test> {
         will_execute: WillExecute,
         emit: Emit,
         local_pm: Option<PassMode>,
+        passes: Vec<String>,
     ) -> ProcRes {
         // Only use `make_exe_name` when the test ends up being executed.
         let output_file = match will_execute {
@@ -1527,6 +1529,7 @@ impl<'test> TestCx<'test> {
             emit,
             allow_unused,
             LinkToAux::Yes,
+            passes,
         );
 
         self.compose_and_run_compiler(rustc, None)
@@ -1777,6 +1780,7 @@ impl<'test> TestCx<'test> {
             Emit::None,
             AllowUnused::No,
             LinkToAux::No,
+            Vec::new(),
         );
 
         for key in &aux_props.unset_rustc_env {
@@ -1908,6 +1912,7 @@ impl<'test> TestCx<'test> {
         emit: Emit,
         allow_unused: AllowUnused,
         link_to_aux: LinkToAux,
+        passes: Vec<String>, // Vec of passes under mir-opt test to be dumped
     ) -> Command {
         let is_aux = input_file.components().map(|c| c.as_os_str()).any(|c| c == "auxiliary");
         let is_rustdoc = self.is_rustdoc() && !is_aux;
@@ -2008,9 +2013,18 @@ impl<'test> TestCx<'test> {
                 rustc.arg("-Cstrip=debuginfo");
             }
             MirOpt => {
+                // We check passes under test to minimize the mir-opt test dump
+                // if files_for_miropt_test parses the passes, we dump only those passes
+                // otherwise we conservatively pass -Zdump-mir=all
+                let zdump_arg = if !passes.is_empty() {
+                    format!("-Zdump-mir={}", passes.join(" | "))
+                } else {
+                    "-Zdump-mir=all".to_string()
+                };
+
                 rustc.args(&[
                     "-Copt-level=1",
-                    "-Zdump-mir=all",
+                    &zdump_arg,
                     "-Zvalidate-mir",
                     "-Zdump-mir-exclude-pass-number",
                     "-Zmir-pretty-relative-line-numbers=yes",
@@ -2333,6 +2347,7 @@ impl<'test> TestCx<'test> {
             Emit::LlvmIr,
             AllowUnused::No,
             LinkToAux::Yes,
+            Vec::new(),
         );
 
         self.compose_and_run_compiler(rustc, None)
@@ -2364,8 +2379,14 @@ impl<'test> TestCx<'test> {
             None => self.fatal("missing 'assembly-output' header"),
         }
 
-        let rustc =
-            self.make_compile_args(input_file, output_file, emit, AllowUnused::No, LinkToAux::Yes);
+        let rustc = self.make_compile_args(
+            input_file,
+            output_file,
+            emit,
+            AllowUnused::No,
+            LinkToAux::Yes,
+            Vec::new(),
+        );
 
         (self.compose_and_run_compiler(rustc, None), output_path)
     }
@@ -2496,6 +2517,7 @@ impl<'test> TestCx<'test> {
             Emit::None,
             AllowUnused::Yes,
             LinkToAux::Yes,
+            Vec::new(),
         );
         new_rustdoc.build_all_auxiliary(&mut rustc);
 
@@ -2769,7 +2791,7 @@ impl<'test> TestCx<'test> {
     fn run_codegen_units_test(&self) {
         assert!(self.revision.is_none(), "revisions not relevant here");
 
-        let proc_res = self.compile_test(WillExecute::No, Emit::None);
+        let proc_res = self.compile_test(WillExecute::No, Emit::None, Vec::new());
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
@@ -3310,14 +3332,15 @@ impl<'test> TestCx<'test> {
         if let Some(FailMode::Build) = self.props.fail_mode {
             // Make sure a build-fail test cannot fail due to failing analysis (e.g. typeck).
             let pm = Some(PassMode::Check);
-            let proc_res = self.compile_test_general(WillExecute::No, Emit::Metadata, pm);
+            let proc_res =
+                self.compile_test_general(WillExecute::No, Emit::Metadata, pm, Vec::new());
             self.check_if_test_should_compile(&proc_res, pm);
         }
 
         let pm = self.pass_mode();
         let should_run = self.should_run(pm);
         let emit_metadata = self.should_emit_metadata(pm);
-        let proc_res = self.compile_test(should_run, emit_metadata);
+        let proc_res = self.compile_test(should_run, emit_metadata, Vec::new());
         self.check_if_test_should_compile(&proc_res, pm);
 
         // if the user specified a format in the ui test
@@ -3479,6 +3502,7 @@ impl<'test> TestCx<'test> {
                 emit_metadata,
                 AllowUnused::No,
                 LinkToAux::Yes,
+                Vec::new(),
             );
             let res = self.compose_and_run_compiler(rustc, None);
             if !res.status.success() {
@@ -3497,14 +3521,14 @@ impl<'test> TestCx<'test> {
         let pm = self.pass_mode();
         let should_run = self.should_run(pm);
         let emit_metadata = self.should_emit_metadata(pm);
-        let proc_res = self.compile_test(should_run, emit_metadata);
+        let passes = self.get_passes();
 
+        let proc_res = self.compile_test(should_run, emit_metadata, passes);
+        self.check_mir_dump();
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
-        self.check_mir_dump();
-
         if let WillExecute::Yes = should_run {
             let proc_res = self.exec_compiled_test();
 
@@ -3514,6 +3538,26 @@ impl<'test> TestCx<'test> {
         }
     }
 
+    fn get_passes(&self) -> Vec<String> {
+        let files = miropt_test_tools::files_for_miropt_test(
+            &self.testpaths.file,
+            self.config.get_pointer_width(),
+        );
+
+        let mut out = Vec::new();
+
+        for miropt_test_tools::MiroptTestFiles {
+            from_file: _,
+            to_file: _,
+            expected_file: _,
+            passes,
+        } in files
+        {
+            out.extend(passes);
+        }
+        out
+    }
+
     fn check_mir_dump(&self) {
         let test_file_contents = fs::read_to_string(&self.testpaths.file).unwrap();
 
@@ -3543,8 +3587,9 @@ impl<'test> TestCx<'test> {
             &self.testpaths.file,
             self.config.get_pointer_width(),
         );
-
-        for miropt_test_tools::MiroptTestFiles { from_file, to_file, expected_file } in files {
+        for miropt_test_tools::MiroptTestFiles { from_file, to_file, expected_file, passes: _ } in
+            files
+        {
             let dumped_string = if let Some(after) = to_file {
                 self.diff_mir_files(from_file.into(), after.into())
             } else {
diff --git a/src/tools/miropt-test-tools/src/lib.rs b/src/tools/miropt-test-tools/src/lib.rs
index cfba7d583b1..f86c3ce0afe 100644
--- a/src/tools/miropt-test-tools/src/lib.rs
+++ b/src/tools/miropt-test-tools/src/lib.rs
@@ -4,6 +4,8 @@ pub struct MiroptTestFiles {
     pub expected_file: std::path::PathBuf,
     pub from_file: String,
     pub to_file: Option<String>,
+    /// Vec of passes under test to be dumped
+    pub passes: Vec<String>,
 }
 
 pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<MiroptTestFiles> {
@@ -28,9 +30,11 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<
             let mut expected_file;
             let from_file;
             let to_file;
+            let mut passes = Vec::new();
 
             if test_name.ends_with(".diff") {
                 let trimmed = test_name.trim_end_matches(".diff");
+                passes.push(trimmed.split('.').last().unwrap().to_owned());
                 let test_against = format!("{}.after.mir", trimmed);
                 from_file = format!("{}.before.mir", trimmed);
                 expected_file = format!("{}{}.diff", trimmed, bit_width);
@@ -38,7 +42,14 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<
                 to_file = Some(test_against);
             } else if let Some(first_pass) = test_names.next() {
                 let second_pass = test_names.next().unwrap();
+                if let Some((first_pass_name, _)) = first_pass.split_once('.') {
+                    passes.push(first_pass_name.to_owned());
+                }
+                if let Some((second_pass_name, _)) = second_pass.split_once('.') {
+                    passes.push(second_pass_name.to_owned());
+                }
                 assert!(test_names.next().is_none(), "three mir pass names specified for MIR diff");
+
                 expected_file =
                     format!("{}{}.{}-{}.diff", test_name, bit_width, first_pass, second_pass);
                 let second_file = format!("{}.{}.mir", test_name, second_pass);
@@ -51,18 +62,24 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<
                     .next()
                     .expect("test_name has an invalid extension");
                 let extension = cap.get(1).unwrap().as_str();
+
                 expected_file =
                     format!("{}{}{}", test_name.trim_end_matches(extension), bit_width, extension,);
                 from_file = test_name.to_string();
                 assert!(test_names.next().is_none(), "two mir pass names specified for MIR dump");
                 to_file = None;
+                // the pass name is the third to last string in the test name
+                // this gets pushed into passes
+                passes.push(
+                    test_name.split('.').rev().nth(2).expect("invalid test format").to_string(),
+                );
             };
             if !expected_file.starts_with(&test_crate) {
                 expected_file = format!("{}.{}", test_crate, expected_file);
             }
             let expected_file = test_dir.join(expected_file);
 
-            out.push(MiroptTestFiles { expected_file, from_file, to_file });
+            out.push(MiroptTestFiles { expected_file, from_file, to_file, passes });
         }
     }
 
diff --git a/tests/codegen/align-offset.rs b/tests/codegen/align-offset.rs
new file mode 100644
index 00000000000..7c7660c5a55
--- /dev/null
+++ b/tests/codegen/align-offset.rs
@@ -0,0 +1,78 @@
+// compile-flags: -O
+// min-llvm-version: 15.0 (because we're using opaque pointers)
+// ignore-debug (debug assertions in `slice::from_raw_parts` block optimizations)
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @align8
+#[no_mangle]
+pub fn align8(p: *const u8) -> bool {
+    // CHECK: ret i1 true
+    p.align_offset(8) < 8
+}
+
+#[repr(align(4))]
+pub struct Align4([u8; 4]);
+
+// CHECK-LABEL: @align_to4
+#[no_mangle]
+pub fn align_to4(x: &[u8]) -> bool {
+    // CHECK: ret i1 true
+    let (prefix, _middle, suffix) = unsafe { x.align_to::<Align4>() };
+    prefix.len() < 4 && suffix.len() < 4
+}
+
+// CHECK-LABEL: @align_offset_byte_ptr(ptr{{.+}}%ptr)
+#[no_mangle]
+pub fn align_offset_byte_ptr(ptr: *const u8) -> usize {
+    // CHECK: %[[ADDR:.+]] = ptrtoint ptr %ptr to [[USIZE:i[0-9]+]]
+    // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31
+    // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32
+    // CHECK: %[[OFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]]
+
+    // Since we're offsetting a byte pointer, there's no further fixups
+    // CHECK-NOT: shr
+    // CHECK-NOT: div
+    // CHECK-NOT: select
+
+    // CHECK: ret [[USIZE]] %[[OFFSET]]
+    ptr.align_offset(32)
+}
+
+// CHECK-LABEL: @align_offset_word_slice(ptr{{.+}}align 4{{.+}}%slice.0
+#[no_mangle]
+pub fn align_offset_word_slice(slice: &[Align4]) -> usize {
+    // CHECK: %[[ADDR:.+]] = ptrtoint ptr %slice.0 to [[USIZE]]
+    // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31
+    // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32
+    // CHECK: %[[BOFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]]
+    // CHECK: %[[OFFSET:.+]] = lshr exact [[USIZE]] %[[BOFFSET]], 2
+
+    // Slices are known to be aligned, so we don't need the "maybe -1" path
+    // CHECK-NOT: select
+
+    // CHECK: ret [[USIZE]] %[[OFFSET]]
+    slice.as_ptr().align_offset(32)
+}
+
+
+// CHECK-LABEL: @align_offset_word_ptr(ptr{{.+}}%ptr
+#[no_mangle]
+pub fn align_offset_word_ptr(ptr: *const Align4) -> usize {
+    // CHECK: %[[ADDR:.+]] = ptrtoint ptr %ptr to [[USIZE]]
+    // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31
+    // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32
+    // CHECK: %[[BOFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]]
+
+    // While we can always get a *byte* offset that will work, if the original
+    // pointer is unaligned it might be impossible to return an *element* offset
+    // that will make it aligned. We want it to be a `select`, not a `br`, so
+    // that the assembly will be branchless.
+    // CHECK: %[[LOW:.+]] = and [[USIZE]] %[[ADDR]], 3
+    // CHECK: %[[ORIGINAL_ALIGNED:.+]] = icmp eq [[USIZE]] %[[LOW]], 0
+    // CHECK: %[[OFFSET:.+]] = lshr exact [[USIZE]] %[[BOFFSET]], 2
+    // CHECK: %[[R:.+]] = select i1 %[[ORIGINAL_ALIGNED]], [[USIZE]] %[[OFFSET]], [[USIZE]] -1
+
+    // CHECK: ret [[USIZE]] %[[R]]
+    ptr.align_offset(32)
+}
diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
index 9b69f79c28e..169e99deee7 100644
--- a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
@@ -21,42 +21,42 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 8, align: 4) {
-    ╾─alloc18─╼ 03 00 00 00                         │ ╾──╼....
+    ╾─alloc19─╼ 03 00 00 00                         │ ╾──╼....
 }
 
-alloc18 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc5──╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc13─╼ 03 00 00 00 │ ....*...╾──╼....
+alloc19 (size: 48, align: 4) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc6──╼ 00 00 00 00 │ ....░░░░╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc9──╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc14─╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
-alloc5 (size: 0, align: 4) {}
+alloc6 (size: 0, align: 4) {}
 
-alloc8 (size: 16, align: 4) {
-    ╾─alloc9──╼ 03 00 00 00 ╾─alloc10─╼ 03 00 00 00 │ ╾──╼....╾──╼....
+alloc9 (size: 16, align: 4) {
+    ╾─alloc10─╼ 03 00 00 00 ╾─alloc11─╼ 03 00 00 00 │ ╾──╼....╾──╼....
 }
 
-alloc9 (size: 3, align: 1) {
+alloc10 (size: 3, align: 1) {
     66 6f 6f                                        │ foo
 }
 
-alloc10 (size: 3, align: 1) {
+alloc11 (size: 3, align: 1) {
     62 61 72                                        │ bar
 }
 
-alloc13 (size: 24, align: 4) {
-    0x00 │ ╾─alloc14─╼ 03 00 00 00 ╾─alloc15─╼ 03 00 00 00 │ ╾──╼....╾──╼....
-    0x10 │ ╾─alloc16─╼ 04 00 00 00                         │ ╾──╼....
+alloc14 (size: 24, align: 4) {
+    0x00 │ ╾─alloc15─╼ 03 00 00 00 ╾─alloc16─╼ 03 00 00 00 │ ╾──╼....╾──╼....
+    0x10 │ ╾─alloc17─╼ 04 00 00 00                         │ ╾──╼....
 }
 
-alloc14 (size: 3, align: 1) {
+alloc15 (size: 3, align: 1) {
     6d 65 68                                        │ meh
 }
 
-alloc15 (size: 3, align: 1) {
+alloc16 (size: 3, align: 1) {
     6d 6f 70                                        │ mop
 }
 
-alloc16 (size: 4, align: 1) {
+alloc17 (size: 4, align: 1) {
     6d c3 b6 70                                     │ m..p
 }
diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
index d0f196e7245..db1f9648843 100644
--- a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
@@ -21,46 +21,46 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 16, align: 8) {
-    ╾───────alloc18───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾───────alloc19───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc18 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc5────────╼ │ ....░░░░╾──────╼
+alloc19 (size: 72, align: 8) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc6────────╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾───────alloc8────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc13───────╼ │ ....*...╾──────╼
+    0x20 │ ╾───────alloc9────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc14───────╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
-alloc5 (size: 0, align: 8) {}
+alloc6 (size: 0, align: 8) {}
 
-alloc8 (size: 32, align: 8) {
-    0x00 │ ╾───────alloc9────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x10 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+alloc9 (size: 32, align: 8) {
+    0x00 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x10 │ ╾───────alloc11───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc9 (size: 3, align: 1) {
+alloc10 (size: 3, align: 1) {
     66 6f 6f                                        │ foo
 }
 
-alloc10 (size: 3, align: 1) {
+alloc11 (size: 3, align: 1) {
     62 61 72                                        │ bar
 }
 
-alloc13 (size: 48, align: 8) {
-    0x00 │ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x10 │ ╾───────alloc15───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x20 │ ╾───────alloc16───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+alloc14 (size: 48, align: 8) {
+    0x00 │ ╾───────alloc15───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x10 │ ╾───────alloc16───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x20 │ ╾───────alloc17───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc14 (size: 3, align: 1) {
+alloc15 (size: 3, align: 1) {
     6d 65 68                                        │ meh
 }
 
-alloc15 (size: 3, align: 1) {
+alloc16 (size: 3, align: 1) {
     6d 6f 70                                        │ mop
 }
 
-alloc16 (size: 4, align: 1) {
+alloc17 (size: 4, align: 1) {
     6d c3 b6 70                                     │ m..p
 }
diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
index aab005c52d6..999acb48afe 100644
--- a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
@@ -21,41 +21,41 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 8, align: 4) {
-    ╾─alloc22─╼ 03 00 00 00                         │ ╾──╼....
+    ╾─alloc23─╼ 03 00 00 00                         │ ╾──╼....
 }
 
-alloc22 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc9──╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc14─╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc20─╼ 03 00 00 00 │ ....*...╾──╼....
+alloc23 (size: 48, align: 4) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc10─╼ 00 00 00 00 │ ....░░░░╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc15─╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc21─╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
-alloc9 (size: 0, align: 4) {}
+alloc10 (size: 0, align: 4) {}
 
-alloc14 (size: 8, align: 4) {
-    ╾─alloc12─╼ ╾─alloc13─╼                         │ ╾──╼╾──╼
+alloc15 (size: 8, align: 4) {
+    ╾─alloc13─╼ ╾─alloc14─╼                         │ ╾──╼╾──╼
 }
 
-alloc12 (size: 1, align: 1) {
+alloc13 (size: 1, align: 1) {
     05                                              │ .
 }
 
-alloc13 (size: 1, align: 1) {
+alloc14 (size: 1, align: 1) {
     06                                              │ .
 }
 
-alloc20 (size: 12, align: 4) {
-    ╾─a17+0x3─╼ ╾─alloc18─╼ ╾─a19+0x2─╼             │ ╾──╼╾──╼╾──╼
+alloc21 (size: 12, align: 4) {
+    ╾─a18+0x3─╼ ╾─alloc19─╼ ╾─a20+0x2─╼             │ ╾──╼╾──╼╾──╼
 }
 
-alloc17 (size: 4, align: 1) {
+alloc18 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
 
-alloc18 (size: 1, align: 1) {
+alloc19 (size: 1, align: 1) {
     2a                                              │ *
 }
 
-alloc19 (size: 4, align: 1) {
+alloc20 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
index 0eff9474c20..30311890eee 100644
--- a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
@@ -21,44 +21,44 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 16, align: 8) {
-    ╾───────alloc22───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾───────alloc23───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc22 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc9────────╼ │ ....░░░░╾──────╼
+alloc23 (size: 72, align: 8) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc10───────╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾───────alloc14───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc20───────╼ │ ....*...╾──────╼
+    0x20 │ ╾───────alloc15───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc21───────╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
-alloc9 (size: 0, align: 8) {}
+alloc10 (size: 0, align: 8) {}
 
-alloc14 (size: 16, align: 8) {
-    ╾───────alloc12───────╼ ╾───────alloc13───────╼ │ ╾──────╼╾──────╼
+alloc15 (size: 16, align: 8) {
+    ╾───────alloc13───────╼ ╾───────alloc14───────╼ │ ╾──────╼╾──────╼
 }
 
-alloc12 (size: 1, align: 1) {
+alloc13 (size: 1, align: 1) {
     05                                              │ .
 }
 
-alloc13 (size: 1, align: 1) {
+alloc14 (size: 1, align: 1) {
     06                                              │ .
 }
 
-alloc20 (size: 24, align: 8) {
-    0x00 │ ╾─────alloc17+0x3─────╼ ╾───────alloc18───────╼ │ ╾──────╼╾──────╼
-    0x10 │ ╾─────alloc19+0x2─────╼                         │ ╾──────╼
+alloc21 (size: 24, align: 8) {
+    0x00 │ ╾─────alloc18+0x3─────╼ ╾───────alloc19───────╼ │ ╾──────╼╾──────╼
+    0x10 │ ╾─────alloc20+0x2─────╼                         │ ╾──────╼
 }
 
-alloc17 (size: 4, align: 1) {
+alloc18 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
 
-alloc18 (size: 1, align: 1) {
+alloc19 (size: 1, align: 1) {
     2a                                              │ *
 }
 
-alloc19 (size: 4, align: 1) {
+alloc20 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
index 55c6db5d0ce..d592e59fafd 100644
--- a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
@@ -21,30 +21,30 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 4, align: 4) {
-    ╾─alloc11─╼                                     │ ╾──╼
+    ╾─alloc12─╼                                     │ ╾──╼
 }
 
-alloc11 (size: 168, align: 1) {
+alloc12 (size: 168, align: 1) {
     0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
-    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc6──╼ │ ............╾──╼
+    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc7──╼ │ ............╾──╼
     0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-    0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc8──╼ 00 00 │ ..........╾──╼..
-    0x90 │ ╾─a9+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
+    0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc9──╼ 00 00 │ ..........╾──╼..
+    0x90 │ ╾a10+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
     0xa0 │ 00 00 00 00 00 00 00 00                         │ ........
 }
 
-alloc6 (size: 4, align: 4) {
+alloc7 (size: 4, align: 4) {
     2a 00 00 00                                     │ *...
 }
 
-alloc8 (fn: main)
+alloc9 (fn: main)
 
-alloc9 (size: 100, align: 1) {
+alloc10 (size: 100, align: 1) {
     0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
index 27492a7fd22..ca53b28be7c 100644
--- a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
@@ -21,12 +21,12 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 8, align: 8) {
-    ╾───────alloc11───────╼                         │ ╾──────╼
+    ╾───────alloc12───────╼                         │ ╾──────╼
 }
 
-alloc11 (size: 180, align: 1) {
+alloc12 (size: 180, align: 1) {
     0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
-    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc6── │ ............╾───
+    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc7── │ ............╾───
     0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............
     0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
@@ -34,18 +34,18 @@ alloc11 (size: 180, align: 1) {
     0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─
-    0x90 │ ─────alloc8─────╼ 00 00 ╾─────alloc9+0x63─────╼ │ ─────╼..╾──────╼
+    0x90 │ ─────alloc9─────╼ 00 00 ╾────alloc10+0x63─────╼ │ ─────╼..╾──────╼
     0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0xb0 │ 00 00 00 00                                     │ ....
 }
 
-alloc6 (size: 4, align: 4) {
+alloc7 (size: 4, align: 4) {
     2a 00 00 00                                     │ *...
 }
 
-alloc8 (fn: main)
+alloc9 (fn: main)
 
-alloc9 (size: 100, align: 1) {
+alloc10 (size: 100, align: 1) {
     0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
diff --git a/tests/run-make/raw-dylib-alt-calling-convention/lib.rs b/tests/run-make/raw-dylib-alt-calling-convention/lib.rs
index 22f222c12c3..dcb5fee9ecc 100644
--- a/tests/run-make/raw-dylib-alt-calling-convention/lib.rs
+++ b/tests/run-make/raw-dylib-alt-calling-convention/lib.rs
@@ -1,5 +1,4 @@
 #![feature(abi_vectorcall)]
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[repr(C)]
 #[derive(Clone)]
diff --git a/tests/run-make/raw-dylib-c/lib.rs b/tests/run-make/raw-dylib-c/lib.rs
index 5fb1204037c..f17125f308c 100644
--- a/tests/run-make/raw-dylib-c/lib.rs
+++ b/tests/run-make/raw-dylib-c/lib.rs
@@ -1,5 +1,3 @@
-#![feature(raw_dylib)]
-
 #[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")]
 extern {
     fn extern_fn_1();
diff --git a/tests/run-make/raw-dylib-cross-compilation/lib.rs b/tests/run-make/raw-dylib-cross-compilation/lib.rs
index 51bf2ec6b6e..3338ac0a0b5 100644
--- a/tests/run-make/raw-dylib-cross-compilation/lib.rs
+++ b/tests/run-make/raw-dylib-cross-compilation/lib.rs
@@ -1,4 +1,3 @@
-#![feature(raw_dylib)]
 #![feature(no_core, lang_items)]
 #![no_std]
 #![no_core]
diff --git a/tests/run-make/raw-dylib-custom-dlltool/Makefile b/tests/run-make/raw-dylib-custom-dlltool/Makefile
new file mode 100644
index 00000000000..f5d5360a3fb
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/Makefile
@@ -0,0 +1,11 @@
+# Test using -Cdlltool to change where raw-dylib looks for the dlltool binary.
+
+# only-windows
+# only-gnu
+# needs-dlltool
+
+include ../tools.mk
+
+all:
+	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs -Cdlltool=$(CURDIR)/script.cmd
+	$(DIFF) output.txt "$(TMPDIR)"/output.txt
diff --git a/tests/run-make/raw-dylib-custom-dlltool/lib.rs b/tests/run-make/raw-dylib-custom-dlltool/lib.rs
new file mode 100644
index 00000000000..2f3f497a00d
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/lib.rs
@@ -0,0 +1,10 @@
+#[link(name = "extern_1", kind = "raw-dylib")]
+extern {
+    fn extern_fn_1();
+}
+
+pub fn library_function() {
+    unsafe {
+        extern_fn_1();
+    }
+}
diff --git a/tests/run-make/raw-dylib-custom-dlltool/output.txt b/tests/run-make/raw-dylib-custom-dlltool/output.txt
new file mode 100644
index 00000000000..6dd9466d26d
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/output.txt
@@ -0,0 +1 @@
+Called dlltool via script.cmd
diff --git a/tests/run-make/raw-dylib-custom-dlltool/script.cmd b/tests/run-make/raw-dylib-custom-dlltool/script.cmd
new file mode 100644
index 00000000000..95f85c61c67
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/script.cmd
@@ -0,0 +1,2 @@
+echo Called dlltool via script.cmd> %TMPDIR%\output.txt
+dlltool.exe %*
diff --git a/tests/run-make/raw-dylib-import-name-type/driver.rs b/tests/run-make/raw-dylib-import-name-type/driver.rs
index 9a3cd9ebe1b..6c1c212f187 100644
--- a/tests/run-make/raw-dylib-import-name-type/driver.rs
+++ b/tests/run-make/raw-dylib-import-name-type/driver.rs
@@ -1,4 +1,3 @@
-#![feature(raw_dylib)]
 #![feature(abi_vectorcall)]
 
 #[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs b/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs
index f72ded7d9f6..0c3125be6f5 100644
--- a/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs
+++ b/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs
@@ -1,5 +1,3 @@
-#![feature(raw_dylib)]
-
 extern crate raw_dylib_test;
 extern crate raw_dylib_test_wrapper;
 
diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs b/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs
index 00c2c1c42d1..4877cb80aea 100644
--- a/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs
+++ b/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs
@@ -1,5 +1,3 @@
-#![feature(raw_dylib)]
-
 #[link(name = "extern_1", kind = "raw-dylib")]
 extern {
     fn extern_fn_1();
diff --git a/tests/run-make/raw-dylib-link-ordinal/lib.rs b/tests/run-make/raw-dylib-link-ordinal/lib.rs
index bb25ac64c61..1bbb45bbc77 100644
--- a/tests/run-make/raw-dylib-link-ordinal/lib.rs
+++ b/tests/run-make/raw-dylib-link-ordinal/lib.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "exporter", kind = "raw-dylib")]
 extern {
     #[link_ordinal(13)]
diff --git a/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs b/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs
index b7921396a0f..74c5c7f8250 100644
--- a/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs
+++ b/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "exporter", kind = "raw-dylib")]
 extern "stdcall" {
     #[link_ordinal(15)]
diff --git a/tests/rustdoc-js/slice-array.js b/tests/rustdoc-js/slice-array.js
new file mode 100644
index 00000000000..8c21e06dc4e
--- /dev/null
+++ b/tests/rustdoc-js/slice-array.js
@@ -0,0 +1,65 @@
+// exact-check
+
+const QUERY = [
+    'R<primitive:slice<P>>',
+    'primitive:slice<R<P>>',
+    'R<primitive:slice<Q>>',
+    'primitive:slice<R<Q>>',
+    'R<primitive:array<Q>>',
+    'primitive:array<R<Q>>',
+    'primitive:array<TraitCat>',
+    'primitive:array<TraitDog>',
+];
+
+const EXPECTED = [
+    {
+        // R<primitive:slice<P>>
+        'returned': [],
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'alpha' },
+        ],
+    },
+    {
+        // primitive:slice<R<P>>
+        'returned': [
+            { 'path': 'slice_array', 'name': 'alef' },
+        ],
+        'in_args': [],
+    },
+    {
+        // R<primitive:slice<Q>>
+        'returned': [],
+        'in_args': [],
+    },
+    {
+        // primitive:slice<R<Q>>
+        'returned': [],
+        'in_args': [],
+    },
+    {
+        // R<primitive:array<Q>>
+        'returned': [
+            { 'path': 'slice_array', 'name': 'bet' },
+        ],
+        'in_args': [],
+    },
+    {
+        // primitive:array<R<Q>>
+        'returned': [],
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'beta' },
+        ],
+    },
+    {
+        // primitive::array<TraitCat>
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'gamma' },
+        ],
+    },
+    {
+        // primitive::array<TraitDog>
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'gamma' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/slice-array.rs b/tests/rustdoc-js/slice-array.rs
new file mode 100644
index 00000000000..2523b21cfaa
--- /dev/null
+++ b/tests/rustdoc-js/slice-array.rs
@@ -0,0 +1,16 @@
+pub struct P;
+pub struct Q;
+pub struct R<T>(T);
+
+// returns test
+pub fn alef() -> &'static [R<P>] { loop {} }
+pub fn bet() -> R<[Q; 32]> { loop {} }
+
+// in_args test
+pub fn alpha(_x: R<&'static [P]>) { loop {} }
+pub fn beta(_x: [R<Q>; 32]) { loop {} }
+
+pub trait TraitCat {}
+pub trait TraitDog {}
+
+pub fn gamma<T: TraitCat + TraitDog>(t: [T; 32]) {}
diff --git a/tests/rustdoc-ui/check-cfg/check-cfg.stderr b/tests/rustdoc-ui/check-cfg/check-cfg.stderr
index 1db8e1d91c2..03fb6f96fb5 100644
--- a/tests/rustdoc-ui/check-cfg/check-cfg.stderr
+++ b/tests/rustdoc-ui/check-cfg/check-cfg.stderr
@@ -2,7 +2,7 @@ warning: unexpected `cfg` condition name
   --> $DIR/check-cfg.rs:5:7
    |
 LL | #[cfg(uniz)]
-   |       ^^^^ help: did you mean: `unix`
+   |       ^^^^ help: there is a config with a similar name: `unix`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
diff --git a/tests/rustdoc-ui/doctest/check-cfg-test.stderr b/tests/rustdoc-ui/doctest/check-cfg-test.stderr
index 9770be2f191..f84543c2072 100644
--- a/tests/rustdoc-ui/doctest/check-cfg-test.stderr
+++ b/tests/rustdoc-ui/doctest/check-cfg-test.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(feature = "invalid")]
    |       ^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: test
+   = note: expected values for `feature` are: `test`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/check-cfg/compact-values.stderr b/tests/ui/check-cfg/compact-values.stderr
index 5ca4d3b3de7..70a967c0e5f 100644
--- a/tests/ui/check-cfg/compact-values.stderr
+++ b/tests/ui/check-cfg/compact-values.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target(os = "linux", arch = "X"))]
    |                            ^^^^^^^^^^
    |
-   = note: expected values for `target_arch` are: aarch64, arm, avr, bpf, hexagon, loongarch64, m68k, mips, mips64, msp430, nvptx64, powerpc, powerpc64, riscv32, riscv64, s390x, sparc, sparc64, wasm32, wasm64, x86, x86_64
+   = note: expected values for `target_arch` are: `aarch64`, `arm`, `avr`, `bpf`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips64`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/check-cfg/diagnotics.rs b/tests/ui/check-cfg/diagnotics.rs
new file mode 100644
index 00000000000..49e127d079a
--- /dev/null
+++ b/tests/ui/check-cfg/diagnotics.rs
@@ -0,0 +1,31 @@
+// check-pass
+// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --check-cfg=values(no_values) -Z unstable-options
+
+#[cfg(featur)]
+//~^ WARNING unexpected `cfg` condition name
+fn feature() {}
+
+#[cfg(featur = "foo")]
+//~^ WARNING unexpected `cfg` condition name
+fn feature() {}
+
+#[cfg(featur = "fo")]
+//~^ WARNING unexpected `cfg` condition name
+fn feature() {}
+
+#[cfg(feature = "foo")]
+fn feature() {}
+
+#[cfg(no_value)]
+//~^ WARNING unexpected `cfg` condition name
+fn no_values() {}
+
+#[cfg(no_value = "foo")]
+//~^ WARNING unexpected `cfg` condition name
+fn no_values() {}
+
+#[cfg(no_values = "bar")]
+//~^ WARNING unexpected `cfg` condition value
+fn no_values() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/diagnotics.stderr b/tests/ui/check-cfg/diagnotics.stderr
new file mode 100644
index 00000000000..8b9fef09d09
--- /dev/null
+++ b/tests/ui/check-cfg/diagnotics.stderr
@@ -0,0 +1,62 @@
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:4:7
+   |
+LL | #[cfg(featur)]
+   |       ^^^^^^ help: there is a config with a similar name: `feature`
+   |
+   = help: expected values for `feature` are: `foo`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:8:7
+   |
+LL | #[cfg(featur = "foo")]
+   |       ^^^^^^^^^^^^^^
+   |
+   = help: expected values for `feature` are: `foo`
+help: there is a config with a similar name and value
+   |
+LL | #[cfg(feature = "foo")]
+   |       ~~~~~~~
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:12:7
+   |
+LL | #[cfg(featur = "fo")]
+   |       ^^^^^^^^^^^^^
+   |
+   = help: expected values for `feature` are: `foo`
+help: there is a config with a similar name and different values
+   |
+LL | #[cfg(feature = "foo")]
+   |       ~~~~~~~~~~~~~~~
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:19:7
+   |
+LL | #[cfg(no_value)]
+   |       ^^^^^^^^ help: there is a config with a similar name: `no_values`
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:23:7
+   |
+LL | #[cfg(no_value = "foo")]
+   |       ^^^^^^^^^^^^^^^^
+   |
+help: there is a config with a similar name and no value
+   |
+LL | #[cfg(no_values)]
+   |       ~~~~~~~~~
+
+warning: unexpected `cfg` condition value
+  --> $DIR/diagnotics.rs:27:7
+   |
+LL | #[cfg(no_values = "bar")]
+   |       ^^^^^^^^^--------
+   |                |
+   |                help: remove the value
+   |
+   = note: no expected value for `no_values`
+
+warning: 6 warnings emitted
+
diff --git a/tests/ui/check-cfg/invalid-cfg-name.stderr b/tests/ui/check-cfg/invalid-cfg-name.stderr
index 2bd1821c942..ed09f8cb66d 100644
--- a/tests/ui/check-cfg/invalid-cfg-name.stderr
+++ b/tests/ui/check-cfg/invalid-cfg-name.stderr
@@ -2,7 +2,7 @@ warning: unexpected `cfg` condition name
   --> $DIR/invalid-cfg-name.rs:7:7
    |
 LL | #[cfg(widnows)]
-   |       ^^^^^^^ help: did you mean: `windows`
+   |       ^^^^^^^ help: there is a config with a similar name: `windows`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
diff --git a/tests/ui/check-cfg/invalid-cfg-value.stderr b/tests/ui/check-cfg/invalid-cfg-value.stderr
index 83383ea61a4..776d264a7ad 100644
--- a/tests/ui/check-cfg/invalid-cfg-value.stderr
+++ b/tests/ui/check-cfg/invalid-cfg-value.stderr
@@ -4,9 +4,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(feature = "sedre")]
    |       ^^^^^^^^^^-------
    |                 |
-   |                 help: did you mean: `"serde"`
+   |                 help: there is a expected value with a similar name: `"serde"`
    |
-   = note: expected values for `feature` are: full, serde
+   = note: expected values for `feature` are: `full`, `serde`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
@@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(feature = "rand")]
    |       ^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: full, serde
+   = note: expected values for `feature` are: `full`, `serde`
 
 warning: unexpected condition value `rand` for condition name `feature`
    |
diff --git a/tests/ui/check-cfg/mix.rs b/tests/ui/check-cfg/mix.rs
index 4e488fc03ec..9adf5c46e43 100644
--- a/tests/ui/check-cfg/mix.rs
+++ b/tests/ui/check-cfg/mix.rs
@@ -12,6 +12,10 @@ fn do_windows_stuff() {}
 //~^ WARNING unexpected `cfg` condition name
 fn do_windows_stuff() {}
 
+#[cfg(feature)]
+//~^ WARNING unexpected `cfg` condition value
+fn no_feature() {}
+
 #[cfg(feature = "foo")]
 fn use_foo() {}
 
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index 9cf887ec788..07c514aed52 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -2,28 +2,36 @@ warning: unexpected `cfg` condition name
   --> $DIR/mix.rs:11:7
    |
 LL | #[cfg(widnows)]
-   |       ^^^^^^^ help: did you mean: `windows`
+   |       ^^^^^^^ help: there is a config with a similar name: `windows`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:18:7
+  --> $DIR/mix.rs:15:7
+   |
+LL | #[cfg(feature)]
+   |       ^^^^^^^- help: specify a config value: `= "foo"`
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value
+  --> $DIR/mix.rs:22:7
    |
 LL | #[cfg(feature = "bar")]
    |       ^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:22:7
+  --> $DIR/mix.rs:26:7
    |
 LL | #[cfg(feature = "zebra")]
    |       ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:26:12
+  --> $DIR/mix.rs:30:12
    |
 LL | #[cfg_attr(uu, test)]
    |            ^^
@@ -37,146 +45,146 @@ warning: unexpected `unknown_name` as condition name
    = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:35:10
+  --> $DIR/mix.rs:39:10
    |
 LL |     cfg!(widnows);
-   |          ^^^^^^^ help: did you mean: `windows`
+   |          ^^^^^^^ help: there is a config with a similar name: `windows`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:38:10
+  --> $DIR/mix.rs:42:10
    |
 LL |     cfg!(feature = "bar");
    |          ^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:40:10
+  --> $DIR/mix.rs:44:10
    |
 LL |     cfg!(feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:42:10
+  --> $DIR/mix.rs:46:10
    |
 LL |     cfg!(xxx = "foo");
    |          ^^^^^^^^^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:44:10
+  --> $DIR/mix.rs:48:10
    |
 LL |     cfg!(xxx);
    |          ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:46:14
+  --> $DIR/mix.rs:50:14
    |
 LL |     cfg!(any(xxx, windows));
    |              ^^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:48:14
+  --> $DIR/mix.rs:52:14
    |
 LL |     cfg!(any(feature = "bad", windows));
    |              ^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:50:23
+  --> $DIR/mix.rs:54:23
    |
 LL |     cfg!(any(windows, xxx));
    |                       ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:52:20
+  --> $DIR/mix.rs:56:20
    |
 LL |     cfg!(all(unix, xxx));
    |                    ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:54:14
+  --> $DIR/mix.rs:58:14
    |
 LL |     cfg!(all(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:54:18
+  --> $DIR/mix.rs:58:18
    |
 LL |     cfg!(all(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:57:14
+  --> $DIR/mix.rs:61:14
    |
 LL |     cfg!(any(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:57:18
+  --> $DIR/mix.rs:61:18
    |
 LL |     cfg!(any(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:60:20
+  --> $DIR/mix.rs:64:20
    |
 LL |     cfg!(any(unix, feature = "zebra"));
    |                    ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:62:14
+  --> $DIR/mix.rs:66:14
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |              ^^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:62:19
+  --> $DIR/mix.rs:66:19
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |                   ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:65:14
+  --> $DIR/mix.rs:69:14
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |              ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:65:25
+  --> $DIR/mix.rs:69:25
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |                         ^^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:68:14
+  --> $DIR/mix.rs:72:14
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |              ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:68:33
+  --> $DIR/mix.rs:72:33
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                 ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:68:52
+  --> $DIR/mix.rs:72:52
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                                    ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
-warning: 27 warnings emitted
+warning: 28 warnings emitted
 
diff --git a/tests/ui/check-cfg/no-values.stderr b/tests/ui/check-cfg/no-values.stderr
index 8c926d187fe..ffa87dc58f2 100644
--- a/tests/ui/check-cfg/no-values.stderr
+++ b/tests/ui/check-cfg/no-values.stderr
@@ -2,7 +2,9 @@ warning: unexpected `cfg` condition value
   --> $DIR/no-values.rs:6:7
    |
 LL | #[cfg(feature = "foo")]
-   |       ^^^^^^^^^^^^^^^
+   |       ^^^^^^^--------
+   |              |
+   |              help: remove the value
    |
    = note: no expected value for `feature`
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/values-target-json.stderr b/tests/ui/check-cfg/values-target-json.stderr
index b58d2970773..eb81535e3ed 100644
--- a/tests/ui/check-cfg/values-target-json.stderr
+++ b/tests/ui/check-cfg/values-target-json.stderr
@@ -4,9 +4,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target_os = "linuz")]
    |       ^^^^^^^^^^^^-------
    |                   |
-   |                   help: did you mean: `"linux"`
+   |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, ericos, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vita, vxworks, wasi, watchos, windows, xous
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `ericos`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr
index bdbe4d29d30..34c5d6172d9 100644
--- a/tests/ui/check-cfg/well-known-names.stderr
+++ b/tests/ui/check-cfg/well-known-names.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name
 LL | #[cfg(target_oz = "linux")]
    |       ---------^^^^^^^^^^
    |       |
-   |       help: did you mean: `target_os`
+   |       help: there is a config with a similar name: `target_os`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
@@ -14,13 +14,13 @@ warning: unexpected `cfg` condition name
 LL | #[cfg(features = "foo")]
    |       --------^^^^^^^^
    |       |
-   |       help: did you mean: `feature`
+   |       help: there is a config with a similar name: `feature`
 
 warning: unexpected `cfg` condition name
   --> $DIR/well-known-names.rs:20:7
    |
 LL | #[cfg(uniw)]
-   |       ^^^^ help: did you mean: `unix`
+   |       ^^^^ help: there is a config with a similar name: `unix`
 
 warning: 3 warnings emitted
 
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 69d799783a9..2d18cb82e03 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -4,9 +4,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target_os = "linuz")]
    |       ^^^^^^^^^^^^-------
    |                   |
-   |                   help: did you mean: `"linux"`
+   |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vita, vxworks, wasi, watchos, windows, xous
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
@@ -15,9 +15,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target_has_atomic = "0")]
    |       ^^^^^^^^^^^^^^^^^^^^---
    |                           |
-   |                           help: did you mean: `"8"`
+   |                           help: there is a expected value with a similar name: `"8"`
    |
-   = note: expected values for `target_has_atomic` are: 128, 16, 32, 64, 8, ptr
+   = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
 
 warning: unexpected `cfg` condition value
   --> $DIR/well-known-values.rs:21:7
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs b/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs
deleted file mode 100644
index fc47a9061d3..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// only-x86
-#[link(name = "foo")]
-extern "C" {
-    #[link_ordinal(42)]
-    //~^ ERROR: `#[link_ordinal]` is unstable on x86
-    fn foo();
-    #[link_ordinal(5)]
-    //~^ ERROR: `#[link_ordinal]` is unstable on x86
-    static mut imported_variable: i32;
-}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr
deleted file mode 100644
index 0e900760d24..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: `#[link_ordinal]` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib-2.rs:4:5
-   |
-LL |     #[link_ordinal(42)]
-   |     ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error[E0658]: `#[link_ordinal]` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib-2.rs:7:5
-   |
-LL |     #[link_ordinal(5)]
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs b/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs
deleted file mode 100644
index 295f502d6a3..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// only-windows
-// only-x86
-#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
-//~^ ERROR link kind `raw-dylib` is unstable on x86
-//~| ERROR import name type is unstable
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr
deleted file mode 100644
index d6b165b7610..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: link kind `raw-dylib` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:29
-   |
-LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
-   |                             ^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error[E0658]: import name type is unstable
-  --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:61
-   |
-LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
-   |                                                             ^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib.rs b/tests/ui/feature-gates/feature-gate-raw-dylib.rs
deleted file mode 100644
index 291cca8fd25..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// only-windows
-// only-x86
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: link kind `raw-dylib` is unstable on x86
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib.stderr
deleted file mode 100644
index f02241e4908..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: link kind `raw-dylib` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib.rs:3:29
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   |                             ^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs
new file mode 100644
index 00000000000..d7a418959bf
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs
@@ -0,0 +1,19 @@
+// Tests that dlltool failing to generate an import library will raise an error.
+
+// only-gnu
+// only-windows
+// needs-dlltool
+// compile-flags: --crate-type lib --emit link
+// normalize-stderr-test: "[^ ']*/dlltool.exe" -> "$$DLLTOOL"
+// normalize-stderr-test: "[^ ]*/foo.def" -> "$$DEF_FILE"
+#[link(name = "foo", kind = "raw-dylib")]
+extern "C" {
+    // `@1` is an invalid name to export, as it usually indicates that something
+    // is being exported via ordinal.
+    #[link_name = "@1"]
+    fn f(x: i32);
+}
+
+pub fn lib_main() {
+    unsafe { f(42); }
+}
diff --git a/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr
new file mode 100644
index 00000000000..020ac6a2b67
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr
@@ -0,0 +1,5 @@
+error: Dlltool could not create import library: 
+       $DLLTOOL: Syntax error in def file $DEF_FILE:1
+
+error: aborting due to previous error
+
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
index 22d57f8bedd..7bc44d65be9 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
@@ -1,7 +1,5 @@
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
 //~^ ERROR import name type must be of the form `import_name_type = "string"`
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
index 0e95fec29d2..fb70b987fc7 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
@@ -1,5 +1,5 @@
 error: import name type must be of the form `import_name_type = "string"`
-  --> $DIR/import-name-type-invalid-format.rs:5:42
+  --> $DIR/import-name-type-invalid-format.rs:3:42
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
    |                                          ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
index 7ccb0082fb9..b96f61a26da 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
@@ -1,8 +1,6 @@
 // ignore-tidy-linelength
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
 //~^ ERROR multiple `import_name_type` arguments in a single `#[link]` attribute
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
index 7c0e0be911f..9533061892f 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
@@ -1,5 +1,5 @@
 error: multiple `import_name_type` arguments in a single `#[link]` attribute
-  --> $DIR/import-name-type-multiple.rs:6:74
+  --> $DIR/import-name-type-multiple.rs:4:74
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
    |                                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
index f728a578d3b..067e82a17fd 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
@@ -1,7 +1,5 @@
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
 //~^ ERROR unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
index 2b299f2fea3..2bce9758e99 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
@@ -1,5 +1,5 @@
 error: unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
-  --> $DIR/import-name-type-unknown-value.rs:5:42
+  --> $DIR/import-name-type-unknown-value.rs:3:42
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
index ae9207864a2..34e907bde83 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
@@ -1,7 +1,5 @@
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", import_name_type = "decorated")]
 //~^ ERROR import name type can only be used with link kind `raw-dylib`
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
index 5898cd875a1..75cadc471c4 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
@@ -1,11 +1,11 @@
 error: import name type can only be used with link kind `raw-dylib`
-  --> $DIR/import-name-type-unsupported-link-kind.rs:5:22
+  --> $DIR/import-name-type-unsupported-link-kind.rs:3:22
    |
 LL | #[link(name = "foo", import_name_type = "decorated")]
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: import name type can only be used with link kind `raw-dylib`
-  --> $DIR/import-name-type-unsupported-link-kind.rs:9:39
+  --> $DIR/import-name-type-unsupported-link-kind.rs:7:39
    |
 LL | #[link(name = "bar", kind = "static", import_name_type = "decorated")]
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs
new file mode 100644
index 00000000000..a07be9d92b4
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs
@@ -0,0 +1,13 @@
+// Tests that failing to run dlltool will raise an error.
+
+// only-gnu
+// only-windows
+// compile-flags: --crate-type lib --emit link -Cdlltool=does_not_exit.exe
+#[link(name = "foo", kind = "raw-dylib")]
+extern "C" {
+    fn f(x: i32);
+}
+
+pub fn lib_main() {
+    unsafe { f(42); }
+}
diff --git a/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr
new file mode 100644
index 00000000000..3ae901e0dbc
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr
@@ -0,0 +1,4 @@
+error: Error calling dlltool 'does_not_exit.exe': program not found
+
+error: aborting due to previous error
+
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
index 1a128c87a0c..b04c2facbcd 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name="foo")]
 extern "C" {
     #[link_name="foo"]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
index 481a06d2797..f1e54d37827 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
@@ -1,11 +1,11 @@
 error: cannot use `#[link_name]` with `#[link_ordinal]`
-  --> $DIR/link-ordinal-and-name.rs:6:5
+  --> $DIR/link-ordinal-and-name.rs:4:5
    |
 LL |     #[link_ordinal(42)]
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: cannot use `#[link_name]` with `#[link_ordinal]`
-  --> $DIR/link-ordinal-and-name.rs:10:5
+  --> $DIR/link-ordinal-and-name.rs:8:5
    |
 LL |     #[link_ordinal(5)]
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
index 7c8da050cf6..9b7e8d70743 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal("JustMonika")]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
index 55cdcad75a4..6341e57a0be 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
@@ -1,5 +1,5 @@
 error: illegal ordinal format in `link_ordinal`
-  --> $DIR/link-ordinal-invalid-format.rs:5:5
+  --> $DIR/link-ordinal-invalid-format.rs:3:5
    |
 LL |     #[link_ordinal("JustMonika")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal("JustMonika")]
    = note: an unsuffixed integer value, e.g., `1`, is expected
 
 error: illegal ordinal format in `link_ordinal`
-  --> $DIR/link-ordinal-invalid-format.rs:8:5
+  --> $DIR/link-ordinal-invalid-format.rs:6:5
    |
 LL |     #[link_ordinal("JustMonika")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
index 9feed394110..6b8cd49566d 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal()]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
index 853cdad8c1c..1b04bb228e7 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
@@ -1,5 +1,5 @@
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-missing-argument.rs:5:5
+  --> $DIR/link-ordinal-missing-argument.rs:3:5
    |
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal()]
    = note: the attribute requires exactly one argument
 
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-missing-argument.rs:8:5
+  --> $DIR/link-ordinal-missing-argument.rs:6:5
    |
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
index 631c363d4ba..8842cb94404 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
@@ -1,6 +1,4 @@
 // only-windows
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo", kind = "raw-dylib")]
 extern "C" {
     #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
index c0453d2bf01..2e6cf3761c2 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
@@ -1,23 +1,23 @@
 error: multiple `link_ordinal` attributes
-  --> $DIR/link-ordinal-multiple.rs:6:5
+  --> $DIR/link-ordinal-multiple.rs:4:5
    |
 LL |     #[link_ordinal(1)]
    |     ^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/link-ordinal-multiple.rs:7:5
+  --> $DIR/link-ordinal-multiple.rs:5:5
    |
 LL |     #[link_ordinal(2)]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: multiple `link_ordinal` attributes
-  --> $DIR/link-ordinal-multiple.rs:9:5
+  --> $DIR/link-ordinal-multiple.rs:7:5
    |
 LL |     #[link_ordinal(1)]
    |     ^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/link-ordinal-multiple.rs:10:5
+  --> $DIR/link-ordinal-multiple.rs:8:5
    |
 LL |     #[link_ordinal(2)]
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
index 54e614164b3..f33a3d62e26 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link_ordinal(123)]
 //~^ ERROR attribute should be applied to a foreign function or static
 struct Foo {}
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
index ec4104fbe50..8f279508720 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
@@ -1,17 +1,17 @@
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:3:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:1:1
    |
 LL | #[link_ordinal(123)]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:7:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:5:1
    |
 LL | #[link_ordinal(123)]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:11:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:9:1
    |
 LL | #[link_ordinal(42)]
    | ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
index 46731581ebc..9d741630fc9 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal(72436)]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
index fef6de6aedf..811145e77ee 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
@@ -1,5 +1,5 @@
 error: ordinal value in `link_ordinal` is too large: `72436`
-  --> $DIR/link-ordinal-too-large.rs:5:5
+  --> $DIR/link-ordinal-too-large.rs:3:5
    |
 LL |     #[link_ordinal(72436)]
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal(72436)]
    = note: the value may not exceed `u16::MAX`
 
 error: ordinal value in `link_ordinal` is too large: `72436`
-  --> $DIR/link-ordinal-too-large.rs:8:5
+  --> $DIR/link-ordinal-too-large.rs:6:5
    |
 LL |     #[link_ordinal(72436)]
    |     ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
index 71e0ac9f3ee..9988115fd8b 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal(3, 4)]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
index 7e0fcd845cb..d5ce8aff34f 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
@@ -1,5 +1,5 @@
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-too-many-arguments.rs:5:5
+  --> $DIR/link-ordinal-too-many-arguments.rs:3:5
    |
 LL |     #[link_ordinal(3, 4)]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal(3, 4)]
    = note: the attribute requires exactly one argument
 
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-too-many-arguments.rs:8:5
+  --> $DIR/link-ordinal-too-many-arguments.rs:6:5
    |
 LL |     #[link_ordinal(3, 4)]
    |     ^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
index 329c93fc196..14e915d602a 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal(3)]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
index 5fbffbda570..200b8f62874 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
@@ -1,11 +1,11 @@
 error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
-  --> $DIR/link-ordinal-unsupported-link-kind.rs:5:5
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:3:5
    |
 LL |     #[link_ordinal(3)]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
-  --> $DIR/link-ordinal-unsupported-link-kind.rs:12:5
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:10:5
    |
 LL |     #[link_ordinal(3)]
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs
index 6542faad264..b4173f3b60b 100644
--- a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs
+++ b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs
@@ -2,7 +2,6 @@
 // only-windows
 // compile-flags: --crate-type lib --emit link
 #![allow(clashing_extern_declarations)]
-#![feature(raw_dylib)]
 #[link(name = "foo", kind = "raw-dylib")]
 extern "C" {
     fn f(x: i32);
diff --git a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
index c6808bec7b5..51010840548 100644
--- a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
@@ -1,5 +1,5 @@
 error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions
-  --> $DIR/multiple-declarations.rs:14:9
+  --> $DIR/multiple-declarations.rs:13:9
    |
 LL |         fn f(x: i32);
    |         ^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
index 4efffbd532e..d4c6658a330 100644
--- a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
+++ b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
@@ -1,6 +1,5 @@
 // ignore-windows
 // compile-flags: --crate-type lib
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 #[link(name = "foo", kind = "raw-dylib")]
 //~^ ERROR: link kind `raw-dylib` is only supported on Windows targets
 extern "C" {}
diff --git a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
index 14e791f1fb9..b635a09afba 100644
--- a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
@@ -1,5 +1,5 @@
 error[E0455]: link kind `raw-dylib` is only supported on Windows targets
-  --> $DIR/raw-dylib-windows-only.rs:4:29
+  --> $DIR/raw-dylib-windows-only.rs:3:29
    |
 LL | #[link(name = "foo", kind = "raw-dylib")]
    |                             ^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs
new file mode 100644
index 00000000000..e4b07ab8108
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs
@@ -0,0 +1,7 @@
+// run-pass
+
+#![feature(c_str_literals)]
+
+fn main() {
+    assert_eq!(b"test\0", c"test".to_bytes_with_nul());
+}
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs
new file mode 100644
index 00000000000..b27da26ed23
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs
@@ -0,0 +1,13 @@
+// gate-test-c_str_literals
+
+macro_rules! m {
+    ($t:tt) => {}
+}
+
+fn main() {
+    c"foo";
+    //~^ ERROR: `c".."` literals are experimental
+
+    m!(c"test");
+    //~^ ERROR: `c".."` literals are experimental
+}
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr
new file mode 100644
index 00000000000..bc0c537aada
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr
@@ -0,0 +1,21 @@
+error[E0658]: `c".."` literals are experimental
+  --> $DIR/gate.rs:8:5
+   |
+LL |     c"foo";
+   |     ^^^^^^
+   |
+   = note: see issue #105723 <https://github.com/rust-lang/rust/issues/105723> for more information
+   = help: add `#![feature(c_str_literals)]` to the crate attributes to enable
+
+error[E0658]: `c".."` literals are experimental
+  --> $DIR/gate.rs:11:8
+   |
+LL |     m!(c"test");
+   |        ^^^^^^^
+   |
+   = note: see issue #105723 <https://github.com/rust-lang/rust/issues/105723> for more information
+   = help: add `#![feature(c_str_literals)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs
new file mode 100644
index 00000000000..7bc6097f124
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs
Binary files differdiff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr
new file mode 100644
index 00000000000..ff9006f6f97
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr
Binary files differdiff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs
new file mode 100644
index 00000000000..82e8e2090d7
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs
@@ -0,0 +1,10 @@
+// run-pass
+
+#![feature(c_str_literals)]
+
+fn main() {
+    assert_eq!(
+        c"\xEF\x80🦀\u{1F980}".to_bytes_with_nul(),
+        &[0xEF, 0x80, 0xF0, 0x9F, 0xA6, 0x80, 0xF0, 0x9F, 0xA6, 0x80, 0x00],
+    );
+}
diff --git a/tests/ui/specialization/issue-111232.rs b/tests/ui/specialization/issue-111232.rs
new file mode 100644
index 00000000000..3ed3c580e6d
--- /dev/null
+++ b/tests/ui/specialization/issue-111232.rs
@@ -0,0 +1,11 @@
+#![feature(min_specialization)]
+
+struct S;
+
+impl From<S> for S {
+    fn from(s: S) -> S { //~ ERROR `from` specializes an item from a parent `impl`, but that item is not marked `default`
+        s
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/specialization/issue-111232.stderr b/tests/ui/specialization/issue-111232.stderr
new file mode 100644
index 00000000000..27ee42fc00c
--- /dev/null
+++ b/tests/ui/specialization/issue-111232.stderr
@@ -0,0 +1,11 @@
+error[E0520]: `from` specializes an item from a parent `impl`, but that item is not marked `default`
+  --> $DIR/issue-111232.rs:6:5
+   |
+LL |     fn from(s: S) -> S {
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: parent implementation is in crate `core`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0520`.