Rollup merge of #138374 - celinval:issue-136925-const-contract, r=compiler-errors,oli-obk,RalfJung

Enable contracts for const functions

Use `const_eval_select!()` macro to enable contract checking only at runtime. The existing contract logic relies on closures, which are not supported in constant functions.

This commit also removes one level of indirection for ensures clauses since we no longer build a closure around the ensures predicate.

Resolves #136925

**Call-out:** This is still a draft PR since CI is broken due to a new warning message for unreachable code when the bottom of the function is indeed unreachable. It's not clear to me why the warning wasn't triggered before.

r? ```@compiler-errors```
diff --git a/Cargo.lock b/Cargo.lock
index 1e1d68f..745a809 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1270,6 +1270,7 @@
  "edition",
  "expect-test",
  "ra-ap-rustc_lexer",
+ "rustc-literal-escaper",
  "stdx",
  "tracing",
 ]
@@ -1744,6 +1745,12 @@
 checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
 
 [[package]]
+name = "rustc-literal-escaper"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04"
+
+[[package]]
 name = "rustc-stable-hash"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1978,10 +1985,10 @@
  "indexmap",
  "itertools",
  "parser",
- "ra-ap-rustc_lexer",
  "rayon",
  "rowan",
  "rustc-hash 2.0.0",
+ "rustc-literal-escaper",
  "rustc_apfloat",
  "smol_str",
  "stdx",
diff --git a/Cargo.toml b/Cargo.toml
index ce2d660..e221913 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -136,6 +136,7 @@
 pulldown-cmark = { version = "0.9.0", default-features = false }
 rayon = "1.8.0"
 rustc-hash = "2.0.0"
+rustc-literal-escaper = "0.0.2"
 semver = "1.0.14"
 serde = { version = "1.0.192" }
 serde_derive = { version = "1.0.192" }
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 6b470d9..80a2d46 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -6882,109 +6882,14 @@
 
 #[test]
 fn hover_feature() {
-    check(
-        r#"#![feature(intrinsics$0)]"#,
-        expect![[r#"
-            *intrinsics*
-            ```
-            intrinsics
-            ```
-            ___
-
-            # `intrinsics`
-
-            The tracking issue for this feature is: None.
-
-            Intrinsics are rarely intended to be stable directly, but are usually
-            exported in some sort of stable manner. Prefer using the stable interfaces to
-            the intrinsic directly when you can.
-
-            ------------------------
-
-
-            ## Intrinsics with fallback logic
-
-            Many intrinsics can be written in pure rust, albeit inefficiently or without supporting
-            some features that only exist on some backends. Backends can simply not implement those
-            intrinsics without causing any code miscompilations or failures to compile.
-            All intrinsic fallback bodies are automatically made cross-crate inlineable (like `#[inline]`)
-            by the codegen backend, but not the MIR inliner.
-
-            ```rust
-            #![feature(intrinsics)]
-            #![allow(internal_features)]
-
-            #[rustc_intrinsic]
-            const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
-            ```
-
-            Since these are just regular functions, it is perfectly ok to create the intrinsic twice:
-
-            ```rust
-            #![feature(intrinsics)]
-            #![allow(internal_features)]
-
-            #[rustc_intrinsic]
-            const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
-
-            mod foo {
-                #[rustc_intrinsic]
-                const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {
-                    panic!("noisy const dealloc")
-                }
-            }
-
-            ```
-
-            The behaviour on backends that override the intrinsic is exactly the same. On other
-            backends, the intrinsic behaviour depends on which implementation is called, just like
-            with any regular function.
-
-            ## Intrinsics lowered to MIR instructions
-
-            Various intrinsics have native MIR operations that they correspond to. Instead of requiring
-            backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
-            will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
-            at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic"
-            or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist
-            anymore after MIR analyses.
-
-            ## Intrinsics without fallback logic
-
-            These must be implemented by all backends.
-
-            ### `#[rustc_intrinsic]` declarations
-
-            These are written like intrinsics with fallback bodies, but the body is irrelevant.
-            Use `loop {}` for the body or call the intrinsic recursively and add
-            `#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't
-            invoke the body.
-
-            ### Legacy extern ABI based intrinsics
-
-            These are imported as if they were FFI functions, with the special
-            `rust-intrinsic` ABI. For example, if one was in a freestanding
-            context, but wished to be able to `transmute` between types, and
-            perform efficient pointer arithmetic, one would import those functions
-            via a declaration like
-
-            ```rust
-            #![feature(intrinsics)]
-            #![allow(internal_features)]
-            # fn main() {}
-
-            extern "rust-intrinsic" {
-                fn transmute<T, U>(x: T) -> U;
-
-                fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
-            }
-            ```
-
-            As with any other FFI functions, these are by default always `unsafe` to call.
-            You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call.
-
-        "#]],
-    )
+    let (analysis, position) = fixture::position(r#"#![feature(intrinsics$0)]"#);
+    analysis
+        .hover(
+            &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG },
+            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
+        )
+        .unwrap()
+        .unwrap();
 }
 
 #[test]
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index a36a39d..114a66a 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -14,6 +14,7 @@
 [dependencies]
 drop_bomb = "0.1.5"
 ra-ap-rustc_lexer.workspace = true
+rustc-literal-escaper.workspace = true
 tracing = { workspace = true, optional = true }
 
 edition.workspace = true
diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs
index c97596d..b0bbc2f 100644
--- a/crates/parser/src/lexed_str.rs
+++ b/crates/parser/src/lexed_str.rs
@@ -10,7 +10,7 @@
 
 use std::ops;
 
-use rustc_lexer::unescape::{EscapeError, Mode};
+use rustc_literal_escaper::{EscapeError, Mode, unescape_byte, unescape_char, unescape_mixed, unescape_unicode};
 
 use crate::{
     Edition,
@@ -282,7 +282,7 @@
                     let text = &self.res.text[self.offset + 1..][..len - 1];
                     let i = text.rfind('\'').unwrap();
                     let text = &text[..i];
-                    if let Err(e) = rustc_lexer::unescape::unescape_char(text) {
+                    if let Err(e) = unescape_char(text) {
                         err = error_to_diagnostic_message(e, Mode::Char);
                     }
                 }
@@ -295,7 +295,7 @@
                     let text = &self.res.text[self.offset + 2..][..len - 2];
                     let i = text.rfind('\'').unwrap();
                     let text = &text[..i];
-                    if let Err(e) = rustc_lexer::unescape::unescape_byte(text) {
+                    if let Err(e) = unescape_byte(text) {
                         err = error_to_diagnostic_message(e, Mode::Byte);
                     }
                 }
@@ -402,14 +402,14 @@
     let mut error_message = "";
     match mode {
         Mode::CStr => {
-            rustc_lexer::unescape::unescape_mixed(text, mode, &mut |_, res| {
+            unescape_mixed(text, mode, &mut |_, res| {
                 if let Err(e) = res {
                     error_message = error_to_diagnostic_message(e, mode);
                 }
             });
         }
         Mode::ByteStr | Mode::Str => {
-            rustc_lexer::unescape::unescape_unicode(text, mode, &mut |_, res| {
+            unescape_unicode(text, mode, &mut |_, res| {
                 if let Err(e) = res {
                     error_message = error_to_diagnostic_message(e, mode);
                 }
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 3fe6e01..6b35639 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -17,13 +17,12 @@
 itertools.workspace = true
 rowan = "=0.15.15"
 rustc-hash.workspace = true
+rustc-literal-escaper.workspace = true
 indexmap.workspace = true
 smol_str.workspace = true
 triomphe.workspace = true
 tracing.workspace = true
 
-ra-ap-rustc_lexer.workspace = true
-
 parser.workspace = true
 stdx.workspace = true
 
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index df851ab..08bffb9 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -2,7 +2,7 @@
 
 use std::{borrow::Cow, num::ParseIntError};
 
-use rustc_lexer::unescape::{
+use rustc_literal_escaper::{
     unescape_byte, unescape_char, unescape_mixed, unescape_unicode, EscapeError, MixedUnit, Mode,
 };
 use stdx::always;
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index c9e9f46..21f1ea5 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -19,13 +19,6 @@
 //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256>
 //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md>
 
-#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
-
-#[cfg(not(feature = "in-rust-tree"))]
-extern crate ra_ap_rustc_lexer as rustc_lexer;
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_lexer;
-
 mod parsing;
 mod ptr;
 mod syntax_error;
@@ -64,7 +57,7 @@
     api::Preorder, Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize,
     TokenAtOffset, WalkEvent,
 };
-pub use rustc_lexer::unescape;
+pub use rustc_literal_escaper as unescape;
 pub use smol_str::{format_smolstr, SmolStr, SmolStrBuilder, ToSmolStr};
 
 /// `Parse` is the result of the parsing: a syntax tree and a collection of
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 85eefac..71c5f9a 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -5,7 +5,7 @@
 mod block;
 
 use rowan::Direction;
-use rustc_lexer::unescape::{self, unescape_mixed, unescape_unicode, Mode};
+use rustc_literal_escaper::{unescape_mixed, unescape_unicode, EscapeError, Mode};
 
 use crate::{
     algo,
@@ -44,8 +44,8 @@
     }
 }
 
-fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> (&'static str, bool) {
-    use unescape::EscapeError as EE;
+fn rustc_unescape_error_to_string(err: EscapeError) -> (&'static str, bool) {
+    use rustc_literal_escaper::EscapeError as EE;
 
     #[rustfmt::skip]
     let err_message = match err {
@@ -127,7 +127,7 @@
     let text = token.text();
 
     // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-lang/rust-analyzer/pull/2834#discussion_r366199205)
-    let mut push_err = |prefix_len, off, err: unescape::EscapeError| {
+    let mut push_err = |prefix_len, off, err: EscapeError| {
         let off = token.text_range().start() + TextSize::try_from(off + prefix_len).unwrap();
         let (message, is_err) = rustc_unescape_error_to_string(err);
         // FIXME: Emit lexer warnings