New upstream version 1.72.1+dfsg1

This commit is contained in:
Fabian Grünbichler 2024-05-23 21:15:29 +02:00
parent 49aad94119
commit fe692bf9c3
13550 changed files with 1091683 additions and 550030 deletions

1582
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
[workspace]
resolver = "1"
members = [
"compiler/rustc",
"library/std",
@ -8,6 +9,7 @@ members = [
"src/tools/cargotest",
"src/tools/clippy",
"src/tools/clippy/clippy_dev",
"src/tools/clippy/clippy_test_deps",
"src/tools/compiletest",
"src/tools/error_index_generator",
"src/tools/linkchecker",

View File

@ -22,8 +22,9 @@ Read ["Installation"] from [The Book].
The Rust build system uses a Python script called `x.py` to build the compiler,
which manages the bootstrapping process. It lives at the root of the project.
It also uses a file named `config.toml` to determine various configuration settings for the build.
You can see a full list of options in `config.example.toml`.
It also uses a file named `config.toml` to determine various configuration
settings for the build. You can see a full list of options in
`config.example.toml`.
The `x.py` command can be run directly on most Unix systems in the following
format:
@ -33,24 +34,14 @@ format:
```
This is how the documentation and examples assume you are running `x.py`.
Some alternative ways are:
```sh
# On a Unix shell if you don't have the necessary `python3` command
./x <subcommand> [flags]
# On the Windows Command Prompt (if .py files are configured to run Python)
x.py <subcommand> [flags]
# You can also run Python yourself, e.g.:
python x.py <subcommand> [flags]
```
See the [rustc dev guide][rustcguidebuild] if this does not work on your
platform.
More information about `x.py` can be found by running it with the `--help` flag
or reading the [rustc dev guide][rustcguidebuild].
[gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html
[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html
[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#what-is-xpy
### Dependencies
@ -116,24 +107,26 @@ See [the rustc-dev-guide for more info][sysllvm].
When complete, `./x.py install` will place several programs into
`$PREFIX/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
API-documentation tool. By default, it will also include [Cargo], Rust's package manager.
You can disable this behavior by passing `--set build.extended=false` to `./configure`.
API-documentation tool. By default, it will also include [Cargo], Rust's
package manager. You can disable this behavior by passing
`--set build.extended=false` to `./configure`.
[Cargo]: https://github.com/rust-lang/cargo
#### Configure and Make
This project provides a configure script and makefile (the latter of which just invokes `x.py`).
`./configure` is the recommended way to programatically generate a `config.toml`. `make` is not
recommended (we suggest using `x.py` directly), but it is supported and we try not to break it
unnecessarily.
This project provides a configure script and makefile (the latter of which just
invokes `x.py`). `./configure` is the recommended way to programatically
generate a `config.toml`. `make` is not recommended (we suggest using `x.py`
directly), but it is supported and we try not to break it unnecessarily.
```sh
./configure
make && sudo make install
```
`configure` generates a `config.toml` which can also be used with normal `x.py` invocations.
`configure` generates a `config.toml` which can also be used with normal `x.py`
invocations.
### Building on Windows
@ -204,7 +197,7 @@ toolchain.
#### MSVC
MSVC builds of Rust additionally require an installation of Visual Studio 2017
(or later) so `rustc` can use its linker. The simplest way is to get
(or later) so `rustc` can use its linker. The simplest way is to get
[Visual Studio], check the "C++ build tools" and "Windows 10 SDK" workload.
[Visual Studio]: https://visualstudio.microsoft.com/downloads/
@ -245,7 +238,8 @@ Windows build triples are:
The build triple can be specified by either specifying `--build=<triple>` when
invoking `x.py` commands, or by creating a `config.toml` file (as described in
[Building on a Unix-like system](#building-on-a-unix-like-system)), and passing `--set build.build=<triple>` to `./configure`.
[Building on a Unix-like system](#building-on-a-unix-like-system)), and passing
`--set build.build=<triple>` to `./configure`.
## Building Documentation

View File

@ -1,3 +1,118 @@
Version 1.72.1 (2023-09-14)
===========================
- [Adjust codegen change to improve LLVM codegen](https://github.com/rust-lang/rust/pull/115236)
- [rustdoc: Fix self ty params in objects with lifetimes](https://github.com/rust-lang/rust/pull/115276)
- [Fix regression in compile times](https://github.com/rust-lang/rust/pull/114948)
- Resolve some ICE regressions in the compiler:
- [#115215](https://github.com/rust-lang/rust/pull/115215)
- [#115559](https://github.com/rust-lang/rust/pull/115559)
Version 1.72.0 (2023-08-24)
==========================
<a id="1.72.0-Language"></a>
Language
--------
- [Replace const eval limit by a lint and add an exponential backoff warning](https://github.com/rust-lang/rust/pull/103877/)
- [expand: Change how `#![cfg(FALSE)]` behaves on crate root](https://github.com/rust-lang/rust/pull/110141/)
- [Stabilize inline asm for LoongArch64](https://github.com/rust-lang/rust/pull/111235/)
- [Uplift `clippy::undropped_manually_drops` lint](https://github.com/rust-lang/rust/pull/111530/)
- [Uplift `clippy::invalid_utf8_in_unchecked` lint](https://github.com/rust-lang/rust/pull/111543/)
- [Uplift `clippy::cast_ref_to_mut` lint](https://github.com/rust-lang/rust/pull/111567/)
- [Uplift `clippy::cmp_nan` lint](https://github.com/rust-lang/rust/pull/111818/)
- [resolve: Remove artificial import ambiguity errors](https://github.com/rust-lang/rust/pull/112086/)
- [Don't require associated types with Self: Sized bounds in `dyn Trait` objects](https://github.com/rust-lang/rust/pull/112319/)
<a id="1.72.0-Compiler"></a>
Compiler
--------
- [Remember names of `cfg`-ed out items to mention them in diagnostics](https://github.com/rust-lang/rust/pull/109005/)
- [Support for native WASM exceptions](https://github.com/rust-lang/rust/pull/111322/)
- [Add support for NetBSD/aarch64-be (big-endian arm64).](https://github.com/rust-lang/rust/pull/111326/)
- [Write to stdout if `-` is given as output file](https://github.com/rust-lang/rust/pull/111626/)
- [Force all native libraries to be statically linked when linking a static binary](https://github.com/rust-lang/rust/pull/111698/)
- [Add Tier 3 support for `loongarch64-unknown-none*`](https://github.com/rust-lang/rust/pull/112310/)
- [Prevent `.eh_frame` from being emitted for `-C panic=abort`](https://github.com/rust-lang/rust/pull/112403/)
- [Support 128-bit enum variant in debuginfo codegen](https://github.com/rust-lang/rust/pull/112474/)
- [compiler: update solaris/illumos to enable tsan support.](https://github.com/rust-lang/rust/pull/112039/)
Refer to Rust's [platform support page][platform-support-doc]
for more information on Rust's tiered platform support.
<a id="1.72.0-Libraries"></a>
Libraries
---------
- [Document memory orderings of `thread::{park, unpark}`](https://github.com/rust-lang/rust/pull/99587/)
- [io: soften at most one write attempt requirement in io::Write::write](https://github.com/rust-lang/rust/pull/107200/)
- [Specify behavior of HashSet::insert](https://github.com/rust-lang/rust/pull/107619/)
- [Relax implicit `T: Sized` bounds on `BufReader<T>`, `BufWriter<T>` and `LineWriter<T>`](https://github.com/rust-lang/rust/pull/111074/)
- [Update runtime guarantee for `select_nth_unstable`](https://github.com/rust-lang/rust/pull/111974/)
- [Return `Ok` on kill if process has already exited](https://github.com/rust-lang/rust/pull/112594/)
- [Implement PartialOrd for `Vec`s over different allocators](https://github.com/rust-lang/rust/pull/112632/)
- [Use 128 bits for TypeId hash](https://github.com/rust-lang/rust/pull/109953/)
- [Don't drain-on-drop in DrainFilter impls of various collections.](https://github.com/rust-lang/rust/pull/104455/)
- [Make `{Arc,Rc,Weak}::ptr_eq` ignore pointer metadata](https://github.com/rust-lang/rust/pull/106450/)
<a id="1.72.0-Rustdoc"></a>
Rustdoc
-------
- [Allow whitespace as path separator like double colon](https://github.com/rust-lang/rust/pull/108537/)
- [Add search result item types after their name](https://github.com/rust-lang/rust/pull/110688/)
- [Search for slices and arrays by type with `[]`](https://github.com/rust-lang/rust/pull/111958/)
- [Clean up type unification and "unboxing"](https://github.com/rust-lang/rust/pull/112233/)
<a id="1.72.0-Stabilized-APIs"></a>
Stabilized APIs
---------------
- [`impl<T: Send> Sync for mpsc::Sender<T>`](https://doc.rust-lang.org/nightly/std/sync/mpsc/struct.Sender.html#impl-Sync-for-Sender%3CT%3E)
- [`impl TryFrom<&OsStr> for &str`](https://doc.rust-lang.org/nightly/std/primitive.str.html#impl-TryFrom%3C%26'a+OsStr%3E-for-%26'a+str)
- [`String::leak`](https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.leak)
These APIs are now stable in const contexts:
- [`CStr::from_bytes_with_nul`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
- [`CStr::to_bytes`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
- [`CStr::to_bytes_with_nul`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
- [`CStr::to_str`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
<a id="1.72.0-Cargo"></a>
Cargo
-----
- Enable `-Zdoctest-in-workspace` by default. When running each documentation
test, the working directory is set to the root directory of the package the
test belongs to.
[docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-test.html#working-directory-of-tests)
[#12221](https://github.com/rust-lang/cargo/pull/12221)
[#12288](https://github.com/rust-lang/cargo/pull/12288)
- Add support of the "default" keyword to reset previously set `build.jobs`
parallelism back to the default.
[#12222](https://github.com/rust-lang/cargo/pull/12222)
<a id="1.72.0-Compatibility-Notes"></a>
Compatibility Notes
-------------------
- [Alter `Display` for `Ipv6Addr` for IPv4-compatible addresses](https://github.com/rust-lang/rust/pull/112606/)
- Cargo changed feature name validation check to a hard error. The warning was
added in Rust 1.49. These extended characters aren't allowed on crates.io, so
this should only impact users of other registries, or people who don't publish
to a registry.
[#12291](https://github.com/rust-lang/cargo/pull/12291)
Version 1.71.1 (2023-08-03)
===========================
@ -102,7 +217,6 @@ Cargo
-----
- [Allow named debuginfo options in `Cargo.toml`.](https://github.com/rust-lang/cargo/pull/11958/)
- [Add `workspace_default_members` to the output of `cargo metadata`.](https://github.com/rust-lang/cargo/pull/11978/)
- [`cargo add` now considers `rust-version` when selecting packages.](https://github.com/rust-lang/cargo/pull/12078/)
- [Automatically inherit workspace fields when running `cargo new`/`cargo init`.](https://github.com/rust-lang/cargo/pull/12069/)
<a id="1.71.0-Rustdoc"></a>
@ -113,6 +227,11 @@ Rustdoc
- [Add a new `rustdoc::unescaped_backticks` lint for broken inline code.](https://github.com/rust-lang/rust/pull/105848/)
- [Support strikethrough with single tildes.](https://github.com/rust-lang/rust/pull/111152/) (`~~old~~` vs. `~new~`)
<a id="1.71.0-Misc"></a>
Misc
----
<a id="1.71.0-Compatibility-Notes"></a>
Compatibility Notes
@ -136,6 +255,16 @@ Compatibility Notes
table. This is considered to be not a use case Cargo would like to support, since it will likely
cause problems or lead to confusion.
<a id="1.71.0-Internal-Changes"></a>
Internal Changes
----------------
These changes do not affect any public interfaces of Rust, but they represent
significant improvements to the performance or internals of rustc and related
tools.
Version 1.70.0 (2023-06-01)
==========================
@ -198,7 +327,7 @@ Stabilized APIs
- [`Default for std::collections::binary_heap::IntoIter`](https://doc.rust-lang.org/stable/std/collections/binary_heap/struct.IntoIter.html)
- [`Default for std::collections::btree_map::{IntoIter, Iter, IterMut}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoIter.html)
- [`Default for std::collections::btree_map::{IntoKeys, Keys}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoKeys.html)
- [`Default for std::collections::btree_map::{IntoValues, Values}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoKeys.html)
- [`Default for std::collections::btree_map::{IntoValues, Values}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoValues.html)
- [`Default for std::collections::btree_map::Range`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.Range.html)
- [`Default for std::collections::btree_set::{IntoIter, Iter}`](https://doc.rust-lang.org/stable/std/collections/btree_set/struct.IntoIter.html)
- [`Default for std::collections::btree_set::Range`](https://doc.rust-lang.org/stable/std/collections/btree_set/struct.Range.html)
@ -2613,7 +2742,7 @@ related tools.
[`OsStr::to_ascii_lowercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_ascii_lowercase
[`OsStr::to_ascii_uppercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_ascii_uppercase
[`Peekable::peek_mut`]: https://doc.rust-lang.org/std/iter/struct.Peekable.html#method.peek_mut
[`Rc::decrement_strong_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.increment_strong_count
[`Rc::decrement_strong_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.decrement_strong_count
[`Rc::increment_strong_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.increment_strong_count
[`Vec::extend_from_within`]: https://doc.rust-lang.org/beta/std/vec/struct.Vec.html#method.extend_from_within
[`array::from_mut`]: https://doc.rust-lang.org/beta/std/array/fn.from_mut.html
@ -2622,7 +2751,7 @@ related tools.
[`cmp::max_by`]: https://doc.rust-lang.org/beta/std/cmp/fn.max_by.html
[`cmp::min_by_key`]: https://doc.rust-lang.org/beta/std/cmp/fn.min_by_key.html
[`cmp::min_by`]: https://doc.rust-lang.org/beta/std/cmp/fn.min_by.html
[`f32::is_subnormal`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_subnormal
[`f32::is_subnormal`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_subnormal
[`f64::is_subnormal`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_subnormal
[ietf6943]: https://datatracker.ietf.org/doc/html/rfc6943#section-3.1.1
@ -2958,7 +3087,7 @@ Internal Only
[`sync::OnceState`]: https://doc.rust-lang.org/stable/std/sync/struct.OnceState.html
[`panic::panic_any`]: https://doc.rust-lang.org/stable/std/panic/fn.panic_any.html
[`slice::strip_prefix`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.strip_prefix
[`slice::strip_suffix`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.strip_prefix
[`slice::strip_suffix`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.strip_suffix
[`Arc::increment_strong_count`]: https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.increment_strong_count
[`Arc::decrement_strong_count`]: https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.decrement_strong_count
[`slice::fill_with`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.fill_with
@ -8028,7 +8157,7 @@ Compatibility Notes
[39379]: https://github.com/rust-lang/rust/pull/39379
[41105]: https://github.com/rust-lang/rust/issues/41105
[`<*const T>::wrapping_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset
[`<*mut T>::wrapping_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset
[`<*mut T>::wrapping_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset-1
[`Duration::checked_add`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_add
[`Duration::checked_div`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_div
[`Duration::checked_mul`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_mul
@ -9006,7 +9135,7 @@ Stabilized APIs
* [`f64::to_radians`](https://doc.rust-lang.org/std/primitive.f64.html#method.to_radians)
(in libcore - previously stabilized in libstd)
* [`Iterator::sum`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum)
* [`Iterator::product`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum)
* [`Iterator::product`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.product)
* [`Cell::get_mut`](https://doc.rust-lang.org/std/cell/struct.Cell.html#method.get_mut)
* [`RefCell::get_mut`](https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.get_mut)

View File

@ -134,7 +134,7 @@ pub trait LayoutCalculator {
scalar_valid_range: (Bound<u128>, Bound<u128>),
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
niche_optimize_enum: bool,
dont_niche_optimize_enum: bool,
always_sized: bool,
) -> Option<LayoutS> {
let dl = self.current_data_layout();
@ -183,10 +183,10 @@ pub trait LayoutCalculator {
// (Typechecking will reject discriminant-sizing attrs.)
let v = present_first;
let kind = if is_enum || variants[v].is_empty() {
let kind = if is_enum || variants[v].is_empty() || always_sized {
StructKind::AlwaysSized
} else {
if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized }
StructKind::MaybeUnsized
};
let mut st = self.univariant(dl, &variants[v], repr, kind)?;
@ -280,7 +280,7 @@ pub trait LayoutCalculator {
}
let calculate_niche_filling_layout = || -> Option<TmpLayout> {
if niche_optimize_enum {
if dont_niche_optimize_enum {
return None;
}

View File

@ -209,7 +209,7 @@ pub enum TargetDataLayoutErrors<'a> {
InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError },
InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError },
MissingAlignment { cause: &'a str },
InvalidAlignment { cause: &'a str, err: String },
InvalidAlignment { cause: &'a str, err: AlignFromBytesError },
InconsistentTargetArchitecture { dl: &'a str, target: &'a str },
InconsistentTargetPointerWidth { pointer_size: u64, target: u32 },
InvalidBitsSize { err: String },
@ -414,7 +414,9 @@ pub struct Size {
// Safety: Ord is implement as just comparing numerical values and numerical values
// are not changed by (de-)serialization.
#[cfg(feature = "nightly")]
unsafe impl StableOrd for Size {}
unsafe impl StableOrd for Size {
const CAN_USE_UNSTABLE_SORT: bool = true;
}
// This is debug-printed a lot in larger structs, don't waste too much space there
impl fmt::Debug for Size {
@ -640,30 +642,65 @@ impl fmt::Debug for Align {
}
}
#[derive(Clone, Copy)]
pub enum AlignFromBytesError {
NotPowerOfTwo(u64),
TooLarge(u64),
}
impl AlignFromBytesError {
pub fn diag_ident(self) -> &'static str {
match self {
Self::NotPowerOfTwo(_) => "not_power_of_two",
Self::TooLarge(_) => "too_large",
}
}
pub fn align(self) -> u64 {
let (Self::NotPowerOfTwo(align) | Self::TooLarge(align)) = self;
align
}
}
impl fmt::Debug for AlignFromBytesError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for AlignFromBytesError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AlignFromBytesError::NotPowerOfTwo(align) => write!(f, "`{align}` is not a power of 2"),
AlignFromBytesError::TooLarge(align) => write!(f, "`{align}` is too large"),
}
}
}
impl Align {
pub const ONE: Align = Align { pow2: 0 };
pub const MAX: Align = Align { pow2: 29 };
#[inline]
pub fn from_bits(bits: u64) -> Result<Align, String> {
pub fn from_bits(bits: u64) -> Result<Align, AlignFromBytesError> {
Align::from_bytes(Size::from_bits(bits).bytes())
}
#[inline]
pub fn from_bytes(align: u64) -> Result<Align, String> {
pub fn from_bytes(align: u64) -> Result<Align, AlignFromBytesError> {
// Treat an alignment of 0 bytes like 1-byte alignment.
if align == 0 {
return Ok(Align::ONE);
}
#[cold]
fn not_power_of_2(align: u64) -> String {
format!("`{}` is not a power of 2", align)
fn not_power_of_2(align: u64) -> AlignFromBytesError {
AlignFromBytesError::NotPowerOfTwo(align)
}
#[cold]
fn too_large(align: u64) -> String {
format!("`{}` is too large", align)
fn too_large(align: u64) -> AlignFromBytesError {
AlignFromBytesError::TooLarge(align)
}
let tz = align.trailing_zeros();

View File

@ -67,7 +67,7 @@ struct ArenaChunk<T = u8> {
unsafe impl<#[may_dangle] T> Drop for ArenaChunk<T> {
fn drop(&mut self) {
unsafe { Box::from_raw(self.storage.as_mut()) };
unsafe { drop(Box::from_raw(self.storage.as_mut())) }
}
}

View File

@ -1295,6 +1295,7 @@ impl Expr {
ExprKind::Yield(..) => ExprPrecedence::Yield,
ExprKind::Yeet(..) => ExprPrecedence::Yeet,
ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs,
ExprKind::Become(..) => ExprPrecedence::Become,
ExprKind::Err => ExprPrecedence::Err,
}
}
@ -1515,6 +1516,11 @@ pub enum ExprKind {
/// with an optional value to be returned.
Yeet(Option<P<Expr>>),
/// A tail call return, with the value to be returned.
///
/// While `.0` must be a function call, we check this later, after parsing.
Become(P<Expr>),
/// Bytes included via `include_bytes!`
/// Added for optimization purposes to avoid the need to escape
/// large binary blobs - should always behave like [`ExprKind::Lit`]
@ -2646,6 +2652,15 @@ pub struct NormalAttr {
pub tokens: Option<LazyAttrTokenStream>,
}
impl NormalAttr {
pub fn from_ident(ident: Ident) -> Self {
Self {
item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None },
tokens: None,
}
}
}
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct AttrItem {
pub path: Path,

View File

@ -1,3 +1,20 @@
//! Definitions shared by macros / syntax extensions and e.g. `rustc_middle`.
use rustc_span::{def_id::DefId, symbol::Ident};
use crate::MetaItem;
pub mod allocator;
#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
pub struct StrippedCfgItem<ModId = DefId> {
pub parent_module: ModId,
pub name: Ident,
pub cfg: MetaItem,
}
impl<ModId> StrippedCfgItem<ModId> {
pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> {
StrippedCfgItem { parent_module: f(self.parent_module), name: self.name, cfg: self.cfg }
}
}

View File

@ -1457,6 +1457,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
ExprKind::Yeet(expr) => {
visit_opt(expr, |expr| vis.visit_expr(expr));
}
ExprKind::Become(expr) => vis.visit_expr(expr),
ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
ExprKind::OffsetOf(container, fields) => {

View File

@ -11,6 +11,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_macros::HashStable_Generic;
use rustc_span::symbol::{kw, sym};
#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{self, edition::Edition, Span, DUMMY_SP};
use std::borrow::Cow;

View File

@ -25,7 +25,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::{Span, DUMMY_SP};
use smallvec::{smallvec, SmallVec};
use std::{fmt, iter};
use std::{fmt, iter, mem};
/// When the main Rust parser encounters a syntax-extension invocation, it
/// parses the arguments to the invocation as a token tree. This is a very
@ -410,8 +410,17 @@ impl TokenStream {
t1.next().is_none() && t2.next().is_none()
}
pub fn map_enumerated<F: FnMut(usize, &TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
TokenStream(Lrc::new(self.0.iter().enumerate().map(|(i, tree)| f(i, tree)).collect()))
/// Applies the supplied function to each `TokenTree` and its index in `self`, returning a new `TokenStream`
///
/// It is equivalent to `TokenStream::new(self.trees().cloned().enumerate().map(|(i, tt)| f(i, tt)).collect())`.
pub fn map_enumerated_owned(
mut self,
mut f: impl FnMut(usize, TokenTree) -> TokenTree,
) -> TokenStream {
let owned = Lrc::make_mut(&mut self.0); // clone if necessary
// rely on vec's in-place optimizations to avoid another allocation
*owned = mem::take(owned).into_iter().enumerate().map(|(i, tree)| f(i, tree)).collect();
self
}
/// Create a token stream containing a single token with alone spacing.

View File

@ -245,6 +245,7 @@ pub enum ExprPrecedence {
Ret,
Yield,
Yeet,
Become,
Range,
@ -298,7 +299,8 @@ impl ExprPrecedence {
| ExprPrecedence::Continue
| ExprPrecedence::Ret
| ExprPrecedence::Yield
| ExprPrecedence::Yeet => PREC_JUMP,
| ExprPrecedence::Yeet
| ExprPrecedence::Become => PREC_JUMP,
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence

View File

@ -908,6 +908,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::Yeet(optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression);
}
ExprKind::Become(expr) => visitor.visit_expr(expr),
ExprKind::MacCall(mac) => visitor.visit_mac_call(mac),
ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression),
ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm),

View File

@ -44,6 +44,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
| asm::InlineAsmArch::AArch64
| asm::InlineAsmArch::RiscV32
| asm::InlineAsmArch::RiscV64
| asm::InlineAsmArch::LoongArch64
);
if !is_stable && !self.tcx.features().asm_experimental_arch {
feature_err(

View File

@ -71,9 +71,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
let kind = match &e.kind {
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(anon_const) => {
let anon_const = self.lower_anon_const(anon_const);
hir::ExprKind::ConstBlock(anon_const)
ExprKind::ConstBlock(c) => {
let c = self.with_new_scopes(|this| hir::ConstBlock {
def_id: this.local_def_id(c.id),
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
});
hir::ExprKind::ConstBlock(c)
}
ExprKind::Repeat(expr, count) => {
let expr = self.lower_expr(expr);
@ -271,6 +275,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::Ret(e)
}
ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
ExprKind::Become(sub_expr) => {
let sub_expr = self.lower_expr(sub_expr);
hir::ExprKind::Become(sub_expr)
}
ExprKind::InlineAsm(asm) => {
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
}
@ -665,14 +673,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(
inner_hir_id,
&[Attribute {
kind: AttrKind::Normal(ptr::P(NormalAttr {
item: AttrItem {
path: Path::from_ident(Ident::new(sym::track_caller, span)),
args: AttrArgs::Empty,
tokens: None,
},
tokens: None,
})),
kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(sym::track_caller, span)))),
id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(),
style: AttrStyle::Outer,
span: unstable_span,

View File

@ -223,6 +223,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
});
}
fn visit_inline_const(&mut self, constant: &'hir ConstBlock) {
self.insert(DUMMY_SP, constant.hir_id, Node::ConstBlock(constant));
self.with_parent(constant.hir_id, |this| {
intravisit::walk_inline_const(this, constant);
});
}
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
self.insert(expr.span, expr.hir_id, Node::Expr(expr));

View File

@ -3,6 +3,7 @@ use super::ResolverAstLoweringExt;
use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
use super::{FnDeclKind, LoweringContext, ParamMode};
use hir::definitions::DefPathData;
use rustc_ast::ptr::P;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
@ -257,10 +258,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
let itctx = ImplTraitContext::Universal;
let (generics, decl) = this.lower_generics(generics, id, &itctx, |this| {
let ret_id = asyncness.opt_return_id();
this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id)
});
let (generics, decl) =
this.lower_generics(generics, header.constness, id, &itctx, |this| {
let ret_id = asyncness.opt_return_id();
this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id)
});
let sig = hir::FnSig {
decl,
header: this.lower_fn_header(*header),
@ -295,6 +297,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
add_ty_alias_where_clause(&mut generics, *where_clauses, true);
let (generics, ty) = self.lower_generics(
&generics,
Const::No,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
@ -316,6 +319,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::Enum(enum_definition, generics) => {
let (generics, variants) = self.lower_generics(
generics,
Const::No,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -329,6 +333,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::Struct(struct_def, generics) => {
let (generics, struct_def) = self.lower_generics(
generics,
Const::No,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, struct_def),
@ -338,6 +343,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::Union(vdata, generics) => {
let (generics, vdata) = self.lower_generics(
generics,
Const::No,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, vdata),
@ -369,7 +375,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// parent lifetime.
let itctx = ImplTraitContext::Universal;
let (generics, (trait_ref, lowered_ty)) =
self.lower_generics(ast_generics, id, &itctx, |this| {
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(
trait_ref,
@ -410,8 +416,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
}))
}
ItemKind::Trait(box Trait { is_auto, unsafety, generics, bounds, items }) => {
// FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible
let constness = attrs
.unwrap_or(&[])
.iter()
.find(|x| x.has_name(sym::const_trait))
.map_or(Const::No, |x| Const::Yes(x.span));
let (generics, (unsafety, items, bounds)) = self.lower_generics(
generics,
constness,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -431,6 +444,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::TraitAlias(generics, bounds) => {
let (generics, bounds) = self.lower_generics(
generics,
Const::No,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -593,7 +607,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let fdec = &sig.decl;
let itctx = ImplTraitContext::Universal;
let (generics, (fn_dec, fn_args)) =
self.lower_generics(generics, i.id, &itctx, |this| {
self.lower_generics(generics, Const::No, i.id, &itctx, |this| {
(
// Disallow `impl Trait` in foreign items.
this.lower_fn_decl(
@ -745,6 +759,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
let (generics, kind) = self.lower_generics(
&generics,
Const::No,
i.id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@ -843,6 +858,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
self.lower_generics(
&generics,
Const::No,
i.id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
@ -1201,9 +1217,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
let header = self.lower_fn_header(sig.header);
let itctx = ImplTraitContext::Universal;
let (generics, decl) = self.lower_generics(generics, id, &itctx, |this| {
this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async)
});
let (generics, decl) =
self.lower_generics(generics, sig.header.constness, id, &itctx, |this| {
this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async)
});
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
}
@ -1275,6 +1292,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_generics<T>(
&mut self,
generics: &Generics,
constness: Const,
parent_node_id: NodeId,
itctx: &ImplTraitContext,
f: impl FnOnce(&mut Self) -> T,
@ -1372,6 +1390,87 @@ impl<'hir> LoweringContext<'_, 'hir> {
let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
predicates.extend(impl_trait_bounds.into_iter());
// Desugar `~const` bound in generics into an additional `const host: bool` param
// if the effects feature is enabled.
if let Const::Yes(span) = constness && self.tcx.features().effects
// Do not add host param if it already has it (manually specified)
&& !params.iter().any(|x| {
self.attrs.get(&x.hir_id.local_id).map_or(false, |attrs| {
attrs.iter().any(|x| x.has_name(sym::rustc_host))
})
})
{
let param_node_id = self.next_node_id();
let const_node_id = self.next_node_id();
let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
let anon_const: LocalDefId = self.create_def(def_id, const_node_id, DefPathData::AnonConst, span);
let hir_id = self.next_id();
let const_id = self.next_id();
let const_expr_id = self.next_id();
let bool_id = self.next_id();
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
self.children.push((anon_const, hir::MaybeOwner::NonOwner(const_id)));
let attr_id = self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id();
let attrs = self.arena.alloc_from_iter([
Attribute {
kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))),
span,
id: attr_id,
style: AttrStyle::Outer,
},
]);
self.attrs.insert(hir_id.local_id, attrs);
let const_body = self.lower_body(|this| {
(
&[],
hir::Expr {
hir_id: const_expr_id,
kind: hir::ExprKind::Lit(
this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }),
),
span,
},
)
});
let param = hir::GenericParam {
def_id,
hir_id,
name: hir::ParamName::Plain(Ident { name: sym::host, span }),
span,
kind: hir::GenericParamKind::Const {
ty: self.arena.alloc(self.ty(
span,
hir::TyKind::Path(hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
res: Res::PrimTy(hir::PrimTy::Bool),
span,
segments: self.arena.alloc_from_iter([hir::PathSegment {
ident: Ident { name: sym::bool, span },
hir_id: bool_id,
res: Res::PrimTy(hir::PrimTy::Bool),
args: None,
infer_args: false,
}]),
}),
)),
)),
default: Some(hir::AnonConst { def_id: anon_const, hir_id: const_id, body: const_body }),
},
colon_span: None,
pure_wrt_drop: false,
source: hir::GenericParamSource::Generics,
};
params.push(param);
}
let lowered_generics = self.arena.alloc(hir::Generics {
params: self.arena.alloc_from_iter(params),
predicates: self.arena.alloc_from_iter(predicates),

View File

@ -1539,9 +1539,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);
debug!(?opaque_ty_def_id);
// Contains the new lifetime definitions created for the TAIT (if any).
let mut collected_lifetimes = Vec::new();
// If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
// to capture the lifetimes that appear in the bounds. So visit the bounds to find out
// exactly which ones those are.
@ -1558,20 +1555,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
debug!(?lifetimes_to_remap);
let mut new_remapping = FxHashMap::default();
// Contains the new lifetime definitions created for the TAIT (if any).
// If this opaque type is only capturing a subset of the lifetimes (those that appear in
// bounds), then create the new lifetime parameters required and create a mapping from the
// old `'a` (on the function) to the new `'a` (on the opaque type).
let collected_lifetimes =
self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping);
debug!(?collected_lifetimes);
debug!(?new_remapping);
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
let collected_lifetime_mapping: Vec<_> = collected_lifetimes
.iter()
.map(|(node_id, lifetime)| {
let id = self.next_node_id();
let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
let def_id = self.local_def_id(*node_id);
(lifetime, def_id)
})
.collect();
debug!(?collected_lifetime_mapping);
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
let mut new_remapping = FxHashMap::default();
// If this opaque type is only capturing a subset of the lifetimes (those that appear
// in bounds), then create the new lifetime parameters required and create a mapping
// from the old `'a` (on the function) to the new `'a` (on the opaque type).
collected_lifetimes = lctx.create_lifetime_defs(
opaque_ty_def_id,
&lifetimes_to_remap,
&mut new_remapping,
);
debug!(?collected_lifetimes);
debug!(?new_remapping);
// Install the remapping from old to new (if any):
lctx.with_remapping(new_remapping, |lctx| {
// This creates HIR lifetime definitions as `hir::GenericParam`, in the given
@ -1610,6 +1618,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
debug!(?hir_bounds);
let lifetime_mapping = if in_trait {
self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
)
} else {
&mut []
};
let opaque_ty_item = hir::OpaqueTy {
generics: self.arena.alloc(hir::Generics {
params: lifetime_defs,
@ -1620,6 +1638,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}),
bounds: hir_bounds,
origin,
lifetime_mapping,
in_trait,
};
debug!(?opaque_ty_item);
@ -1628,20 +1647,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
})
});
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
let lifetimes =
self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| {
let id = self.next_node_id();
let l = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
hir::GenericArg::Lifetime(l)
}));
debug!(?lifetimes);
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
hir::TyKind::OpaqueDef(
hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
lifetimes,
self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
),
in_trait,
)
}
@ -1655,7 +1668,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: Span,
opaque_ty_span: Span,
) -> hir::OwnerNode<'hir> {
let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(opaque_ty_item);
let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(self.arena.alloc(opaque_ty_item));
// Generate an `type Foo = impl Trait;` declaration.
trace!("registering opaque type with id {:#?}", opaque_ty_id);
let opaque_ty_item = hir::Item {
@ -1983,7 +1996,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let lifetime = Lifetime { id: outer_node_id, ident };
collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
}
debug!(?collected_lifetimes);
// We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
@ -1993,22 +2005,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
debug!(?lifetimes_to_remap);
self.with_hir_id_owner(opaque_ty_node_id, |this| {
// If this opaque type is only capturing a subset of the lifetimes (those that appear
// in bounds), then create the new lifetime parameters required and create a mapping
// from the old `'a` (on the function) to the new `'a` (on the opaque type).
collected_lifetimes.extend(
this.create_lifetime_defs(
opaque_ty_def_id,
&lifetimes_to_remap,
&mut new_remapping,
)
// If this opaque type is only capturing a subset of the lifetimes (those that appear in
// bounds), then create the new lifetime parameters required and create a mapping from the
// old `'a` (on the function) to the new `'a` (on the opaque type).
collected_lifetimes.extend(
self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping)
.into_iter()
.map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
);
debug!(?collected_lifetimes);
debug!(?new_remapping);
);
debug!(?collected_lifetimes);
debug!(?new_remapping);
// This creates pairs of HIR lifetimes and def_ids. In the given example `type
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the
// new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to
// `TestReturn`.
let collected_lifetime_mapping: Vec<_> = collected_lifetimes
.iter()
.map(|(node_id, lifetime, res)| {
let id = self.next_node_id();
let res = res.unwrap_or(
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
);
let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res);
let def_id = self.local_def_id(*node_id);
(lifetime, def_id)
})
.collect();
debug!(?collected_lifetime_mapping);
self.with_hir_id_owner(opaque_ty_node_id, |this| {
// Install the remapping from old to new (if any):
this.with_remapping(new_remapping, |this| {
// We have to be careful to get elision right here. The
@ -2063,6 +2089,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
));
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
let lifetime_mapping = if in_trait {
self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
)
} else {
&mut []
};
let opaque_ty_item = hir::OpaqueTy {
generics: this.arena.alloc(hir::Generics {
params: generic_params,
@ -2073,6 +2109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}),
bounds: arena_vec![this; future_bound],
origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
lifetime_mapping,
in_trait,
};
@ -2096,15 +2133,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
//
// For the "output" lifetime parameters, we just want to
// generate `'_`.
let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
|(_, lifetime, res)| {
let id = self.next_node_id();
let res = res.unwrap_or(
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
);
hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, lifetime.ident, res))
},
));
let generic_args = self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
);
// Create the `Foo<...>` reference itself. Note that the `type
// Foo = impl Trait` is, internally, created as a child of the

View File

@ -364,7 +364,12 @@ impl<'a> AstValidator<'a> {
self.err_handler().emit_err(errors::BoundInContext { span, ctx });
}
fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
fn check_foreign_ty_genericless(
&self,
generics: &Generics,
before_where_clause: &TyAliasWhereClause,
after_where_clause: &TyAliasWhereClause,
) {
let cannot_have = |span, descr, remove_descr| {
self.err_handler().emit_err(errors::ExternTypesCannotHave {
span,
@ -378,9 +383,14 @@ impl<'a> AstValidator<'a> {
cannot_have(generics.span, "generic parameters", "generic parameters");
}
if !generics.where_clause.predicates.is_empty() {
cannot_have(where_span, "`where` clauses", "`where` clause");
}
let check_where_clause = |where_clause: &TyAliasWhereClause| {
if let TyAliasWhereClause(true, where_clause_span) = where_clause {
cannot_have(*where_clause_span, "`where` clauses", "`where` clause");
}
};
check_where_clause(before_where_clause);
check_where_clause(after_where_clause);
}
fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
@ -613,13 +623,12 @@ impl<'a> AstValidator<'a> {
fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
// call site which do not have a macro backtrace. See #61963.
let is_macro_callsite = self
if self
.session
.source_map()
.span_to_snippet(span)
.map(|snippet| snippet.starts_with("#["))
.unwrap_or(true);
if !is_macro_callsite {
.is_ok_and(|snippet| !snippet.starts_with("#["))
{
self.lint_buffer.buffer_lint_with_diagnostic(
MISSING_ABI,
id,
@ -1039,7 +1048,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_defaultness(fi.span, *defaultness);
self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
self.check_type_no_bounds(bounds, "`extern` blocks");
self.check_foreign_ty_genericless(generics, where_clauses.0.1);
self.check_foreign_ty_genericless(generics, &where_clauses.0, &where_clauses.1);
self.check_foreign_item_ascii_only(fi.ident);
}
ForeignItemKind::Static(_, _, body) => {

View File

@ -77,13 +77,6 @@ pub struct ForbiddenLifetimeBound {
pub spans: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag(ast_passes_forbidden_non_lifetime_param)]
pub struct ForbiddenNonLifetimeParam {
#[primary_span]
pub spans: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag(ast_passes_fn_param_too_many)]
pub struct FnParamTooMany {

View File

@ -2,7 +2,6 @@ use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd};
use rustc_errors::{Applicability, StashKey};
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
use rustc_session::Session;
@ -374,55 +373,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
if let ast::StmtKind::Semi(expr) = &stmt.kind
&& let ast::ExprKind::Assign(lhs, _, _) = &expr.kind
&& let ast::ExprKind::Type(..) = lhs.kind
&& self.sess.parse_sess.span_diagnostic.err_count() == 0
&& !self.features.type_ascription
&& !lhs.span.allows_unstable(sym::type_ascription)
{
// When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
// ascription error, but the likely intention was to write a `let` statement. (#78907).
feature_err(
&self.sess.parse_sess,
sym::type_ascription,
lhs.span,
"type ascription is experimental",
).span_suggestion_verbose(
lhs.span.shrink_to_lo(),
"you might have meant to introduce a new binding",
"let ",
Applicability::MachineApplicable,
).emit();
}
visit::walk_stmt(self, stmt);
}
fn visit_expr(&mut self, e: &'a ast::Expr) {
match e.kind {
ast::ExprKind::Type(..) => {
if self.sess.parse_sess.span_diagnostic.err_count() == 0 {
// To avoid noise about type ascription in common syntax errors,
// only emit if it is the *only* error.
gate_feature_post!(
&self,
type_ascription,
e.span,
"type ascription is experimental"
);
} else {
// And if it isn't, cancel the early-pass warning.
if let Some(err) = self
.sess
.parse_sess
.span_diagnostic
.steal_diagnostic(e.span, StashKey::EarlySyntaxWarning)
{
err.cancel()
}
}
}
ast::ExprKind::TryBlock(_) => {
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
}
@ -603,6 +555,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(dyn_star, "`dyn*` trait objects are experimental");
gate_all!(const_closures, "const closures are experimental");
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
gate_all!(explicit_tail_calls, "`become` expression is experimental");
if !visitor.features.negative_bounds {
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
@ -629,7 +582,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(box_patterns, "box pattern syntax is experimental");
gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
gate_all!(try_blocks, "`try` blocks are unstable");
gate_all!(type_ascription, "type ascription is experimental");
visit::walk_crate(&mut visitor, krate);
}

View File

@ -32,6 +32,10 @@ pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String {
State::new().bounds_to_string(bounds)
}
pub fn where_bound_predicate_to_string(where_bound_predicate: &ast::WhereBoundPredicate) -> String {
State::new().where_bound_predicate_to_string(where_bound_predicate)
}
pub fn pat_to_string(pat: &ast::Pat) -> String {
State::new().pat_to_string(pat)
}

View File

@ -824,6 +824,13 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
Self::to_string(|s| s.print_type_bounds(bounds))
}
fn where_bound_predicate_to_string(
&self,
where_bound_predicate: &ast::WhereBoundPredicate,
) -> String {
Self::to_string(|s| s.print_where_bound_predicate(where_bound_predicate))
}
fn pat_to_string(&self, pat: &ast::Pat) -> String {
Self::to_string(|s| s.print_pat(pat))
}

View File

@ -537,6 +537,11 @@ impl<'a> State<'a> {
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
}
}
ast::ExprKind::Become(result) => {
self.word("become");
self.word(" ");
self.print_expr_maybe_paren(result, parser::PREC_JUMP);
}
ast::ExprKind::InlineAsm(a) => {
// FIXME: This should have its own syntax, distinct from a macro invocation.
self.word("asm!");

View File

@ -623,19 +623,8 @@ impl<'a> State<'a> {
pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
match predicate {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
bound_generic_params,
bounded_ty,
bounds,
..
}) => {
self.print_formal_generic_params(bound_generic_params);
self.print_type(bounded_ty);
self.word(":");
if !bounds.is_empty() {
self.nbsp();
self.print_type_bounds(bounds);
}
ast::WherePredicate::BoundPredicate(where_bound_predicate) => {
self.print_where_bound_predicate(where_bound_predicate);
}
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
lifetime,
@ -658,6 +647,19 @@ impl<'a> State<'a> {
}
}
pub fn print_where_bound_predicate(
&mut self,
where_bound_predicate: &ast::WhereBoundPredicate,
) {
self.print_formal_generic_params(&where_bound_predicate.bound_generic_params);
self.print_type(&where_bound_predicate.bounded_ty);
self.word(":");
if !where_bound_predicate.bounds.is_empty() {
self.nbsp();
self.print_type_bounds(&where_bound_predicate.bounds);
}
}
fn print_use_tree(&mut self, tree: &ast::UseTree) {
match &tree.kind {
ast::UseTreeKind::Simple(rename) => {

View File

@ -72,8 +72,11 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
let kind = match self.kind {
mir::BorrowKind::Shared => "",
mir::BorrowKind::Shallow => "shallow ",
mir::BorrowKind::Unique => "uniq ",
mir::BorrowKind::Mut { .. } => "mut ",
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
// FIXME: differentiate `TwoPhaseBorrow`
mir::BorrowKind::Mut {
kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow,
} => "mut ",
};
write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
}

View File

@ -278,7 +278,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
move_from_span: Span,
move_from_desc: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc,)
struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc)
}
/// Signal an error due to an attempt to move out of the interior

View File

@ -4,8 +4,8 @@ use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::visit::TyContext;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue,
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, SourceInfo, Statement,
StatementKind, Terminator, TerminatorKind, UserTypeProjection,
};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::visit::TypeVisitable;
@ -49,10 +49,6 @@ struct ConstraintGeneration<'cg, 'tcx> {
}
impl<'cg, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'tcx> {
fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
self.super_basic_block_data(bb, data);
}
/// We sometimes have `substs` within an rvalue, or within a
/// call. Make them live at the location where they appear.
fn visit_substs(&mut self, substs: &SubstsRef<'tcx>, location: Location) {

View File

@ -59,7 +59,7 @@ macro_rules! impl_visitable {
}
fn reconstruct_before_statement_effect(
&self,
&mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
@ -69,7 +69,7 @@ macro_rules! impl_visitable {
}
fn reconstruct_statement_effect(
&self,
&mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
@ -79,7 +79,7 @@ macro_rules! impl_visitable {
}
fn reconstruct_before_terminator_effect(
&self,
&mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
@ -89,7 +89,7 @@ macro_rules! impl_visitable {
}
fn reconstruct_terminator_effect(
&self,
&mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
@ -125,15 +125,9 @@ pub struct Borrows<'a, 'tcx> {
borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
}
struct StackEntry {
bb: mir::BasicBlock,
lo: usize,
hi: usize,
}
struct OutOfScopePrecomputer<'a, 'tcx> {
visited: BitSet<mir::BasicBlock>,
visit_stack: Vec<StackEntry>,
visit_stack: Vec<mir::BasicBlock>,
body: &'a Body<'tcx>,
regioncx: &'a RegionInferenceContext<'tcx>,
borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
@ -158,29 +152,50 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
borrow_region: RegionVid,
first_location: Location,
) {
// We visit one BB at a time. The complication is that we may start in the
// middle of the first BB visited (the one containing `first_location`), in which
// case we may have to later on process the first part of that BB if there
// is a path back to its start.
// For visited BBs, we record the index of the first statement processed.
// (In fully processed BBs this index is 0.) Note also that we add BBs to
// `visited` once they are added to `stack`, before they are actually
// processed, because this avoids the need to look them up again on
// completion.
self.visited.insert(first_location.block);
let first_block = first_location.block;
let mut first_lo = first_location.statement_index;
let first_hi = self.body[first_block].statements.len();
let first_bb_data = &self.body.basic_blocks[first_block];
self.visit_stack.push(StackEntry { bb: first_block, lo: first_lo, hi: first_hi });
// This is the first block, we only want to visit it from the creation of the borrow at
// `first_location`.
let first_lo = first_location.statement_index;
let first_hi = first_bb_data.statements.len();
'preorder: while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() {
if let Some(kill_stmt) = self.regioncx.first_non_contained_inclusive(
borrow_region,
first_block,
first_lo,
first_hi,
) {
let kill_location = Location { block: first_block, statement_index: kill_stmt };
// If region does not contain a point at the location, then add to list and skip
// successor locations.
debug!("borrow {:?} gets killed at {:?}", borrow_index, kill_location);
self.borrows_out_of_scope_at_location
.entry(kill_location)
.or_default()
.push(borrow_index);
// The borrow is already dead, there is no need to visit other blocks.
return;
}
// The borrow is not dead. Add successor BBs to the work list, if necessary.
for succ_bb in first_bb_data.terminator().successors() {
if self.visited.insert(succ_bb) {
self.visit_stack.push(succ_bb);
}
}
// We may end up visiting `first_block` again. This is not an issue: we know at this point
// that it does not kill the borrow in the `first_lo..=first_hi` range, so checking the
// `0..first_lo` range and the `0..first_hi` range give the same result.
while let Some(block) = self.visit_stack.pop() {
let bb_data = &self.body[block];
let num_stmts = bb_data.statements.len();
if let Some(kill_stmt) =
self.regioncx.first_non_contained_inclusive(borrow_region, bb, lo, hi)
self.regioncx.first_non_contained_inclusive(borrow_region, block, 0, num_stmts)
{
let kill_location = Location { block: bb, statement_index: kill_stmt };
let kill_location = Location { block, statement_index: kill_stmt };
// If region does not contain a point at the location, then add to list and skip
// successor locations.
debug!("borrow {:?} gets killed at {:?}", borrow_index, kill_location);
@ -188,38 +203,15 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
.entry(kill_location)
.or_default()
.push(borrow_index);
continue 'preorder;
}
// If we process the first part of the first basic block (i.e. we encounter that block
// for the second time), we no longer have to visit its successors again.
if bb == first_block && hi != first_hi {
// We killed the borrow, so we do not visit this block's successors.
continue;
}
// Add successor BBs to the work list, if necessary.
let bb_data = &self.body[bb];
debug_assert!(hi == bb_data.statements.len());
for succ_bb in bb_data.terminator().successors() {
if !self.visited.insert(succ_bb) {
if succ_bb == first_block && first_lo > 0 {
// `succ_bb` has been seen before. If it wasn't
// fully processed, add its first part to `stack`
// for processing.
self.visit_stack.push(StackEntry { bb: succ_bb, lo: 0, hi: first_lo - 1 });
// And update this entry with 0, to represent the
// whole BB being processed.
first_lo = 0;
}
} else {
// succ_bb hasn't been seen before. Add it to
// `stack` for processing.
self.visit_stack.push(StackEntry {
bb: succ_bb,
lo: 0,
hi: self.body[succ_bb].statements.len(),
});
if self.visited.insert(succ_bb) {
self.visit_stack.push(succ_bb);
}
}
}
@ -343,7 +335,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
type Idx = BorrowIndex;
fn before_statement_effect(
&self,
&mut self,
trans: &mut impl GenKill<Self::Idx>,
_statement: &mir::Statement<'tcx>,
location: Location,
@ -352,7 +344,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
}
fn statement_effect(
&self,
&mut self,
trans: &mut impl GenKill<Self::Idx>,
stmt: &mir::Statement<'tcx>,
location: Location,
@ -400,7 +392,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
}
fn before_terminator_effect(
&self,
&mut self,
trans: &mut impl GenKill<Self::Idx>,
_terminator: &mir::Terminator<'tcx>,
location: Location,
@ -409,7 +401,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
}
fn terminator_effect(
&self,
&mut self,
trans: &mut impl GenKill<Self::Idx>,
terminator: &mir::Terminator<'tcx>,
_location: Location,
@ -426,7 +418,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
}
fn call_return_effect(
&self,
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,

View File

@ -180,24 +180,25 @@ trait TypeOpInfo<'tcx> {
return;
};
let placeholder_region = tcx.mk_re_placeholder(ty::Placeholder {
universe: adjusted_universe.into(),
bound: placeholder.bound,
});
let placeholder_region = ty::Region::new_placeholder(
tcx,
ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound },
);
let error_region =
if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
let adjusted_universe =
error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
adjusted_universe.map(|adjusted| {
tcx.mk_re_placeholder(ty::Placeholder {
universe: adjusted.into(),
bound: error_placeholder.bound,
})
})
} else {
None
};
let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) =
error_element
{
let adjusted_universe =
error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
adjusted_universe.map(|adjusted| {
ty::Region::new_placeholder(
tcx,
ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound },
)
})
} else {
None
};
debug!(?placeholder_region);
@ -390,7 +391,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
error_region,
&region_constraints,
|vid| ocx.infcx.region_var_origin(vid),
|vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_re_var(vid)),
|vid| ocx.infcx.universe_of_region(ty::Region::new_var(ocx.infcx.tcx, vid)),
)
}
@ -411,7 +412,7 @@ fn try_extract_error_from_region_constraints<'tcx>(
}
// FIXME: Should this check the universe of the var?
Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
Some((infcx.tcx.mk_re_var(vid), cause.clone()))
Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
}
_ => None,
}

View File

@ -1,6 +1,5 @@
use std::iter;
use either::Either;
use hir::PatField;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{
@ -14,9 +13,10 @@ use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place,
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
VarBindingForm,
};
use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty};
use rustc_middle::util::CallKind;
@ -27,6 +27,7 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::ObligationCtxt;
use std::iter;
use crate::borrow_set::TwoPhaseActivation;
use crate::borrowck_errors;
@ -677,8 +678,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let tcx = self.infcx.tcx;
// Find out if the predicates show that the type is a Fn or FnMut
let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder()
let find_fn_kind_from_did = |(pred, _): (ty::Clause<'tcx>, _)| {
if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
&& pred.self_ty() == ty
{
if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
@ -704,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
.explicit_item_bounds(def_id)
.subst_iter_copied(tcx, substs)
.find_map(find_fn_kind_from_did),
.find_map(|(clause, span)| find_fn_kind_from_did((clause, span))),
ty::Closure(_, substs) => match substs.as_closure().kind() {
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
@ -775,7 +776,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let predicates: Result<Vec<_>, _> = errors
.into_iter()
.map(|err| match err.obligation.predicate.kind().skip_binder() {
PredicateKind::Clause(ty::Clause::Trait(predicate)) => {
PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
match predicate.self_ty().kind() {
ty::Param(param_ty) => Ok((
generics.type_param(param_ty, tcx),
@ -926,7 +927,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// FIXME: supply non-"" `opt_via` when appropriate
let first_borrow_desc;
let mut err = match (gen_borrow_kind, issued_borrow.kind) {
(BorrowKind::Shared, BorrowKind::Mut { .. }) => {
(
BorrowKind::Shared,
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
) => {
first_borrow_desc = "mutable ";
self.cannot_reborrow_already_borrowed(
span,
@ -940,7 +944,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None,
)
}
(BorrowKind::Mut { .. }, BorrowKind::Shared) => {
(
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
BorrowKind::Shared,
) => {
first_borrow_desc = "immutable ";
let mut err = self.cannot_reborrow_already_borrowed(
span,
@ -962,7 +969,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err
}
(BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
(
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
) => {
first_borrow_desc = "first ";
let mut err = self.cannot_mutably_borrow_multiply(
span,
@ -972,7 +982,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&msg_borrow,
None,
);
self.suggest_split_at_mut_if_applicable(
self.suggest_slice_method_if_applicable(
&mut err,
place,
issued_borrow.borrowed_place,
@ -982,15 +992,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
issued_borrow.borrowed_place,
&issued_spans,
);
self.explain_iterator_advancement_in_for_loop_if_applicable(
&mut err,
span,
&issued_spans,
);
err
}
(BorrowKind::Unique, BorrowKind::Unique) => {
(
BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
) => {
first_borrow_desc = "first ";
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
}
(BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => {
(BorrowKind::Mut { .. }, BorrowKind::Shallow) => {
if let Some(immutable_section_description) =
self.classify_immutable_section(issued_borrow.assigned_place)
{
@ -1004,7 +1022,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
borrow_spans.var_subdiag(
None,
&mut err,
Some(BorrowKind::Unique),
Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }),
|kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
@ -1038,7 +1056,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
(BorrowKind::Unique, _) => {
(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, _) => {
first_borrow_desc = "first ";
self.cannot_uniquely_borrow_by_one_closure(
span,
@ -1052,7 +1070,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
}
(BorrowKind::Shared, BorrowKind::Unique) => {
(BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
first_borrow_desc = "first ";
self.cannot_reborrow_already_uniquely_borrowed(
span,
@ -1067,7 +1085,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
}
(BorrowKind::Mut { .. }, BorrowKind::Unique) => {
(BorrowKind::Mut { .. }, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
first_borrow_desc = "first ";
self.cannot_reborrow_already_uniquely_borrowed(
span,
@ -1085,10 +1103,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow)
| (
BorrowKind::Shallow,
BorrowKind::Mut { .. }
| BorrowKind::Unique
| BorrowKind::Shared
| BorrowKind::Shallow,
BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow,
) => unreachable!(),
};
@ -1252,7 +1267,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
fn suggest_split_at_mut_if_applicable(
fn suggest_slice_method_if_applicable(
&self,
err: &mut Diagnostic,
place: Place<'tcx>,
@ -1264,7 +1279,75 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.help(
"consider using `.split_at_mut(position)` or similar method to obtain \
two mutable non-overlapping sub-slices",
);
)
.help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices");
}
}
/// Suggest using `while let` for call `next` on an iterator in a for loop.
///
/// For example:
/// ```ignore (illustrative)
///
/// for x in iter {
/// ...
/// iter.next()
/// }
/// ```
pub(crate) fn explain_iterator_advancement_in_for_loop_if_applicable(
&self,
err: &mut Diagnostic,
span: Span,
issued_spans: &UseSpans<'tcx>,
) {
let issue_span = issued_spans.args_or_use();
let tcx = self.infcx.tcx;
let hir = tcx.hir();
let Some(body_id) = hir.get(self.mir_hir_id()).body_id() else { return };
let typeck_results = tcx.typeck(self.mir_def_id());
struct ExprFinder<'hir> {
issue_span: Span,
expr_span: Span,
body_expr: Option<&'hir hir::Expr<'hir>>,
loop_bind: Option<Symbol>,
}
impl<'hir> Visitor<'hir> for ExprFinder<'hir> {
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
if let hir::ExprKind::Loop(hir::Block{ stmts: [stmt, ..], ..}, _, hir::LoopSource::ForLoop, _) = ex.kind &&
let hir::StmtKind::Expr(hir::Expr{ kind: hir::ExprKind::Match(call, [_, bind, ..], _), ..}) = stmt.kind &&
let hir::ExprKind::Call(path, _args) = call.kind &&
let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _, )) = path.kind &&
let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind &&
let hir::QPath::LangItem(LangItem::OptionSome, _, _) = path &&
let PatField { pat: hir::Pat{ kind: hir::PatKind::Binding(_, _, ident, ..), .. }, ..} = field &&
self.issue_span.source_equal(call.span) {
self.loop_bind = Some(ident.name);
}
if let hir::ExprKind::MethodCall(body_call, _recv, ..) = ex.kind &&
body_call.ident.name == sym::next && ex.span.source_equal(self.expr_span) {
self.body_expr = Some(ex);
}
hir::intravisit::walk_expr(self, ex);
}
}
let mut finder =
ExprFinder { expr_span: span, issue_span, loop_bind: None, body_expr: None };
finder.visit_expr(hir.body(body_id).value);
if let Some(loop_bind) = finder.loop_bind &&
let Some(body_expr) = finder.body_expr &&
let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id) &&
let Some(trait_did) = tcx.trait_of_item(def_id) &&
tcx.is_diagnostic_item(sym::Iterator, trait_did) {
err.note(format!(
"a for loop advances the iterator for you, the result is stored in `{}`.",
loop_bind
));
err.help("if you want to call `next` on a iterator within the loop, consider using `while let`.");
}
}
@ -1720,18 +1803,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(
Some(name),
BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
) => self.report_escaping_closure_capture(
borrow_spans,
borrow_span,
&RegionName {
name: self.synthesize_region_name(),
source: RegionNameSource::Static,
},
ConstraintCategory::CallArgument(None),
var_or_use_span,
&format!("`{}`", name),
"block",
),
) if borrow_spans.for_generator() || borrow_spans.for_closure() => self
.report_escaping_closure_capture(
borrow_spans,
borrow_span,
&RegionName {
name: self.synthesize_region_name(),
source: RegionNameSource::Static,
},
ConstraintCategory::CallArgument(None),
var_or_use_span,
&format!("`{}`", name),
"block",
),
(
Some(name),
BorrowExplanation::MustBeValidFor {
@ -1744,7 +1828,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
span,
..
},
) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
) if borrow_spans.for_generator() || borrow_spans.for_closure() => self
.report_escaping_closure_capture(
borrow_spans,
borrow_span,
@ -2579,7 +2663,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
let tcx = self.infcx.tcx;
if let (
Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
Some(Terminator {
kind: TerminatorKind::Call { call_source: CallSource::OverloadedOperator, .. },
..
}),
Some((method_did, method_substs)),
) = (
&self.body[loan.reserve_location.block].terminator,

View File

@ -6,10 +6,10 @@ use rustc_hir::intravisit::Visitor;
use rustc_index::IndexSlice;
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::mir::{
Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place,
Rvalue, Statement, StatementKind, TerminatorKind,
Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location,
Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind,
};
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::{self, RegionVid, TyCtxt};
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{sym, DesugaringKind, Span};
@ -494,7 +494,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} else if self.was_captured_by_trait_object(borrow) {
LaterUseKind::TraitCapture
} else if location.statement_index == block.statements.len() {
if let TerminatorKind::Call { func, from_hir_call: true, .. } =
if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } =
&block.terminator().kind
{
// Just point to the function, to reduce the chance of overlapping spans.
@ -584,7 +584,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
},
// If we see an unsized cast, then if it is our data we should check
// whether it is being cast to a trait object.
Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, ty) => {
Rvalue::Cast(
CastKind::PointerCoercion(PointerCoercion::Unsize),
operand,
ty,
) => {
match operand {
Operand::Copy(place) | Operand::Move(place) => {
if let Some(from) = place.as_local() {

View File

@ -13,8 +13,9 @@ use rustc_index::IndexSlice;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
AggregateKind, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place,
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location,
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
TerminatorKind,
};
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
@ -414,7 +415,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if !is_terminator {
continue;
} else if let Some(Terminator {
kind: TerminatorKind::Call { func, from_hir_call: false, .. },
kind:
TerminatorKind::Call {
func,
call_source: CallSource::OverloadedOperator,
..
},
..
}) = &bbd.terminator
{
@ -622,8 +628,7 @@ impl UseSpans<'_> {
err.subdiagnostic(match kind {
Some(kd) => match kd {
rustc_middle::mir::BorrowKind::Shared
| rustc_middle::mir::BorrowKind::Shallow
| rustc_middle::mir::BorrowKind::Unique => {
| rustc_middle::mir::BorrowKind::Shallow => {
CaptureVarKind::Immut { kind_span: capture_kind_span }
}
@ -839,7 +844,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("move_spans: target_temp = {:?}", target_temp);
if let Some(Terminator {
kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
kind: TerminatorKind::Call { fn_span, call_source, .. }, ..
}) = &self.body[location.block].terminator
{
let Some((method_did, method_substs)) =
@ -859,7 +864,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
method_did,
method_substs,
*fn_span,
*from_hir_call,
call_source.from_hir_call(),
Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
);
@ -1045,7 +1050,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some(def_id) => type_known_to_meet_bound_modulo_regions(
&self.infcx,
self.param_env,
tcx.mk_imm_ref(tcx.lifetimes.re_erased, ty),
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty),
def_id,
),
_ => false,
@ -1141,6 +1146,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Avoid pointing to the same function in multiple different
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
self.explain_iterator_advancement_in_for_loop_if_applicable(
err,
span,
&move_spans,
);
let func = tcx.def_path_str(method_did);
err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
func,

View File

@ -123,13 +123,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
item_msg = access_place_desc;
debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
debug_assert!(is_closure_or_generator(
Place::ty_from(
the_place_err.local,
the_place_err.projection,
self.body,
self.infcx.tcx
)
.ty
the_place_err.ty(self.body, self.infcx.tcx).ty
));
reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
@ -234,7 +228,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
borrow_spans.var_subdiag(
None,
&mut err,
Some(mir::BorrowKind::Mut { allow_two_phase_borrow: false }),
Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
|_kind, var_span| {
let place = self.describe_any_place(access_place.as_ref());
crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
@ -300,7 +294,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
_,
mir::Rvalue::Ref(
_,
mir::BorrowKind::Mut { allow_two_phase_borrow: false },
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
_,
),
)),
@ -416,12 +410,28 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
_,
) = pat.kind
{
err.span_suggestion(
upvar_ident.span,
"consider changing this to be mutable",
format!("mut {}", upvar_ident.name),
Applicability::MachineApplicable,
);
if upvar_ident.name == kw::SelfLower {
for (_, node) in self.infcx.tcx.hir().parent_iter(upvar_hir_id) {
if let Some(fn_decl) = node.fn_decl() {
if !matches!(fn_decl.implicit_self, hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef) {
err.span_suggestion(
upvar_ident.span,
"consider changing this to be mutable",
format!("mut {}", upvar_ident.name),
Applicability::MachineApplicable,
);
break;
}
}
}
} else {
err.span_suggestion(
upvar_ident.span,
"consider changing this to be mutable",
format!("mut {}", upvar_ident.name),
Applicability::MachineApplicable,
);
}
}
let tcx = self.infcx.tcx;

View File

@ -508,7 +508,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let generic_arg = substs[param_index as usize];
let identity_substs =
InternalSubsts::identity_for_item(self.infcx.tcx, adt.did());
let base_ty = self.infcx.tcx.mk_adt(*adt, identity_substs);
let base_ty = Ty::new_adt(self.infcx.tcx, *adt, identity_substs);
let base_generic_arg = identity_substs[param_index as usize];
let adt_desc = adt.descr();

View File

@ -928,7 +928,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
fn any_param_predicate_mentions(
&self,
predicates: &[ty::Predicate<'tcx>],
clauses: &[ty::Clause<'tcx>],
ty: Ty<'tcx>,
region: ty::EarlyBoundRegion,
) -> bool {
@ -937,10 +937,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
&& let ty::Param(_) = ty.kind()
{
predicates.iter().any(|pred| {
clauses.iter().any(|pred| {
match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(data)) if data.self_ty() == ty => {}
ty::PredicateKind::Clause(ty::Clause::Projection(data)) if data.projection_ty.self_ty() == ty => {}
ty::ClauseKind::Trait(data) if data.self_ty() == ty => {}
ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
_ => return false,
}
tcx.any_free_region_meets(pred, |r| {

View File

@ -128,7 +128,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
destination,
target: _,
unwind: _,
from_hir_call: _,
call_source: _,
fn_span: _,
} => {
self.consume_operand(location, func);
@ -255,7 +255,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
}
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Unique | BorrowKind::Mut { .. } => {
BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if allow_two_phase_borrow(bk) {
(Deep, Reservation(wk))
@ -273,7 +273,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
Mutability::Mut => (
Deep,
Write(WriteKind::MutableBorrow(BorrowKind::Mut {
allow_two_phase_borrow: false,
kind: mir::MutBorrowKind::Default,
})),
),
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
@ -376,14 +376,11 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
}
(Read(_), BorrowKind::Shallow | BorrowKind::Shared)
| (
Read(ReadKind::Borrow(BorrowKind::Shallow)),
BorrowKind::Unique | BorrowKind::Mut { .. },
) => {
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
// Reads don't invalidate shared or shallow borrows
}
(Read(_), BorrowKind::Unique | BorrowKind::Mut { .. }) => {
(Read(_), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
if !is_active(&this.dominators, borrow, location) {
// If the borrow isn't active yet, reads don't invalidate it
@ -425,7 +422,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
// only mutable borrows should be 2-phase
assert!(match borrow.kind {
BorrowKind::Shared | BorrowKind::Shallow => false,
BorrowKind::Unique | BorrowKind::Mut { .. } => true,
BorrowKind::Mut { .. } => true,
});
self.access_place(

View File

@ -29,8 +29,8 @@ use rustc_infer::infer::{
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
};
use rustc_middle::mir::{
traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
Place, PlaceElem, PlaceRef, VarDebugInfoContents,
traversal, Body, ClearCrossCrate, Local, Location, MutBorrowKind, Mutability,
NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents,
};
use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
@ -222,7 +222,7 @@ fn do_mir_borrowck<'tcx>(
let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) =
match MoveData::gather_moves(&body, tcx, param_env) {
Ok((_, move_data)) => (move_data, Vec::new()),
Ok(move_data) => (move_data, Vec::new()),
Err((move_data, move_errors)) => (move_data, move_errors),
};
let promoted_errors = promoted
@ -368,7 +368,7 @@ fn do_mir_borrowck<'tcx>(
// Compute and report region errors, if any.
mbcx.report_region_errors(nll_errors);
let results = BorrowckResults {
let mut results = BorrowckResults {
ever_inits: flow_ever_inits,
uninits: flow_uninits,
borrows: flow_borrows,
@ -379,7 +379,7 @@ fn do_mir_borrowck<'tcx>(
rustc_mir_dataflow::visit_results(
body,
traversal::reverse_postorder(body).map(|(bb, _)| bb),
&results,
&mut results,
&mut mbcx,
);
@ -598,11 +598,12 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
// 2. loans made in overlapping scopes do not conflict
// 3. assignments do not affect things loaned out as immutable
// 4. moves do not affect things loaned out in any way
impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> {
impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorrowckCtxt<'cx, 'tcx> {
type FlowState = Flows<'cx, 'tcx>;
fn visit_statement_before_primary_effect(
&mut self,
_results: &R,
flow_state: &Flows<'cx, 'tcx>,
stmt: &'cx Statement<'tcx>,
location: Location,
@ -672,6 +673,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
fn visit_terminator_before_primary_effect(
&mut self,
_results: &R,
flow_state: &Flows<'cx, 'tcx>,
term: &'cx Terminator<'tcx>,
loc: Location,
@ -708,7 +710,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
destination,
target: _,
unwind: _,
from_hir_call: _,
call_source: _,
fn_span: _,
} => {
self.consume_operand(loc, (func, span), flow_state);
@ -782,6 +784,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
fn visit_terminator_after_primary_effect(
&mut self,
_results: &R,
flow_state: &Flows<'cx, 'tcx>,
term: &'cx Terminator<'tcx>,
loc: Location,
@ -1068,10 +1071,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
(Read(_), BorrowKind::Shared | BorrowKind::Shallow)
| (
Read(ReadKind::Borrow(BorrowKind::Shallow)),
BorrowKind::Unique | BorrowKind::Mut { .. },
) => Control::Continue,
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
Control::Continue
}
(Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => {
// This used to be a future compatibility warning (to be
@ -1084,7 +1086,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Control::Continue
}
(Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => {
(Read(kind), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
if !is_active(this.dominators(), borrow, location) {
assert!(allow_two_phase_borrow(borrow.kind));
@ -1191,7 +1193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
}
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Unique | BorrowKind::Mut { .. } => {
BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if allow_two_phase_borrow(bk) {
(Deep, Reservation(wk))
@ -1228,7 +1230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Mutability::Mut => (
Deep,
Write(WriteKind::MutableBorrow(BorrowKind::Mut {
allow_two_phase_borrow: false,
kind: MutBorrowKind::Default,
})),
),
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
@ -1562,7 +1564,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// only mutable borrows should be 2-phase
assert!(match borrow.kind {
BorrowKind::Shared | BorrowKind::Shallow => false,
BorrowKind::Unique | BorrowKind::Mut { .. } => true,
BorrowKind::Mut { .. } => true,
});
self.access_place(
@ -1956,16 +1958,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let the_place_err;
match kind {
Reservation(WriteKind::MutableBorrow(
borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }),
))
| Write(WriteKind::MutableBorrow(
borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }),
)) => {
let is_local_mutation_allowed = match borrow_kind {
BorrowKind::Unique => LocalMutationIsAllowed::Yes,
BorrowKind::Mut { .. } => is_local_mutation_allowed,
BorrowKind::Shared | BorrowKind::Shallow => unreachable!(),
Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind }))
| Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
let is_local_mutation_allowed = match mut_borrow_kind {
// `ClosureCapture` is used for mutable variable with a immutable binding.
// This is only behaviour difference between `ClosureCapture` and mutable borrows.
MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
is_local_mutation_allowed
}
};
match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
Ok(root_place) => {
@ -2028,12 +2029,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return false;
}
Read(
ReadKind::Borrow(
BorrowKind::Unique
| BorrowKind::Mut { .. }
| BorrowKind::Shared
| BorrowKind::Shallow,
)
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow)
| ReadKind::Copy,
) => {
// Access authorized

View File

@ -441,7 +441,7 @@ fn for_each_region_constraint<'tcx>(
let subject = match req.subject {
ClosureOutlivesSubject::Region(subject) => format!("{:?}", subject),
ClosureOutlivesSubject::Ty(ty) => {
format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid)))
format!("{:?}", ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)))
}
};
with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?;

View File

@ -46,11 +46,9 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
}
}
for (i, elem) in self.projection.iter().enumerate() {
let proj_base = &self.projection[..i];
for (i, (proj_base, elem)) in self.iter_projections().enumerate() {
if elem == ProjectionElem::Deref {
let ty = Place::ty_from(self.local, proj_base, body, tcx).ty;
let ty = proj_base.ty(body, tcx).ty;
match ty.kind() {
ty::Ref(_, _, hir::Mutability::Not) if i == 0 => {
// For references to thread-local statics, we do need

View File

@ -4,7 +4,9 @@ use crate::ArtificialField;
use crate::Overlap;
use crate::{AccessDepth, Deep, Shallow};
use rustc_hir as hir;
use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem};
use rustc_middle::mir::{
Body, BorrowKind, Local, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
};
use rustc_middle::ty::{self, TyCtxt};
use std::cmp::max;
use std::iter;
@ -35,7 +37,7 @@ pub fn places_conflict<'tcx>(
tcx,
body,
borrow_place,
BorrowKind::Mut { allow_two_phase_borrow: true },
BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow },
access_place.as_ref(),
AccessDepth::Deep,
bias,
@ -135,13 +137,11 @@ fn place_components_conflict<'tcx>(
}
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
for (i, (borrow_c, &access_c)) in
iter::zip(borrow_place.projection, access_place.projection).enumerate()
for ((borrow_place, borrow_c), &access_c) in
iter::zip(borrow_place.iter_projections(), access_place.projection)
{
debug!(?borrow_c, ?access_c);
let borrow_proj_base = &borrow_place.projection[..i];
// Borrow and access path both have more components.
//
// Examples:
@ -154,15 +154,7 @@ fn place_components_conflict<'tcx>(
// check whether the components being borrowed vs
// accessed are disjoint (as in the second example,
// but not the first).
match place_projection_conflict(
tcx,
body,
borrow_local,
borrow_proj_base,
borrow_c,
access_c,
bias,
) {
match place_projection_conflict(tcx, body, borrow_place, borrow_c, access_c, bias) {
Overlap::Arbitrary => {
// We have encountered different fields of potentially
// the same union - the borrow now partially overlaps.
@ -193,8 +185,7 @@ fn place_components_conflict<'tcx>(
}
if borrow_place.projection.len() > access_place.projection.len() {
for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate()
{
for (base, elem) in borrow_place.iter_projections().skip(access_place.projection.len()) {
// Borrow path is longer than the access path. Examples:
//
// - borrow of `a.b.c`, access to `a.b`
@ -203,8 +194,7 @@ fn place_components_conflict<'tcx>(
// our place. This is a conflict if that is a part our
// access cares about.
let proj_base = &borrow_place.projection[..access_place.projection.len() + i];
let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty;
let base_ty = base.ty(body, tcx).ty;
match (elem, &base_ty.kind(), access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
@ -308,8 +298,7 @@ fn place_base_conflict(l1: Local, l2: Local) -> Overlap {
fn place_projection_conflict<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
pi1_local: Local,
pi1_proj_base: &[PlaceElem<'tcx>],
pi1: PlaceRef<'tcx>,
pi1_elem: PlaceElem<'tcx>,
pi2_elem: PlaceElem<'tcx>,
bias: PlaceConflictBias,
@ -331,7 +320,7 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
Overlap::EqualOrDisjoint
} else {
let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
let ty = pi1.ty(body, tcx).ty;
if ty.is_union() {
// Different fields of a union, we are basically stuck.
debug!("place_element_conflict: STUCK-UNION");

View File

@ -1139,7 +1139,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
_ => arg.fold_with(self),
}
});
tcx.mk_opaque(def_id, tcx.mk_substs_from_iter(substs))
Ty::new_opaque(tcx, def_id, tcx.mk_substs_from_iter(substs))
}
}
@ -1158,7 +1158,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.universal_regions_outlived_by(r_scc)
.filter(|&u_r| !self.universal_regions.is_local_free_region(u_r))
.find(|&u_r| self.eval_equal(u_r, r_vid))
.map(|u_r| tcx.mk_re_var(u_r))
.map(|u_r| ty::Region::new_var(tcx, u_r))
// In the case of a failure, use `ReErased`. We will eventually
// return `None` in this case.
.unwrap_or(tcx.lifetimes.re_erased)
@ -1355,7 +1355,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let vid = self.to_region_vid(r);
let scc = self.constraint_sccs.scc(vid);
let repr = self.scc_representatives[scc];
tcx.mk_re_var(repr)
ty::Region::new_var(tcx, repr)
})
}
@ -1779,7 +1779,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
// If not, report an error.
let member_region = infcx.tcx.mk_re_var(member_region_vid);
let member_region = ty::Region::new_var(infcx.tcx, member_region_vid);
errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion {
span: m_c.definition_span,
hidden_ty: m_c.hidden_ty,

View File

@ -61,7 +61,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'tcx>,
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
@ -72,7 +72,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.collect();
debug!(?member_constraints);
for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls {
for (opaque_type_key, concrete_type) in opaque_ty_decls {
let substs = opaque_type_key.substs;
debug!(?concrete_type, ?substs);
@ -92,7 +92,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
None => {
subst_regions.push(vid);
infcx.tcx.mk_re_error_with_message(
ty::Region::new_error_with_message(
infcx.tcx,
concrete_type.span,
"opaque type with non-universal region substs",
)
@ -142,7 +143,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let ty = infcx.infer_opaque_definition_from_instantiation(
opaque_type_key,
universal_concrete_type,
origin,
);
// Sometimes two opaque types are the same only after we remap the generic parameters
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
@ -158,7 +158,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
)
.emit()
});
prev.ty = infcx.tcx.ty_error(guar);
prev.ty = Ty::new_error(infcx.tcx, guar);
}
// Pick a better span if there is one.
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
@ -214,7 +214,6 @@ pub trait InferCtxtExt<'tcx> {
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Ty<'tcx>;
}
@ -247,99 +246,117 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Ty<'tcx> {
if let Some(e) = self.tainted_by_errors() {
return self.tcx.ty_error(e);
return Ty::new_error(self.tcx, e);
}
if let Err(guar) =
check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span)
{
return Ty::new_error(self.tcx, guar);
}
let definition_ty = instantiated_ty
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
.ty;
if let Err(guar) = check_opaque_type_parameter_valid(
// `definition_ty` does not live in of the current inference context,
// so lets make sure that we don't accidentally misuse our current `infcx`.
match check_opaque_type_well_formed(
self.tcx,
opaque_type_key,
origin,
self.next_trait_solver(),
opaque_type_key.def_id,
instantiated_ty.span,
) {
return self.tcx.ty_error(guar);
}
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that.
let OpaqueTyOrigin::TyAlias { .. } = origin else {
return definition_ty;
};
let def_id = opaque_type_key.def_id;
// This logic duplicates most of `check_opaque_meets_bounds`.
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
let param_env = self.tcx.param_env(def_id);
// HACK This bubble is required for this tests to pass:
// nested-return-type2-tait2.rs
// nested-return-type2-tait3.rs
let infcx =
self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build();
let ocx = ObligationCtxt::new(&infcx);
// Require the hidden type to be well-formed with only the generics of the opaque type.
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
// hidden type is well formed even without those bounds.
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()));
let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
// the bounds that the function supplies.
let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
if let Err(err) = ocx.eq(
&ObligationCause::misc(instantiated_ty.span, def_id),
param_env,
opaque_ty,
definition_ty,
) {
Ok(hidden_ty) => hidden_ty,
Err(guar) => Ty::new_error(self.tcx, guar),
}
}
}
/// This logic duplicates most of `check_opaque_meets_bounds`.
/// FIXME(oli-obk): Also do region checks here and then consider removing
/// `check_opaque_meets_bounds` entirely.
fn check_opaque_type_well_formed<'tcx>(
tcx: TyCtxt<'tcx>,
next_trait_solver: bool,
def_id: LocalDefId,
definition_span: Span,
definition_ty: Ty<'tcx>,
) -> Result<Ty<'tcx>, ErrorGuaranteed> {
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that.
let opaque_ty_hir = tcx.hir().expect_item(def_id);
let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else {
return Ok(definition_ty);
};
let param_env = tcx.param_env(def_id);
// HACK This bubble is required for this tests to pass:
// nested-return-type2-tait2.rs
// nested-return-type2-tait3.rs
// FIXME(-Ztrait-solver=next): We probably should use `DefiningAnchor::Error`
// and prepopulate this `InferCtxt` with known opaque values, rather than
// using the `Bind` anchor here. For now it's fine.
let infcx = tcx
.infer_ctxt()
.with_next_trait_solver(next_trait_solver)
.with_opaque_type_inference(if next_trait_solver {
DefiningAnchor::Bind(def_id)
} else {
DefiningAnchor::Bubble
})
.build();
let ocx = ObligationCtxt::new(&infcx);
let identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
// the bounds that the function supplies.
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_substs);
ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
.map_err(|err| {
infcx
.err_ctxt()
.report_mismatched_types(
&ObligationCause::misc(instantiated_ty.span, def_id),
&ObligationCause::misc(definition_span, def_id),
opaque_ty,
definition_ty,
err,
)
.emit();
}
.emit()
})?;
ocx.register_obligation(Obligation::misc(
infcx.tcx,
instantiated_ty.span,
def_id,
param_env,
predicate,
));
// Require the hidden type to be well-formed with only the generics of the opaque type.
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
// hidden type is well formed even without those bounds.
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
definition_ty.into(),
)));
ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate));
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
// This is still required for many(half of the tests in ui/type-alias-impl-trait)
// tests to pass
let _ = infcx.take_opaque_types();
// This is still required for many(half of the tests in ui/type-alias-impl-trait)
// tests to pass
let _ = infcx.take_opaque_types();
if errors.is_empty() {
definition_ty
} else {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
self.tcx.ty_error(reported)
}
if errors.is_empty() {
Ok(definition_ty)
} else {
Err(infcx.err_ctxt().report_fulfillment_errors(&errors))
}
}
fn check_opaque_type_parameter_valid(
tcx: TyCtxt<'_>,
opaque_type_key: OpaqueTypeKey<'_>,
origin: OpaqueTyOrigin,
span: Span,
) -> Result<(), ErrorGuaranteed> {
match origin {
let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
match opaque_ty_hir.expect_opaque_ty().origin {
// No need to check return position impl trait (RPIT)
// because for type and const parameters they are correct
// by construction: we convert

View File

@ -89,11 +89,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
category: ConstraintCategory<'tcx>,
) {
self.prove_predicate(
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
polarity: ty::ImplPolarity::Positive,
}))),
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait(
ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
polarity: ty::ImplPolarity::Positive,
},
))),
locations,
category,
);

View File

@ -245,7 +245,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
.and(type_op::normalize::Normalize::new(ty))
.fully_perform(self.infcx, span)
.unwrap_or_else(|guar| TypeOpOutput {
output: self.infcx.tcx.ty_error(guar),
output: Ty::new_error(self.infcx.tcx, guar),
constraints: None,
error_info: None,
});

View File

@ -124,21 +124,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// Return types are a bit more complex. They may contain opaque `impl Trait` types.
let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
let output_span = body.local_decls[RETURN_PLACE].source_info.span;
if let Err(terr) = self.eq_types(
normalized_output_ty,
mir_output_ty,
Locations::All(output_span),
ConstraintCategory::BoringNoLocation,
) {
span_mirbug!(
self,
Location::START,
"equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
normalized_output_ty,
mir_output_ty,
terr
);
};
self.equate_normalized_input_or_output(normalized_output_ty, mir_output_ty, output_span);
}
#[instrument(skip(self), level = "debug")]

View File

@ -7,7 +7,6 @@ use std::{fmt, iter, mem};
use either::Either;
use hir::OpaqueTyOrigin;
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::ErrorGuaranteed;
@ -28,7 +27,8 @@ use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::*;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{SubstsRef, UserSubsts};
use rustc_middle::ty::visit::TypeVisitableExt;
@ -50,7 +50,6 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::ResultsCursor;
use crate::renumber::RegionCtxt;
use crate::session_diagnostics::MoveUnsized;
use crate::{
borrow_set::BorrowSet,
@ -139,7 +138,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
upvars: &[Upvar<'tcx>],
use_polonius: bool,
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = infcx.tcx.mk_re_var(universal_regions.fr_fn_body);
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
let mut constraints = MirTypeckRegionConstraints {
placeholder_indices: PlaceholderIndices::default(),
placeholder_index_to_region: IndexVec::default(),
@ -188,10 +187,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
// FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
// predefined opaques in the typeck root.
// FIXME(-Ztrait-solver=next): This is also totally wrong for TAITs, since
// the HIR typeck map defining usages back to their definition params,
// they won't actually match up with the usages in this body...
if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
checker.register_predefined_opaques_in_new_solver();
}
@ -241,10 +237,10 @@ pub(crate) fn type_check<'mir, 'tcx>(
decl.hidden_type.span,
format!("could not resolve {:#?}", hidden_type.ty.kind()),
);
hidden_type.ty = infcx.tcx.ty_error(reported);
hidden_type.ty = Ty::new_error(infcx.tcx, reported);
}
(opaque_type_key, (hidden_type, decl.origin))
(opaque_type_key, hidden_type)
})
.collect();
@ -480,9 +476,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
fn visit_body(&mut self, body: &Body<'tcx>) {
self.sanitize_type(&"return type", body.return_ty());
for local_decl in &body.local_decls {
self.sanitize_type(local_decl, local_decl.ty);
}
// The types of local_decls are checked above which is called in super_body.
self.super_body(body);
}
}
@ -526,7 +520,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
for elem in place.projection.iter() {
if place_ty.variant_index.is_none() {
if let Err(guar) = place_ty.ty.error_reported() {
return PlaceTy::from_ty(self.tcx().ty_error(guar));
return PlaceTy::from_ty(Ty::new_error(self.tcx(), guar));
}
}
place_ty = self.sanitize_projection(place_ty, elem, place, location, context);
@ -662,7 +656,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
PlaceTy::from_ty(match base_ty.kind() {
ty::Array(inner, _) => {
assert!(!from_end, "array subslices should not use from_end");
tcx.mk_array(*inner, to - from)
Ty::new_array(tcx, *inner, to - from)
}
ty::Slice(..) => {
assert!(from_end, "slice subslices should use from_end");
@ -755,7 +749,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
fn error(&mut self) -> Ty<'tcx> {
self.tcx().ty_error_misc()
Ty::new_misc_error(self.tcx())
}
fn get_ambient_variance(&self, context: PlaceContext) -> ty::Variance {
@ -883,8 +877,7 @@ struct BorrowCheckContext<'a, 'tcx> {
pub(crate) struct MirTypeckResults<'tcx> {
pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
pub(crate) opaque_type_values:
FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
}
/// A collection of region constraints that must be satisfied for the
@ -1042,16 +1035,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.typeck(self.body.source.def_id().expect_local())
.concrete_opaque_types
.iter()
.map(|(&def_id, &hidden_ty)| {
let substs = ty::InternalSubsts::identity_for_item(self.infcx.tcx, def_id);
(ty::OpaqueTypeKey { def_id, substs }, hidden_ty)
})
.map(|(k, v)| (*k, *v))
.collect();
let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| {
self.infcx.next_nll_region_var(
self.infcx.next_nll_region_var_in_universe(
NllRegionVariableOrigin::Existential { from_forall: false },
|| RegionCtxt::Unknown,
ty::UniverseIndex::ROOT,
)
});
@ -1061,15 +1051,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::OpaqueType,
CustomTypeOp::new(
|ocx| {
for (key, hidden_ty) in renumbered_opaques {
ocx.register_infer_ok_obligations(
ocx.infcx.register_hidden_type_in_new_solver(
key,
param_env,
hidden_ty.ty,
)?,
let mut obligations = Vec::new();
for (opaque_type_key, hidden_ty) in renumbered_opaques {
let cause = ObligationCause::dummy();
ocx.infcx.insert_hidden_type(
opaque_type_key,
&cause,
param_env,
hidden_ty.ty,
true,
&mut obligations,
)?;
ocx.infcx.add_item_bounds_for_hidden_type(
opaque_type_key.def_id.to_def_id(),
opaque_type_key.substs,
cause,
param_env,
hidden_ty.ty,
&mut obligations,
);
}
ocx.register_obligations(obligations);
Ok(())
},
"register pre-defined opaques",
@ -1366,7 +1370,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
// FIXME: check the values
}
TerminatorKind::Call { func, args, destination, from_hir_call, target, .. } => {
TerminatorKind::Call { func, args, destination, call_source, target, .. } => {
self.check_operand(func, term_location);
for arg in args {
self.check_operand(arg, term_location);
@ -1415,9 +1419,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
//
// See #91068 for an example.
self.prove_predicates(
sig.inputs_and_output
.iter()
.map(|ty| ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))),
sig.inputs_and_output.iter().map(|ty| {
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
ty.into(),
)))
}),
term_location.to_locations(),
ConstraintCategory::Boring,
);
@ -1440,7 +1446,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.add_element(region_vid, term_location);
}
self.check_call_inputs(body, term, &sig, args, term_location, *from_hir_call);
self.check_call_inputs(body, term, &sig, args, term_location, *call_source);
}
TerminatorKind::Assert { cond, msg, .. } => {
self.check_operand(cond, term_location);
@ -1567,7 +1573,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
sig: &ty::FnSig<'tcx>,
args: &[Operand<'tcx>],
term_location: Location,
from_hir_call: bool,
call_source: CallSource,
) {
debug!("check_call_inputs({:?}, {:?})", sig, args);
if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
@ -1585,7 +1591,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let op_arg_ty = op_arg.ty(body, self.tcx());
let op_arg_ty = self.normalize(op_arg_ty, term_location);
let category = if from_hir_call {
let category = if call_source.from_hir_call() {
ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty))
} else {
ConstraintCategory::Boring
@ -1846,7 +1852,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let array_ty = rvalue.ty(body.local_decls(), tcx);
self.prove_predicate(
ty::PredicateKind::WellFormed(array_ty.into()),
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(array_ty.into())),
Locations::Single(location),
ConstraintCategory::Boring,
);
@ -1902,7 +1908,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.check_operand(op, location);
match cast_kind {
CastKind::Pointer(PointerCast::ReifyFnPointer) => {
CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => {
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
// The type that we see in the fcx is like
@ -1912,7 +1918,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// and hence may contain unnormalized results.
let fn_sig = self.normalize(fn_sig, location);
let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
let ty_fn_ptr_from = Ty::new_fn_ptr(tcx, fn_sig);
if let Err(terr) = self.eq_types(
*ty,
@ -1931,12 +1937,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => {
CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(unsafety)) => {
let sig = match op.ty(body, tcx).kind() {
ty::Closure(_, substs) => substs.as_closure().sig(),
_ => bug!(),
};
let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety));
let ty_fn_ptr_from =
Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *unsafety));
if let Err(terr) = self.eq_types(
*ty,
@ -1955,7 +1962,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
CastKind::Pointer(PointerCast::UnsafeFnPointer) => {
CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => {
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
// The type that we see in the fcx is like
@ -1984,7 +1991,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
CastKind::Pointer(PointerCast::Unsize) => {
CastKind::PointerCoercion(PointerCoercion::Unsize) => {
let &ty = ty;
let trait_ref = ty::TraitRef::from_lang_item(
tcx,
@ -2019,10 +2026,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::Cast,
);
let outlives_predicate =
tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(
ty::Clause::TypeOutlives(ty::OutlivesPredicate(self_ty, *region)),
)));
let outlives_predicate = tcx.mk_predicate(Binder::dummy(
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
ty::OutlivesPredicate(self_ty, *region),
)),
));
self.prove_predicate(
outlives_predicate,
location.to_locations(),
@ -2030,7 +2038,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}
CastKind::Pointer(PointerCast::MutToConstPointer) => {
CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) => {
let ty::RawPtr(ty::TypeAndMut {
ty: ty_from,
mutbl: hir::Mutability::Mut,
@ -2072,7 +2080,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
CastKind::Pointer(PointerCast::ArrayToPointer) => {
CastKind::PointerCoercion(PointerCoercion::ArrayToPointer) => {
let ty_from = op.ty(body, tcx);
let opt_ty_elem_mut = match ty_from.kind() {
@ -2495,7 +2503,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
location, borrow_region, borrowed_place
);
let mut cursor = borrowed_place.projection.as_ref();
let tcx = self.infcx.tcx;
let field = path_utils::is_upvar_field_projection(
tcx,
@ -2509,14 +2516,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::Boring
};
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
for (base, elem) in borrowed_place.as_ref().iter_projections().rev() {
debug!("add_reborrow_constraint - iteration {:?}", elem);
match elem {
ProjectionElem::Deref => {
let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty;
let base_ty = base.ty(body, tcx).ty;
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
match base_ty.kind() {

View File

@ -500,7 +500,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
.next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic")))
.as_var();
let region = self.infcx.tcx.mk_re_var(reg_vid);
let region = ty::Region::new_var(self.infcx.tcx, reg_vid);
let va_list_ty =
self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]);
@ -660,7 +660,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
kind: ty::BrEnv,
};
let env_region = tcx.mk_re_late_bound(ty::INNERMOST, br);
let env_region = ty::Region::new_late_bound(tcx, ty::INNERMOST, br);
let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap();
// The "inputs" of the closure in the
@ -685,7 +685,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
assert_eq!(self.mir_def.to_def_id(), def_id);
let resume_ty = substs.as_generator().resume_ty();
let output = substs.as_generator().return_ty();
let generator_ty = tcx.mk_generator(def_id, substs, movability);
let generator_ty = Ty::new_generator(tcx, def_id, substs, movability);
let inputs_and_output =
self.infcx.tcx.mk_type_list(&[generator_ty, resume_ty, output]);
ty::Binder::dummy(inputs_and_output)
@ -778,7 +778,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
{
let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
debug!(?br);
let liberated_region = self.tcx.mk_re_free(all_outlive_scope.to_def_id(), br.kind);
let liberated_region =
ty::Region::new_free(self.tcx, all_outlive_scope.to_def_id(), br.kind);
let region_vid = {
let name = match br.kind.get_name() {
Some(name) => name,
@ -889,7 +890,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
tcx.fold_regions(value, |region, _| tcx.mk_re_var(self.to_region_vid(region)))
tcx.fold_regions(value, |region, _| ty::Region::new_var(tcx, self.to_region_vid(region)))
}
}
@ -929,7 +930,7 @@ fn for_each_late_bound_region_in_item<'tcx>(
for bound_var in tcx.late_bound_vars(tcx.hir().local_def_id_to_hir_id(mir_def_id)) {
let ty::BoundVariableKind::Region(bound_region) = bound_var else { continue; };
let liberated_region = tcx.mk_re_free(mir_def_id.to_def_id(), bound_region);
let liberated_region = ty::Region::new_free(tcx, mir_def_id.to_def_id(), bound_region);
f(liberated_region);
}
}

View File

@ -1,4 +1,5 @@
builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
builtin_macros_alloc_must_statics = allocators must be statics
builtin_macros_asm_clobber_abi = clobber_abi
builtin_macros_asm_clobber_no_reg = asm with `clobber_abi` must specify explicit registers for outputs
@ -56,6 +57,9 @@ builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `e
.label = not applicable here
.label2 = not a `struct`, `enum` or `union`
builtin_macros_bench_sig = functions used as benches must have signature `fn(&mut Bencher) -> impl Termination`
builtin_macros_cannot_derive_union = this trait cannot be derived for unions
builtin_macros_cfg_accessible_has_args = `cfg_accessible` path cannot accept arguments
@ -84,6 +88,7 @@ builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8`
builtin_macros_concat_bytes_oob = numeric literal is out of bounds
builtin_macros_concat_bytestr = cannot concatenate a byte string literal
builtin_macros_concat_c_str_lit = cannot concatenate a C string literal
builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args
@ -111,6 +116,10 @@ builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
builtin_macros_expected_register_class_or_explicit_register = expected register class or explicit register
builtin_macros_export_macro_rules = cannot export macro_rules! macros from a `proc-macro` crate type currently
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
.label1 = previously here
.label2 = duplicate argument
@ -158,6 +167,8 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
builtin_macros_invalid_crate_attribute = invalid crate attribute
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
.note = only one `#[default]` attribute is needed
.label = `#[default]` used here
@ -177,6 +188,8 @@ builtin_macros_no_default_variant = no default declared
.help = make a unit variant default by placing `#[default]` above it
.suggestion = make `{$ident}` default
builtin_macros_non_abi = at least one abi must be provided as an argument to `clobber_abi`
builtin_macros_non_exhaustive_default = default variant must be exhaustive
.label = declared `#[non_exhaustive]` here
.help = consider a manual implementation of `Default`
@ -184,12 +197,20 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
.help = consider a manual implementation of `Default`
builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
builtin_macros_requires_cfg_pattern =
macro requires a cfg-pattern as an argument
.label = cfg-pattern required
builtin_macros_should_panic = functions using `#[should_panic]` must return `()`
builtin_macros_sugg = consider using a positional formatting argument instead
builtin_macros_test_arg_non_lifetime = functions used as tests can not have any non-lifetime generic parameters
builtin_macros_test_args = functions used as tests can not have any arguments
builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
.label = `{$kind}` because of this
@ -198,6 +219,10 @@ builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on
builtin_macros_test_runner_invalid = `test_runner` argument must be a path
builtin_macros_test_runner_nargs = `#![test_runner(..)]` accepts exactly 1 argument
builtin_macros_tests_not_support = building tests with panic=abort is not supported without `-Zpanic_abort_tests`
builtin_macros_trace_macros = trace_macros! accepts only `true` or `false`
builtin_macros_unexpected_lit = expected path to a trait, found literal
.label = not a trait
.str_lit = try using `#[derive({$sym})]`

View File

@ -371,24 +371,16 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
let err = p.sess.span_diagnostic.struct_span_err(
p.token.span,
"at least one abi must be provided as an argument to `clobber_abi`",
);
return Err(err);
return Err(p.sess.span_diagnostic.create_err(errors::NonABI { span: p.token.span }));
}
let mut new_abis = Vec::new();
loop {
while !p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
match p.parse_str_lit() {
Ok(str_lit) => {
new_abis.push((str_lit.symbol_unescaped, str_lit.span));
}
Err(opt_lit) => {
// If the non-string literal is a closing paren then it's the end of the list and is fine
if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
break;
}
let span = opt_lit.map_or(p.token.span, |lit| lit.span);
let mut err =
p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
@ -432,9 +424,9 @@ fn parse_reg<'a>(
ast::InlineAsmRegOrRegClass::Reg(symbol)
}
_ => {
return Err(
p.struct_span_err(p.token.span, "expected register class or explicit register")
);
return Err(p.sess.create_err(errors::ExpectedRegisterClassOrExplicitRegister {
span: p.token.span,
}));
}
};
p.bump();

View File

@ -320,6 +320,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
| ExprKind::Underscore
| ExprKind::While(_, _, _)
| ExprKind::Yeet(_)
| ExprKind::Become(_)
| ExprKind::Yield(_) => {}
}
}

View File

@ -1,5 +1,6 @@
//! Attributes injected into the crate root from command line using `-Z crate-attr`.
use crate::errors;
use rustc_ast::attr::mk_attr;
use rustc_ast::token;
use rustc_ast::{self as ast, AttrItem, AttrStyle};
@ -24,7 +25,9 @@ pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String])
};
let end_span = parser.token.span;
if parser.token != token::Eof {
parse_sess.span_diagnostic.span_err(start_span.to(end_span), "invalid crate attribute");
parse_sess
.span_diagnostic
.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
continue;
}

View File

@ -18,7 +18,7 @@ pub fn expand_compile_error<'cx>(
reason = "diagnostic message is specified by user"
)]
#[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
cx.span_err(sp, var.as_str());
cx.span_err(sp, var.to_string());
DummyResult::any(sp)
}

View File

@ -33,7 +33,7 @@ pub fn expand_concat(
accumulator.push_str(&b.to_string());
}
Ok(ast::LitKind::CStr(..)) => {
cx.span_err(e.span, "cannot concatenate a C string literal");
cx.emit_err(errors::ConcatCStrLit{ span: e.span});
has_errors = true;
}
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {

View File

@ -21,7 +21,7 @@ fn invalid_type_err(
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");
cx.emit_err(errors::ConcatCStrLit { span: span });
}
Ok(ast::LitKind::Char(_)) => {
let sugg =

View File

@ -8,7 +8,7 @@ use rustc_feature::AttributeTemplate;
use rustc_parse::validate_attr;
use rustc_session::Session;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_span::{ErrorGuaranteed, Span};
pub(crate) struct Expander(pub bool);
@ -22,7 +22,7 @@ impl MultiItemModifier for Expander {
_: bool,
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
let sess = ecx.sess;
if report_bad_target(sess, &item, span) {
if report_bad_target(sess, &item, span).is_err() {
// We don't want to pass inappropriate targets to derive macros to avoid
// follow up errors, all other errors below are recoverable.
return ExpandResult::Ready(vec![item]);
@ -103,7 +103,11 @@ fn dummy_annotatable() -> Annotatable {
})
}
fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
fn report_bad_target(
sess: &Session,
item: &Annotatable,
span: Span,
) -> Result<(), ErrorGuaranteed> {
let item_kind = match item {
Annotatable::Item(item) => Some(&item.kind),
Annotatable::Stmt(stmt) => match &stmt.kind {
@ -116,9 +120,9 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
let bad_target =
!matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
if bad_target {
sess.emit_err(errors::BadDeriveTarget { span, item: item.span() });
return Err(sess.emit_err(errors::BadDeriveTarget { span, item: item.span() }));
}
bad_target
Ok(())
}
fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) {

View File

@ -68,7 +68,6 @@ pub fn expand_deriving_clone(
_ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
}
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
let trait_def = TraitDef {
span,
path: path_std!(clone::Clone),
@ -82,7 +81,7 @@ pub fn expand_deriving_clone(
explicit_self: true,
nonself_args: Vec::new(),
ret_ty: Self_,
attributes: attrs,
attributes: thin_vec![cx.attr_word(sym::inline, span)],
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
combine_substructure: substructure,
}],

View File

@ -18,11 +18,6 @@ pub fn expand_deriving_eq(
is_const: bool,
) {
let span = cx.with_def_site_ctxt(span);
let attrs = thin_vec![
cx.attr_word(sym::inline, span),
cx.attr_nested_word(sym::doc, sym::hidden, span),
cx.attr_word(sym::no_coverage, span)
];
let trait_def = TraitDef {
span,
path: path_std!(cmp::Eq),
@ -36,7 +31,11 @@ pub fn expand_deriving_eq(
explicit_self: true,
nonself_args: vec![],
ret_ty: Unit,
attributes: attrs,
attributes: thin_vec![
cx.attr_word(sym::inline, span),
cx.attr_nested_word(sym::doc, sym::hidden, span),
cx.attr_word(sym::no_coverage, span)
],
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
cs_total_eq_assert(a, b, c)

View File

@ -15,7 +15,6 @@ pub fn expand_deriving_ord(
push: &mut dyn FnMut(Annotatable),
is_const: bool,
) {
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
let trait_def = TraitDef {
span,
path: path_std!(cmp::Ord),
@ -29,7 +28,7 @@ pub fn expand_deriving_ord(
explicit_self: true,
nonself_args: vec![(self_ref(), sym::other)],
ret_ty: Path(path_std!(cmp::Ordering)),
attributes: attrs,
attributes: thin_vec![cx.attr_word(sym::inline, span)],
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))),
}],

View File

@ -82,14 +82,13 @@ pub fn expand_deriving_partial_eq(
// No need to generate `ne`, the default suffices, and not generating it is
// faster.
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
let methods = vec![MethodDef {
name: sym::eq,
generics: Bounds::empty(),
explicit_self: true,
nonself_args: vec![(self_ref(), sym::other)],
ret_ty: Path(path_local!(bool)),
attributes: attrs,
attributes: thin_vec![cx.attr_word(sym::inline, span)],
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))),
}];

View File

@ -19,8 +19,6 @@ pub fn expand_deriving_partial_ord(
let ret_ty =
Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
// Order in which to perform matching
let tag_then_data = if let Annotatable::Item(item) = item
&& let ItemKind::Enum(def, _) = &item.kind {
@ -48,7 +46,7 @@ pub fn expand_deriving_partial_ord(
explicit_self: true,
nonself_args: vec![(self_ref(), sym::other)],
ret_ty,
attributes: attrs,
attributes: thin_vec![cx.attr_word(sym::inline, span)],
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
cs_partial_cmp(cx, span, substr, tag_then_data)

View File

@ -20,7 +20,6 @@ pub fn expand_deriving_default(
) {
item.visit_with(&mut DetectNonVariantDefaultAttr { cx });
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
let trait_def = TraitDef {
span,
path: Path::new(vec![kw::Default, sym::Default]),
@ -34,7 +33,7 @@ pub fn expand_deriving_default(
explicit_self: false,
nonself_args: Vec::new(),
ret_ty: Self_,
attributes: attrs,
attributes: thin_vec![cx.attr_word(sym::inline, span)],
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| {
match substr.fields {

View File

@ -1,7 +1,7 @@
use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::{path_std, pathvec_std};
use rustc_ast::{AttrVec, MetaItem, Mutability};
use rustc_ast::{MetaItem, Mutability};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
@ -33,7 +33,7 @@ pub fn expand_deriving_hash(
explicit_self: true,
nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
ret_ty: Unit,
attributes: AttrVec::new(),
attributes: thin_vec![cx.attr_word(sym::inline, span)],
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
hash_substructure(a, b, c)

View File

@ -87,6 +87,83 @@ pub(crate) struct ConcatBytestr {
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_concat_c_str_lit)]
pub(crate) struct ConcatCStrLit {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_export_macro_rules)]
pub(crate) struct ExportMacroRules {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_proc_macro)]
pub(crate) struct ProcMacro {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_invalid_crate_attribute)]
pub(crate) struct InvalidCrateAttr {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_non_abi)]
pub(crate) struct NonABI {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_trace_macros)]
pub(crate) struct TraceMacros {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_bench_sig)]
pub(crate) struct BenchSig {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_test_arg_non_lifetime)]
pub(crate) struct TestArgNonLifetime {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_should_panic)]
pub(crate) struct ShouldPanic {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_test_args)]
pub(crate) struct TestArgs {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_alloc_must_statics)]
pub(crate) struct AllocMustStatics {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_concat_bytes_invalid)]
pub(crate) struct ConcatBytesInvalid {
@ -201,6 +278,10 @@ pub(crate) struct BadDeriveTarget {
pub(crate) item: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_tests_not_support)]
pub(crate) struct TestsNotSupport {}
#[derive(Diagnostic)]
#[diag(builtin_macros_unexpected_lit, code = "E0777")]
pub(crate) struct BadDeriveLit {
@ -377,7 +458,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined {
rustc::untranslatable_diagnostic,
reason = "cannot translate user-provided messages"
)]
handler.struct_diagnostic(msg.as_str())
handler.struct_diagnostic(msg.to_string())
} else {
handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined)
};
@ -732,3 +813,10 @@ pub(crate) struct TestRunnerNargs {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_expected_register_class_or_explicit_register)]
pub(crate) struct ExpectedRegisterClassOrExplicitRegister {
#[primary_span]
pub(crate) span: Span,
}

View File

@ -554,9 +554,6 @@ fn report_missing_placeholders(
fmt_span: Span,
) {
let mut diag = if let &[(span, named)] = &unused[..] {
//let mut diag = ecx.struct_span_err(span, msg);
//diag.span_label(span, msg);
//diag
ecx.create_err(errors::FormatUnusedArg { span, named })
} else {
let unused_labels =

View File

@ -1,5 +1,6 @@
use crate::util::check_builtin_macro_attribute;
use crate::errors;
use rustc_ast::expand::allocator::{
global_fn_name, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
};
@ -34,7 +35,7 @@ pub fn expand(
{
(item, true, ecx.with_def_site_ctxt(ty.span))
} else {
ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocMustStatics{span: item.span()});
return vec![orig_item];
};

View File

@ -1,3 +1,4 @@
use crate::errors;
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, attr, NodeId};
@ -83,12 +84,7 @@ pub fn inject(
impl<'a> CollectProcMacros<'a> {
fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
if self.is_proc_macro_crate && self.in_root && vis.kind.is_pub() {
self.handler.span_err(
sp,
"`proc-macro` crate types currently cannot export any items other \
than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, \
or `#[proc_macro_attribute]`",
);
self.handler.emit_err(errors::ProcMacro { span: sp });
}
}
@ -157,9 +153,9 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
fn visit_item(&mut self, item: &'a ast::Item) {
if let ast::ItemKind::MacroDef(..) = item.kind {
if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) {
let msg =
"cannot export macro_rules! macros from a `proc-macro` crate type currently";
self.handler.span_err(self.source_map.guess_head_span(item.span), msg);
self.handler.emit_err(errors::ExportMacroRules {
span: self.source_map.guess_head_span(item.span),
});
}
}

View File

@ -3,12 +3,12 @@ use crate::errors;
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, attr};
use rustc_ast::{self as ast, attr, GenericParamKind};
use rustc_ast_pretty::pprust;
use rustc_errors::Applicability;
use rustc_expand::base::*;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{FileNameDisplayPreference, Span};
use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span};
use std::iter;
use thin_vec::{thin_vec, ThinVec};
@ -122,23 +122,26 @@ pub fn expand_test_or_bench(
let ast::ItemKind::Fn(fn_) = &item.kind else {
not_testable_error(cx, attr_sp, Some(&item));
return if is_stmt {
vec![Annotatable::Stmt(P(ast::Stmt {
id: ast::DUMMY_NODE_ID,
span: item.span,
kind: ast::StmtKind::Item(item),
}))]
vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))]
} else {
vec![Annotatable::Item(item)]
};
};
// has_*_signature will report any errors in the type so compilation
// check_*_signature will report any errors in the type so compilation
// will fail. We shouldn't try to expand in this case because the errors
// would be spurious.
if (!is_bench && !has_test_signature(cx, &item))
|| (is_bench && !has_bench_signature(cx, &item))
{
return vec![Annotatable::Item(item)];
let check_result = if is_bench {
check_bench_signature(cx, &item, &fn_)
} else {
check_test_signature(cx, &item, &fn_)
};
if check_result.is_err() {
return if is_stmt {
vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))]
} else {
vec![Annotatable::Item(item)]
};
}
let sp = cx.with_def_site_ctxt(item.span);
@ -523,75 +526,57 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType {
}
}
fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
fn check_test_signature(
cx: &ExtCtxt<'_>,
i: &ast::Item,
f: &ast::Fn,
) -> Result<(), ErrorGuaranteed> {
let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
let sd = &cx.sess.parse_sess.span_diagnostic;
match &i.kind {
ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => {
if let ast::Unsafe::Yes(span) = sig.header.unsafety {
sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" });
return false;
}
if let ast::Async::Yes { span, .. } = sig.header.asyncness {
sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" });
return false;
}
// If the termination trait is active, the compiler will check that the output
// type implements the `Termination` trait as `libtest` enforces that.
let has_output = match &sig.decl.output {
ast::FnRetTy::Default(..) => false,
ast::FnRetTy::Ty(t) if t.kind.is_unit() => false,
_ => true,
};
if !sig.decl.inputs.is_empty() {
sd.span_err(i.span, "functions used as tests can not have any arguments");
return false;
}
match (has_output, has_should_panic_attr) {
(true, true) => {
sd.span_err(i.span, "functions using `#[should_panic]` must return `()`");
false
}
(true, false) => {
if !generics.params.is_empty() {
sd.span_err(
i.span,
"functions used as tests must have signature fn() -> ()",
);
false
} else {
true
}
}
(false, _) => true,
}
}
_ => {
// should be unreachable because `is_test_fn_item` should catch all non-fn items
debug_assert!(false);
false
}
if let ast::Unsafe::Yes(span) = f.sig.header.unsafety {
return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
}
}
fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
let has_sig = match &i.kind {
// N.B., inadequate check, but we're running
// well before resolve, can't get too deep.
ast::ItemKind::Fn(box ast::Fn { sig, .. }) => sig.decl.inputs.len() == 1,
_ => false,
if let ast::Async::Yes { span, .. } = f.sig.header.asyncness {
return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" }));
}
// If the termination trait is active, the compiler will check that the output
// type implements the `Termination` trait as `libtest` enforces that.
let has_output = match &f.sig.decl.output {
ast::FnRetTy::Default(..) => false,
ast::FnRetTy::Ty(t) if t.kind.is_unit() => false,
_ => true,
};
if !has_sig {
cx.sess.parse_sess.span_diagnostic.span_err(
i.span,
"functions used as benches must have \
signature `fn(&mut Bencher) -> impl Termination`",
);
if !f.sig.decl.inputs.is_empty() {
return Err(sd.span_err(i.span, "functions used as tests can not have any arguments"));
}
has_sig
if has_should_panic_attr && has_output {
return Err(sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"));
}
if f.generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime)) {
return Err(sd.span_err(
i.span,
"functions used as tests can not have any non-lifetime generic parameters",
));
}
Ok(())
}
fn check_bench_signature(
cx: &ExtCtxt<'_>,
i: &ast::Item,
f: &ast::Fn,
) -> Result<(), ErrorGuaranteed> {
// N.B., inadequate check, but we're running
// well before resolve, can't get too deep.
if f.sig.decl.inputs.len() != 1 {
return Err(cx.sess.parse_sess.span_diagnostic.emit_err(errors::BenchSig { span: i.span }));
}
Ok(())
}

View File

@ -63,10 +63,7 @@ pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn Resolve
// Silently allow compiling with panic=abort on these platforms,
// but with old behavior (abort if a test fails).
} else {
span_diagnostic.err(
"building tests with panic=abort is not supported \
without `-Zpanic_abort_tests`",
);
span_diagnostic.emit_err(errors::TestsNotSupport {});
}
PanicStrategy::Unwind
}

View File

@ -1,3 +1,4 @@
use crate::errors;
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_expand::base::{self, ExtCtxt};
use rustc_span::symbol::kw;
@ -20,7 +21,7 @@ pub fn expand_trace_macros(
};
err |= cursor.next().is_some();
if err {
cx.span_err(sp, "trace_macros! accepts only `true` or `false`")
cx.emit_err(errors::TraceMacros { span: sp });
} else {
cx.set_trace_macros(value);
}

View File

@ -1,16 +1,16 @@
task:
name: freebsd
freebsd_instance:
image: freebsd-13-1-release-amd64
image: freebsd-13-2-release-amd64
setup_rust_script:
- pkg install -y curl git bash
- pkg install -y git bash
- curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh --default-toolchain none -y --profile=minimal
target_cache:
folder: target
prepare_script:
- . $HOME/.cargo/env
- ./y.rs prepare
- ./y.sh prepare
test_script:
- . $HOME/.cargo/env
- ./y.rs test
- ./y.sh test

View File

@ -46,12 +46,12 @@ jobs:
run: rustup set default-host x86_64-pc-windows-gnu
- name: Prepare dependencies
run: ./y.rs prepare
run: ./y.sh prepare
- name: Build
run: ./y.rs build --sysroot none
run: ./y.sh build --sysroot none
- name: Test abi-cafe
env:
TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
run: ./y.rs abi-cafe
run: ./y.sh abi-cafe

View File

@ -19,7 +19,7 @@ jobs:
- name: Rustfmt
run: |
cargo fmt --check
rustfmt --check build_system/mod.rs
rustfmt --check build_system/main.rs
rustfmt --check example/*
@ -91,22 +91,52 @@ jobs:
sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
- name: Prepare dependencies
run: ./y.rs prepare
- name: Build without unstable features
env:
TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
# This is the config rust-lang/rust uses for builds
run: ./y.rs build --no-unstable-features
run: ./y.sh prepare
- name: Build
run: ./y.rs build --sysroot none
run: ./y.sh build --sysroot none
- name: Test
env:
TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
run: ./y.rs test
run: ./y.sh test
- name: Install LLVM standard library
run: rustup target add ${{ matrix.env.TARGET_TRIPLE }}
# This is roughly config rust-lang/rust uses for testing
- name: Test with LLVM sysroot
# Skip native x86_64-pc-windows-gnu. It is way too slow and cross-compiled
# x86_64-pc-windows-gnu covers at least part of the tests.
if: matrix.os != 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
env:
TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
run: ./y.sh test --sysroot llvm --no-unstable-features
# This job doesn't use cg_clif in any way. It checks that all cg_clif tests work with cg_llvm too.
test_llvm:
runs-on: ubuntu-latest
timeout-minutes: 60
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v3
- name: Prepare dependencies
run: ./y.rs prepare
- name: Disable JIT tests
run: |
sed -i 's/jit./#jit./' config.txt
- name: Test
env:
TARGET_TRIPLE: x86_64-unknown-linux-gnu
run: ./y.rs test --use-backend llvm
bench:
runs-on: ubuntu-latest
@ -135,13 +165,13 @@ jobs:
run: cargo install hyperfine || true
- name: Prepare dependencies
run: ./y.rs prepare
run: ./y.sh prepare
- name: Build
run: CI_OPT=1 ./y.rs build --sysroot none
run: CI_OPT=1 ./y.sh build --sysroot none
- name: Benchmark
run: CI_OPT=1 ./y.rs bench
run: CI_OPT=1 ./y.sh bench
dist:
@ -194,13 +224,13 @@ jobs:
sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
- name: Prepare dependencies
run: ./y.rs prepare
run: ./y.sh prepare
- name: Build backend
run: CI_OPT=1 ./y.rs build --sysroot none
run: CI_OPT=1 ./y.sh build --sysroot none
- name: Build sysroot
run: CI_OPT=1 ./y.rs build
run: CI_OPT=1 ./y.sh build
- name: Package prebuilt cg_clif
run: tar cvfJ cg_clif.tar.xz dist

View File

@ -18,7 +18,7 @@ jobs:
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Prepare dependencies
run: ./y.rs prepare
run: ./y.sh prepare
- name: Test
run: ./scripts/test_bootstrap.sh
@ -38,7 +38,7 @@ jobs:
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Prepare dependencies
run: ./y.rs prepare
run: ./y.sh prepare
- name: Test
run: ./scripts/test_rustc_tests.sh

View File

@ -6,9 +6,10 @@
"rust-analyzer.imports.granularity.enforce": true,
"rust-analyzer.imports.granularity.group": "module",
"rust-analyzer.imports.prefix": "crate",
"rust-analyzer.cargo.features": ["unstable-features", "__check_build_system_using_ra"],
"rust-analyzer.cargo.features": ["unstable-features"],
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
"./build_system/Cargo.toml",
{
"crates": [
{

View File

@ -19,6 +19,12 @@ version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
[[package]]
name = "arbitrary"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e"
[[package]]
name = "autocfg"
version = "1.1.0"
@ -37,12 +43,6 @@ version = "3.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -51,23 +51,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift-bforest"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1277fbfa94bc82c8ec4af2ded3e639d49ca5f7f3c7eeab2c66accd135ece4e70"
checksum = "9b6160c0a96253993b79fb7e0983534a4515ecf666120ddf8f92068114997ebc"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6e8c31ad3b2270e9aeec38723888fe1b0ace3bea2b06b3f749ccf46661d3220"
checksum = "7b38da5f63562e42f3c929d7c76871098e5ad12c8ab44b0659ffc529f22a5b3a"
dependencies = [
"bumpalo",
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
"cranelift-control",
"cranelift-entity",
"cranelift-isle",
"gimli",
@ -80,30 +81,39 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8ac5ac30d62b2d66f12651f6b606dbdfd9c2cfd0908de6b387560a277c5c9da"
checksum = "011371e213e163b55dd9e8404b3f2d9fa52cd14dc2f3dc5b83e61ffceff126db"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd82b8b376247834b59ed9bdc0ddeb50f517452827d4a11bccf5937b213748b8"
checksum = "1bf97dde7f5ad571161cdd203a2c9c88682ef669830aea3c14ea5d164ef8bb43"
[[package]]
name = "cranelift-control"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd9a9254aee733b0f2b68e5eaaf0337ad53cb23252a056c10a35370551be8d40"
dependencies = [
"arbitrary",
]
[[package]]
name = "cranelift-entity"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40099d38061b37e505e63f89bab52199037a72b931ad4868d9089ff7268660b0"
checksum = "baf39a33ee39479d1337cd9333f3c09786c5a0ca1ec509edcaf9d1346d5de0e5"
[[package]]
name = "cranelift-frontend"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64a25d9d0a0ae3079c463c34115ec59507b4707175454f0eee0891e83e30e82d"
checksum = "65e260b92a193a0a2dccc3938f133d9532e7dcfe8d03e36bf8b7d3518c1c1793"
dependencies = [
"cranelift-codegen",
"log",
@ -113,18 +123,19 @@ dependencies = [
[[package]]
name = "cranelift-isle"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80de6a7d0486e4acbd5f9f87ec49912bf4c8fb6aea00087b989685460d4469ba"
checksum = "9446c8e1aadfcdacee1a49592bc2c25d1d9bf5484782c163e7f5485c92cd3c1c"
[[package]]
name = "cranelift-jit"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ca96b05988aa057eda09a817a6e31915fabd7f476b513123aff08053cd193dd"
checksum = "689a6df165d0f860c1e1a3d53c28944e2743c3e9ee4c678cf190fe60ad7a6ef5"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-control",
"cranelift-entity",
"cranelift-module",
"cranelift-native",
@ -138,19 +149,20 @@ dependencies = [
[[package]]
name = "cranelift-module"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5112c0be9cc5da064e0620570d67852f11ce44f2e572a58ecf7f11df73978b8"
checksum = "0b1402d6ff1695b429536b2eaa126db560fc94c375ed0e9cfb15051fc07427f7"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-control",
]
[[package]]
name = "cranelift-native"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6b03e0e03801c4b3fd8ce0758a94750c07a44e7944cc0ffbf0d3f2e7c79b00"
checksum = "eac916f3c5aff4b817e42fc2e682292b931495b3fe2603d5e3c3cf602d74e344"
dependencies = [
"cranelift-codegen",
"libc",
@ -159,12 +171,13 @@ dependencies = [
[[package]]
name = "cranelift-object"
version = "0.95.1"
version = "0.96.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48ed1b37d0972abe804cb5bf2b35f3a76a276ebbe148e3a726d8e31042790978"
checksum = "23860f4cd064017f2108e6bc5d25660a77cd6eea77f1ac0756870a00abb12e93"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-control",
"cranelift-module",
"log",
"object",
@ -186,15 +199,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
dependencies = [
"byteorder",
]
[[package]]
name = "gimli"
version = "0.27.2"
@ -273,9 +277,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "object"
version = "0.30.3"
version = "0.30.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385"
dependencies = [
"crc32fast",
"hashbrown 0.13.2",
@ -291,12 +295,13 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "regalloc2"
version = "0.6.1"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80535183cae11b149d618fbd3c37e38d7cda589d82d7769e196ca9a9042d7621"
checksum = "d4a52e724646c6c0800fc456ec43b4165d2f91fba88ceaca06d9e0b400023478"
dependencies = [
"fxhash",
"hashbrown 0.13.2",
"log",
"rustc-hash",
"slice-group-by",
"smallvec",
]
@ -313,6 +318,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc_codegen_cranelift"
version = "0.1.0"
@ -327,7 +338,6 @@ dependencies = [
"indexmap",
"libloading",
"object",
"once_cell",
"smallvec",
"target-lexicon",
]
@ -364,9 +374,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasmtime-jit-icache-coherence"
version = "8.0.1"
version = "9.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aecae978b13f7f67efb23bd827373ace4578f2137ec110bbf6a4a7cde4121bbd"
checksum = "7d90933b781e1cef7656baed671c7a90bdba0c1c694e04fdd4124419308f5cbb"
dependencies = [
"cfg-if",
"libc",
@ -397,18 +407,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
@ -421,42 +431,42 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"

View File

@ -3,31 +3,23 @@ name = "rustc_codegen_cranelift"
version = "0.1.0"
edition = "2021"
[[bin]]
# This is used just to teach rust-analyzer how to check the build system. required-features is used
# to disable it for regular builds.
name = "y"
path = "./y.rs"
required-features = ["__check_build_system_using_ra"]
[lib]
crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
cranelift-codegen = { version = "0.95.1", features = ["unwind", "all-arch"] }
cranelift-frontend = { version = "0.95.1" }
cranelift-module = { version = "0.95.1" }
cranelift-native = { version = "0.95.1" }
cranelift-jit = { version = "0.95.1", optional = true }
cranelift-object = { version = "0.95.1" }
cranelift-codegen = { version = "0.96.1", features = ["unwind", "all-arch"] }
cranelift-frontend = { version = "0.96.1" }
cranelift-module = { version = "0.96.1" }
cranelift-native = { version = "0.96.1" }
cranelift-jit = { version = "0.96.1", optional = true }
cranelift-object = { version = "0.96.1" }
target-lexicon = "0.12.0"
gimli = { version = "0.27.2", default-features = false, features = ["write"]}
object = { version = "0.30.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
indexmap = "1.9.3"
libloading = { version = "0.7.3", optional = true }
once_cell = "1.10.0"
smallvec = "1.8.1"
[patch.crates-io]
@ -46,7 +38,6 @@ smallvec = "1.8.1"
unstable-features = ["jit", "inline_asm"]
jit = ["cranelift-jit", "libloading"]
inline_asm = []
__check_build_system_using_ra = []
[package.metadata.rust-analyzer]
rustc_private = true

View File

@ -10,8 +10,8 @@ If not please open an issue.
```bash
$ git clone https://github.com/bjorn3/rustc_codegen_cranelift
$ cd rustc_codegen_cranelift
$ ./y.rs prepare
$ ./y.rs build
$ ./y.sh prepare
$ ./y.sh build
```
To run the test suite replace the last command with:
@ -20,9 +20,14 @@ To run the test suite replace the last command with:
$ ./test.sh
```
For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.rs`.
For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.sh`.
## Precompiled builds
Alternatively you can download a pre built version from the [releases] page.
Extract the `dist` directory in the archive anywhere you want.
If you want to use `cargo clif build` instead of having to specify the full path to the `cargo-clif` executable, you can add the `bin` subdirectory of the extracted `dist` directory to your `PATH`.
(tutorial [for Windows](https://stackoverflow.com/a/44272417), and [for Linux/MacOS](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path/26059#26059)).
[releases]: https://github.com/bjorn3/rustc_codegen_cranelift/releases/tag/dev
@ -30,7 +35,7 @@ Alternatively you can download a pre built version from the [releases] page.
rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects.
Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`y.rs prepare` and `y.rs build` or `test.sh`).
Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`y.sh prepare` and `y.sh build` or `test.sh`).
In the directory with your project (where you can do the usual `cargo build`), run:
@ -42,6 +47,32 @@ This will build your project with rustc_codegen_cranelift instead of the usual L
For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage.md](docs/usage.md).
## Building and testing with changes in rustc code
This is useful when changing code in `rustc_codegen_cranelift` as part of changing [main Rust repository](https://github.com/rust-lang/rust/).
This can happen, for example, when you are implementing a new compiler intrinsic.
Instruction below uses `$RustCheckoutDir` as substitute for any folder where you cloned Rust repository.
You need to do this steps to successfully compile and use the cranelift backend with your changes in rustc code:
1. `cd $RustCheckoutDir`
2. Run `python x.py setup` and choose option for compiler (`b`).
3. Build compiler and necessary tools: `python x.py build --stage=2 compiler library/std src/tools/rustdoc src/tools/rustfmt`
* (Optional) You can also build cargo by adding `src/tools/cargo` to previous command.
4. Copy exectutable files from `./build/host/stage2-tools/<your hostname triple>/release`
to `./build/host/stage2/bin/`. Note that you would need to do this every time you rebuilt `rust` repository.
5. Copy cargo from another toolchain: `cp $(rustup which cargo) .build/<your hostname triple>/stage2/bin/cargo`
* Another option is to build it at step 3 and copy with other executables at step 4.
6. Link your new `rustc` to toolchain: `rustup toolchain link stage2 ./build/host/stage2/`.
7. (Windows only) compile y.rs: `rustc +stage2 -O y.rs`.
8. You need to prefix every `./y.rs` (or `y` if you built `y.rs`) command by `rustup run stage2` to make cg_clif use your local changes in rustc.
* `rustup run stage2 ./y.rs prepare`
* `rustup run stage2 ./y.rs build`
* (Optional) run tests: `rustup run stage2 ./y.rs test`
9. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`.
## Configuration
See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all

View File

@ -1,323 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
dependencies = [
"compiler_builtins",
"gimli",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
[[package]]
name = "alloc"
version = "0.0.0"
dependencies = [
"compiler_builtins",
"core",
]
[[package]]
name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
[[package]]
name = "compiler_builtins"
version = "0.1.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "571298a3cce7e2afbd3d61abb91a18667d5ab25993ec577a88ee8ac45f00cc3a"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "core"
version = "0.0.0"
[[package]]
name = "dlmalloc"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a"
dependencies = [
"compiler_builtins",
"libc",
"rustc-std-workspace-core",
]
[[package]]
name = "fortanix-sgx-abi"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"rustc-std-workspace-core",
"rustc-std-workspace-std",
"unicode-width",
]
[[package]]
name = "gimli"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "libc"
version = "0.2.142"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
[[package]]
name = "miniz_oxide"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
dependencies = [
"adler",
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "object"
version = "0.30.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
dependencies = [
"compiler_builtins",
"memchr",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "panic_abort"
version = "0.0.0"
dependencies = [
"alloc",
"cfg-if",
"compiler_builtins",
"core",
"libc",
]
[[package]]
name = "panic_unwind"
version = "0.0.0"
dependencies = [
"alloc",
"cfg-if",
"compiler_builtins",
"core",
"libc",
"unwind",
]
[[package]]
name = "proc_macro"
version = "0.0.0"
dependencies = [
"core",
"std",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
[[package]]
name = "rustc-std-workspace-alloc"
version = "1.99.0"
dependencies = [
"alloc",
]
[[package]]
name = "rustc-std-workspace-core"
version = "1.99.0"
dependencies = [
"core",
]
[[package]]
name = "rustc-std-workspace-std"
version = "1.99.0"
dependencies = [
"std",
]
[[package]]
name = "std"
version = "0.0.0"
dependencies = [
"addr2line",
"alloc",
"cfg-if",
"compiler_builtins",
"core",
"dlmalloc",
"fortanix-sgx-abi",
"hashbrown",
"hermit-abi",
"libc",
"miniz_oxide",
"object",
"panic_abort",
"panic_unwind",
"rustc-demangle",
"std_detect",
"unwind",
"wasi",
]
[[package]]
name = "std_detect"
version = "0.1.5"
dependencies = [
"cfg-if",
"compiler_builtins",
"libc",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "sysroot"
version = "0.0.0"
dependencies = [
"alloc",
"compiler_builtins",
"core",
"std",
"test",
]
[[package]]
name = "test"
version = "0.0.0"
dependencies = [
"core",
"getopts",
"panic_abort",
"panic_unwind",
"proc_macro",
"std",
]
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
"rustc-std-workspace-std",
]
[[package]]
name = "unwind"
version = "0.0.0"
dependencies = [
"cc",
"cfg-if",
"compiler_builtins",
"core",
"libc",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]

View File

@ -1,35 +0,0 @@
[package]
name = "sysroot"
version = "0.0.0"
[dependencies]
core = { path = "./sysroot_src/library/core" }
alloc = { path = "./sysroot_src/library/alloc" }
std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
test = { path = "./sysroot_src/library/test" }
compiler_builtins = { version = "0.1.87", default-features = false, features = ["no-asm"] }
[patch.crates-io]
rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" }
[profile.dev]
lto = "off"
[profile.release]
debug = true
incremental = true
lto = "off"
# Mandatory for correctly compiling compiler-builtins
[profile.dev.package.compiler_builtins]
debug-assertions = false
overflow-checks = false
codegen-units = 10000
[profile.release.package.compiler_builtins]
debug-assertions = false
overflow-checks = false
codegen-units = 10000

View File

@ -1 +0,0 @@
#![no_std]

View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "y"
version = "0.1.0"

View File

@ -0,0 +1,13 @@
[package]
name = "y"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "y"
path = "main.rs"
[features]
unstable-features = [] # for rust-analyzer
# Do not add any dependencies

View File

@ -1,25 +1,29 @@
use std::path::Path;
use super::build_sysroot;
use super::path::Dirs;
use super::prepare::GitRepo;
use super::utils::{spawn_and_wait, CargoProject, Compiler};
use super::SysrootKind;
use super::{CodegenBackend, SysrootKind};
static ABI_CAFE_REPO: GitRepo =
GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
static ABI_CAFE_REPO: GitRepo = GitRepo::github(
"Gankra",
"abi-cafe",
"4c6dc8c9c687e2b3a760ff2176ce236872b37212",
"588df6d66abbe105",
"abi-cafe",
);
static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe");
static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe_target");
pub(crate) fn run(
channel: &str,
sysroot_kind: SysrootKind,
dirs: &Dirs,
cg_clif_dylib: &Path,
cg_clif_dylib: &CodegenBackend,
rustup_toolchain_name: Option<&str>,
bootstrap_host_compiler: &Compiler,
) {
ABI_CAFE_REPO.fetch(dirs);
spawn_and_wait(ABI_CAFE.fetch("cargo", &bootstrap_host_compiler.rustc, dirs));
ABI_CAFE_REPO.patch(dirs);
eprintln!("Building sysroot for abi-cafe");
build_sysroot::build_sysroot(
@ -28,6 +32,7 @@ pub(crate) fn run(
sysroot_kind,
cg_clif_dylib,
bootstrap_host_compiler,
rustup_toolchain_name,
bootstrap_host_compiler.triple.clone(),
);
@ -40,7 +45,14 @@ pub(crate) fn run(
cmd.arg("--pairs");
cmd.args(pairs);
cmd.arg("--add-rustc-codegen-backend");
cmd.arg(format!("cgclif:{}", cg_clif_dylib.display()));
match cg_clif_dylib {
CodegenBackend::Local(path) => {
cmd.arg(format!("cgclif:{}", path.display()));
}
CodegenBackend::Builtin(name) => {
cmd.arg(format!("cgclif:{name}"));
}
}
cmd.current_dir(ABI_CAFE.source_dir(dirs));
spawn_and_wait(cmd);

View File

@ -1,26 +1,19 @@
use std::env;
use std::fs;
use std::path::Path;
use super::path::{Dirs, RelPath};
use super::prepare::GitRepo;
use super::rustc_info::get_file_name;
use super::utils::{hyperfine_command, spawn_and_wait, CargoProject, Compiler};
use super::utils::{hyperfine_command, spawn_and_wait, Compiler};
static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
"ebobby",
"simple-raytracer",
"804a7a21b9e673a482797aa289a18ed480e4d813",
"ad6f59a2331a3f56",
"<none>",
);
// Use a separate target dir for the initial LLVM build to reduce unnecessary recompiles
static SIMPLE_RAYTRACER_LLVM: CargoProject =
CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer_llvm");
static SIMPLE_RAYTRACER: CargoProject =
CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer");
pub(crate) fn benchmark(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
benchmark_simple_raytracer(dirs, bootstrap_host_compiler);
}
@ -32,35 +25,17 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
std::process::exit(1);
}
if !SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).exists() {
SIMPLE_RAYTRACER_REPO.fetch(dirs);
spawn_and_wait(SIMPLE_RAYTRACER.fetch(
&bootstrap_host_compiler.cargo,
&bootstrap_host_compiler.rustc,
dirs,
));
}
eprintln!("[LLVM BUILD] simple-raytracer");
let build_cmd = SIMPLE_RAYTRACER_LLVM.build(bootstrap_host_compiler, dirs);
spawn_and_wait(build_cmd);
fs::copy(
SIMPLE_RAYTRACER_LLVM
.target_dir(dirs)
.join(&bootstrap_host_compiler.triple)
.join("debug")
.join(get_file_name("main", "bin")),
RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
)
.unwrap();
SIMPLE_RAYTRACER_REPO.fetch(dirs);
SIMPLE_RAYTRACER_REPO.patch(dirs);
let bench_runs = env::var("BENCH_RUNS").unwrap_or_else(|_| "10".to_string()).parse().unwrap();
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
let cargo_clif =
RelPath::DIST.to_path(dirs).join(get_file_name("cargo_clif", "bin").replace('_', "-"));
let manifest_path = SIMPLE_RAYTRACER.manifest_path(dirs);
let target_dir = SIMPLE_RAYTRACER.target_dir(dirs);
let cargo_clif = RelPath::DIST
.to_path(dirs)
.join(get_file_name(&bootstrap_host_compiler.rustc, "cargo_clif", "bin").replace('_', "-"));
let manifest_path = SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).join("Cargo.toml");
let target_dir = RelPath::BUILD.join("simple_raytracer").to_path(dirs);
let clean_cmd = format!(
"RUSTC=rustc cargo clean --manifest-path {manifest_path} --target-dir {target_dir}",
@ -68,35 +43,52 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
target_dir = target_dir.display(),
);
let llvm_build_cmd = format!(
"RUSTC=rustc cargo build --manifest-path {manifest_path} --target-dir {target_dir}",
"RUSTC=rustc cargo build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_llvm || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_llvm",
manifest_path = manifest_path.display(),
target_dir = target_dir.display(),
);
let clif_build_cmd = format!(
"RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir}",
"RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif",
cargo_clif = cargo_clif.display(),
manifest_path = manifest_path.display(),
target_dir = target_dir.display(),
);
let clif_build_opt_cmd = format!(
"RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt",
cargo_clif = cargo_clif.display(),
manifest_path = manifest_path.display(),
target_dir = target_dir.display(),
);
let bench_compile =
hyperfine_command(1, bench_runs, Some(&clean_cmd), &llvm_build_cmd, &clif_build_cmd);
let bench_compile = hyperfine_command(
1,
bench_runs,
Some(&clean_cmd),
&[&llvm_build_cmd, &clif_build_cmd, &clif_build_opt_cmd],
);
spawn_and_wait(bench_compile);
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
fs::copy(
target_dir.join("debug").join(get_file_name("main", "bin")),
RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_clif", "bin")),
)
.unwrap();
let mut bench_run = hyperfine_command(
0,
bench_runs,
None,
Path::new(".").join(get_file_name("raytracer_cg_llvm", "bin")).to_str().unwrap(),
Path::new(".").join(get_file_name("raytracer_cg_clif", "bin")).to_str().unwrap(),
&[
Path::new(".")
.join(get_file_name(&bootstrap_host_compiler.rustc, "raytracer_cg_llvm", "bin"))
.to_str()
.unwrap(),
Path::new(".")
.join(get_file_name(&bootstrap_host_compiler.rustc, "raytracer_cg_clif", "bin"))
.to_str()
.unwrap(),
Path::new(".")
.join(get_file_name(&bootstrap_host_compiler.rustc, "raytracer_cg_clif_opt", "bin"))
.to_str()
.unwrap(),
],
);
bench_run.current_dir(RelPath::BUILD.to_path(dirs));
spawn_and_wait(bench_run);

View File

@ -3,7 +3,7 @@ use std::path::PathBuf;
use super::path::{Dirs, RelPath};
use super::rustc_info::get_file_name;
use super::utils::{is_ci, is_ci_opt, CargoProject, Compiler};
use super::utils::{is_ci, is_ci_opt, maybe_incremental, CargoProject, Compiler};
pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
@ -14,8 +14,7 @@ pub(crate) fn build_backend(
use_unstable_features: bool,
) -> PathBuf {
let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs);
cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
maybe_incremental(&mut cmd);
let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default();
@ -23,11 +22,9 @@ pub(crate) fn build_backend(
// Deny warnings on CI
rustflags += " -Dwarnings";
// Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
cmd.env("CARGO_BUILD_INCREMENTAL", "false");
if !is_ci_opt() {
cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true");
cmd.env("CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS", "true");
}
}
@ -52,5 +49,5 @@ pub(crate) fn build_backend(
.target_dir(dirs)
.join(&bootstrap_host_compiler.triple)
.join(channel)
.join(get_file_name("rustc_codegen_cranelift", "dylib"))
.join(get_file_name(&bootstrap_host_compiler.rustc, "rustc_codegen_cranelift", "dylib"))
}

View File

@ -1,11 +1,13 @@
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{self, Command};
use std::process::Command;
use super::path::{Dirs, RelPath};
use super::rustc_info::{get_file_name, get_rustc_version, get_toolchain_name};
use super::utils::{remove_dir_if_exists, spawn_and_wait, try_hard_link, CargoProject, Compiler};
use super::SysrootKind;
use super::rustc_info::get_file_name;
use super::utils::{
maybe_incremental, remove_dir_if_exists, spawn_and_wait, try_hard_link, CargoProject, Compiler,
};
use super::{CodegenBackend, SysrootKind};
static DIST_DIR: RelPath = RelPath::DIST;
static BIN_DIR: RelPath = RelPath::DIST.join("bin");
@ -15,8 +17,9 @@ pub(crate) fn build_sysroot(
dirs: &Dirs,
channel: &str,
sysroot_kind: SysrootKind,
cg_clif_dylib_src: &Path,
cg_clif_dylib_src: &CodegenBackend,
bootstrap_host_compiler: &Compiler,
rustup_toolchain_name: Option<&str>,
target_triple: String,
) -> Compiler {
eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
@ -27,32 +30,52 @@ pub(crate) fn build_sysroot(
let is_native = bootstrap_host_compiler.triple == target_triple;
// Copy the backend
let cg_clif_dylib_path = if cfg!(windows) {
// Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
// binaries.
BIN_DIR
} else {
LIB_DIR
}
.to_path(dirs)
.join(cg_clif_dylib_src.file_name().unwrap());
try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path);
let cg_clif_dylib_path = match cg_clif_dylib_src {
CodegenBackend::Local(src_path) => {
// Copy the backend
let cg_clif_dylib_path = if cfg!(windows) {
// Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
// binaries.
BIN_DIR
} else {
LIB_DIR
}
.to_path(dirs)
.join(src_path.file_name().unwrap());
try_hard_link(src_path, &cg_clif_dylib_path);
CodegenBackend::Local(cg_clif_dylib_path)
}
CodegenBackend::Builtin(name) => CodegenBackend::Builtin(name.clone()),
};
// Build and copy rustc and cargo wrappers
let wrapper_base_name = get_file_name("____", "bin");
let toolchain_name = get_toolchain_name();
let wrapper_base_name = get_file_name(&bootstrap_host_compiler.rustc, "____", "bin");
for wrapper in ["rustc-clif", "rustdoc-clif", "cargo-clif"] {
let wrapper_name = wrapper_base_name.replace("____", wrapper);
let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc);
let wrapper_path = DIST_DIR.to_path(dirs).join(&wrapper_name);
build_cargo_wrapper_cmd
.env("TOOLCHAIN_NAME", toolchain_name.clone())
.arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
.arg("-o")
.arg(&wrapper_path)
.arg("-Cstrip=debuginfo");
if let Some(rustup_toolchain_name) = &rustup_toolchain_name {
build_cargo_wrapper_cmd
.env("TOOLCHAIN_NAME", rustup_toolchain_name)
.env_remove("CARGO")
.env_remove("RUSTC")
.env_remove("RUSTDOC");
} else {
build_cargo_wrapper_cmd
.env_remove("TOOLCHAIN_NAME")
.env("CARGO", &bootstrap_host_compiler.cargo)
.env("RUSTC", &bootstrap_host_compiler.rustc)
.env("RUSTDOC", &bootstrap_host_compiler.rustdoc);
}
if let CodegenBackend::Builtin(name) = cg_clif_dylib_src {
build_cargo_wrapper_cmd.env("BUILTIN_BACKEND", name);
}
spawn_and_wait(build_cargo_wrapper_cmd);
try_hard_link(wrapper_path, BIN_DIR.to_path(dirs).join(wrapper_name));
}
@ -134,12 +157,9 @@ impl SysrootTarget {
}
}
pub(crate) static ORIG_BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot");
pub(crate) static BUILD_SYSROOT: RelPath = RelPath::DOWNLOAD.join("sysroot");
pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = BUILD_SYSROOT.join("rustc_version");
pub(crate) static SYSROOT_SRC: RelPath = BUILD_SYSROOT.join("sysroot_src");
pub(crate) static STDLIB_SRC: RelPath = RelPath::BUILD.join("stdlib");
pub(crate) static STANDARD_LIBRARY: CargoProject =
CargoProject::new(&BUILD_SYSROOT, "build_sysroot");
CargoProject::new(&STDLIB_SRC.join("library/sysroot"), "stdlib_target");
pub(crate) static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup");
#[must_use]
@ -147,7 +167,7 @@ fn build_sysroot_for_triple(
dirs: &Dirs,
channel: &str,
compiler: Compiler,
cg_clif_dylib_path: &Path,
cg_clif_dylib_path: &CodegenBackend,
sysroot_kind: SysrootKind,
) -> SysrootTarget {
match sysroot_kind {
@ -155,7 +175,7 @@ fn build_sysroot_for_triple(
.unwrap_or(SysrootTarget { triple: compiler.triple, libs: vec![] }),
SysrootKind::Llvm => build_llvm_sysroot_for_triple(compiler),
SysrootKind::Clif => {
build_clif_sysroot_for_triple(dirs, channel, compiler, &cg_clif_dylib_path)
build_clif_sysroot_for_triple(dirs, channel, compiler, cg_clif_dylib_path)
}
}
}
@ -199,26 +219,8 @@ fn build_clif_sysroot_for_triple(
dirs: &Dirs,
channel: &str,
mut compiler: Compiler,
cg_clif_dylib_path: &Path,
cg_clif_dylib_path: &CodegenBackend,
) -> SysrootTarget {
match fs::read_to_string(SYSROOT_RUSTC_VERSION.to_path(dirs)) {
Err(e) => {
eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
eprintln!("Hint: Try `./y.rs prepare` to patch the sysroot source");
process::exit(1);
}
Ok(source_version) => {
let rustc_version = get_rustc_version(&compiler.rustc);
if source_version != rustc_version {
eprintln!("The patched sysroot source is outdated");
eprintln!("Source version: {}", source_version.trim());
eprintln!("Rustc version: {}", rustc_version.trim());
eprintln!("Hint: Try `./y.rs prepare` to update the patched sysroot source");
process::exit(1);
}
}
}
let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] };
if let Some(rtstartup_target_libs) = build_rtstartup(dirs, &compiler) {
@ -237,19 +239,28 @@ fn build_clif_sysroot_for_triple(
// Build sysroot
let mut rustflags = " -Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
match cg_clif_dylib_path {
CodegenBackend::Local(path) => {
rustflags.push_str(&format!(" -Zcodegen-backend={}", path.to_str().unwrap()));
}
CodegenBackend::Builtin(name) => {
rustflags.push_str(&format!(" -Zcodegen-backend={name}"));
}
};
// Necessary for MinGW to find rsbegin.o and rsend.o
rustflags
.push_str(&format!(" --sysroot={}", RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap()));
.push_str(&format!(" --sysroot {}", RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap()));
if channel == "release" {
rustflags.push_str(" -Zmir-opt-level=3");
}
compiler.rustflags += &rustflags;
let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
maybe_incremental(&mut build_cmd);
if channel == "release" {
build_cmd.arg("--release");
}
build_cmd.arg("--locked");
build_cmd.arg("--features").arg("compiler-builtins-no-asm backtrace panic-unwind");
build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true");
build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
if compiler.triple.contains("apple") {
build_cmd.env("CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO", "packed");
@ -272,13 +283,17 @@ fn build_clif_sysroot_for_triple(
}
fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
if !super::config::get_bool("keep_sysroot") {
super::prepare::prepare_stdlib(dirs, &compiler.rustc);
}
if !compiler.triple.ends_with("windows-gnu") {
return None;
}
RTSTARTUP_SYSROOT.ensure_fresh(dirs);
let rtstartup_src = SYSROOT_SRC.to_path(dirs).join("library").join("rtstartup");
let rtstartup_src = STDLIB_SRC.to_path(dirs).join("library").join("rtstartup");
let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] };
for file in ["rsbegin", "rsend"] {

View File

@ -0,0 +1,272 @@
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]
use std::env;
use std::path::PathBuf;
use std::process;
use self::utils::{is_ci, is_ci_opt, Compiler};
mod abi_cafe;
mod bench;
mod build_backend;
mod build_sysroot;
mod config;
mod path;
mod prepare;
mod rustc_info;
mod tests;
mod utils;
fn usage() {
eprintln!("{}", include_str!("usage.txt"));
}
macro_rules! arg_error {
($($err:tt)*) => {{
eprintln!($($err)*);
usage();
std::process::exit(1);
}};
}
#[derive(PartialEq, Debug)]
enum Command {
Prepare,
Build,
Test,
AbiCafe,
Bench,
}
#[derive(Copy, Clone, Debug)]
enum SysrootKind {
None,
Clif,
Llvm,
}
#[derive(Clone, Debug)]
enum CodegenBackend {
Local(PathBuf),
Builtin(String),
}
fn main() {
if env::var("RUST_BACKTRACE").is_err() {
env::set_var("RUST_BACKTRACE", "1");
}
env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
if is_ci() {
// Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
env::set_var("CARGO_BUILD_INCREMENTAL", "false");
if !is_ci_opt() {
// Enable the Cranelift verifier
env::set_var("CG_CLIF_ENABLE_VERIFIER", "1");
}
}
let mut args = env::args().skip(1);
let command = match args.next().as_deref() {
Some("prepare") => Command::Prepare,
Some("build") => Command::Build,
Some("test") => Command::Test,
Some("abi-cafe") => Command::AbiCafe,
Some("bench") => Command::Bench,
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
Some(command) => arg_error!("Unknown command {}", command),
None => {
usage();
process::exit(0);
}
};
let mut out_dir = PathBuf::from(".");
let mut download_dir = None;
let mut channel = "release";
let mut sysroot_kind = SysrootKind::Clif;
let mut use_unstable_features = true;
let mut frozen = false;
let mut skip_tests = vec![];
let mut use_backend = None;
while let Some(arg) = args.next().as_deref() {
match arg {
"--out-dir" => {
out_dir = PathBuf::from(args.next().unwrap_or_else(|| {
arg_error!("--out-dir requires argument");
}));
}
"--download-dir" => {
download_dir = Some(PathBuf::from(args.next().unwrap_or_else(|| {
arg_error!("--download-dir requires argument");
})));
}
"--debug" => channel = "debug",
"--sysroot" => {
sysroot_kind = match args.next().as_deref() {
Some("none") => SysrootKind::None,
Some("clif") => SysrootKind::Clif,
Some("llvm") => SysrootKind::Llvm,
Some(arg) => arg_error!("Unknown sysroot kind {}", arg),
None => arg_error!("--sysroot requires argument"),
}
}
"--no-unstable-features" => use_unstable_features = false,
"--frozen" => frozen = true,
"--skip-test" => {
// FIXME check that all passed in tests actually exist
skip_tests.push(args.next().unwrap_or_else(|| {
arg_error!("--skip-test requires argument");
}));
}
"--use-backend" => {
use_backend = Some(match args.next() {
Some(name) => name,
None => arg_error!("--use-backend requires argument"),
});
}
flag if flag.starts_with("-") => arg_error!("Unknown flag {}", flag),
arg => arg_error!("Unexpected argument {}", arg),
}
}
let current_dir = std::env::current_dir().unwrap();
out_dir = current_dir.join(out_dir);
if command == Command::Prepare {
prepare::prepare(&path::Dirs {
source_dir: current_dir.clone(),
download_dir: download_dir
.map(|dir| current_dir.join(dir))
.unwrap_or_else(|| out_dir.join("download")),
build_dir: PathBuf::from("dummy_do_not_use"),
dist_dir: PathBuf::from("dummy_do_not_use"),
frozen,
});
process::exit(0);
}
let rustup_toolchain_name = match (env::var("CARGO"), env::var("RUSTC"), env::var("RUSTDOC")) {
(Ok(_), Ok(_), Ok(_)) => None,
(Err(_), Err(_), Err(_)) => Some(rustc_info::get_toolchain_name()),
_ => {
eprintln!("All of CARGO, RUSTC and RUSTDOC need to be set or none must be set");
process::exit(1);
}
};
let bootstrap_host_compiler = {
let cargo = rustc_info::get_cargo_path();
let rustc = rustc_info::get_rustc_path();
let rustdoc = rustc_info::get_rustdoc_path();
let triple = std::env::var("HOST_TRIPLE")
.ok()
.or_else(|| config::get_value("host"))
.unwrap_or_else(|| rustc_info::get_host_triple(&rustc));
Compiler {
cargo,
rustc,
rustdoc,
rustflags: String::new(),
rustdocflags: String::new(),
triple,
runner: vec![],
}
};
let target_triple = std::env::var("TARGET_TRIPLE")
.ok()
.or_else(|| config::get_value("target"))
.unwrap_or_else(|| bootstrap_host_compiler.triple.clone());
let dirs = path::Dirs {
source_dir: current_dir.clone(),
download_dir: download_dir
.map(|dir| current_dir.join(dir))
.unwrap_or_else(|| out_dir.join("download")),
build_dir: out_dir.join("build"),
dist_dir: out_dir.join("dist"),
frozen,
};
path::RelPath::BUILD.ensure_exists(&dirs);
{
// Make sure we always explicitly specify the target dir
let target =
path::RelPath::BUILD.join("target_dir_should_be_set_explicitly").to_path(&dirs);
env::set_var("CARGO_TARGET_DIR", &target);
let _ = std::fs::remove_file(&target);
std::fs::File::create(target).unwrap();
}
env::set_var("RUSTC", "rustc_should_be_set_explicitly");
env::set_var("RUSTDOC", "rustdoc_should_be_set_explicitly");
let cg_clif_dylib = if let Some(name) = use_backend {
CodegenBackend::Builtin(name)
} else {
CodegenBackend::Local(build_backend::build_backend(
&dirs,
channel,
&bootstrap_host_compiler,
use_unstable_features,
))
};
match command {
Command::Prepare => {
// Handled above
}
Command::Test => {
tests::run_tests(
&dirs,
channel,
sysroot_kind,
use_unstable_features,
&skip_tests.iter().map(|test| &**test).collect::<Vec<_>>(),
&cg_clif_dylib,
&bootstrap_host_compiler,
rustup_toolchain_name.as_deref(),
target_triple.clone(),
);
}
Command::AbiCafe => {
if bootstrap_host_compiler.triple != target_triple {
eprintln!("Abi-cafe doesn't support cross-compilation");
process::exit(1);
}
abi_cafe::run(
channel,
sysroot_kind,
&dirs,
&cg_clif_dylib,
rustup_toolchain_name.as_deref(),
&bootstrap_host_compiler,
);
}
Command::Build => {
build_sysroot::build_sysroot(
&dirs,
channel,
sysroot_kind,
&cg_clif_dylib,
&bootstrap_host_compiler,
rustup_toolchain_name.as_deref(),
target_triple,
);
}
Command::Bench => {
build_sysroot::build_sysroot(
&dirs,
channel,
sysroot_kind,
&cg_clif_dylib,
&bootstrap_host_compiler,
rustup_toolchain_name.as_deref(),
target_triple,
);
bench::benchmark(&dirs, &bootstrap_host_compiler);
}
}
}

View File

@ -1,193 +0,0 @@
use std::env;
use std::path::PathBuf;
use std::process;
use self::utils::{is_ci, is_ci_opt, Compiler};
mod abi_cafe;
mod bench;
mod build_backend;
mod build_sysroot;
mod config;
mod path;
mod prepare;
mod rustc_info;
mod tests;
mod utils;
fn usage() {
eprintln!("{}", include_str!("usage.txt"));
}
macro_rules! arg_error {
($($err:tt)*) => {{
eprintln!($($err)*);
usage();
std::process::exit(1);
}};
}
#[derive(PartialEq, Debug)]
enum Command {
Prepare,
Build,
Test,
AbiCafe,
Bench,
}
#[derive(Copy, Clone, Debug)]
pub(crate) enum SysrootKind {
None,
Clif,
Llvm,
}
pub(crate) fn main() {
if env::var("RUST_BACKTRACE").is_err() {
env::set_var("RUST_BACKTRACE", "1");
}
env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
if is_ci() {
// Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
env::set_var("CARGO_BUILD_INCREMENTAL", "false");
if !is_ci_opt() {
// Enable the Cranelift verifier
env::set_var("CG_CLIF_ENABLE_VERIFIER", "1");
}
}
let mut args = env::args().skip(1);
let command = match args.next().as_deref() {
Some("prepare") => Command::Prepare,
Some("build") => Command::Build,
Some("test") => Command::Test,
Some("abi-cafe") => Command::AbiCafe,
Some("bench") => Command::Bench,
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
Some(command) => arg_error!("Unknown command {}", command),
None => {
usage();
process::exit(0);
}
};
let mut out_dir = PathBuf::from(".");
let mut channel = "release";
let mut sysroot_kind = SysrootKind::Clif;
let mut use_unstable_features = true;
while let Some(arg) = args.next().as_deref() {
match arg {
"--out-dir" => {
out_dir = PathBuf::from(args.next().unwrap_or_else(|| {
arg_error!("--out-dir requires argument");
}))
}
"--debug" => channel = "debug",
"--sysroot" => {
sysroot_kind = match args.next().as_deref() {
Some("none") => SysrootKind::None,
Some("clif") => SysrootKind::Clif,
Some("llvm") => SysrootKind::Llvm,
Some(arg) => arg_error!("Unknown sysroot kind {}", arg),
None => arg_error!("--sysroot requires argument"),
}
}
"--no-unstable-features" => use_unstable_features = false,
flag if flag.starts_with("-") => arg_error!("Unknown flag {}", flag),
arg => arg_error!("Unexpected argument {}", arg),
}
}
let bootstrap_host_compiler = Compiler::bootstrap_with_triple(
std::env::var("HOST_TRIPLE")
.ok()
.or_else(|| config::get_value("host"))
.unwrap_or_else(|| rustc_info::get_host_triple()),
);
let target_triple = std::env::var("TARGET_TRIPLE")
.ok()
.or_else(|| config::get_value("target"))
.unwrap_or_else(|| bootstrap_host_compiler.triple.clone());
// FIXME allow changing the location of these dirs using cli arguments
let current_dir = std::env::current_dir().unwrap();
out_dir = current_dir.join(out_dir);
let dirs = path::Dirs {
source_dir: current_dir.clone(),
download_dir: out_dir.join("download"),
build_dir: out_dir.join("build"),
dist_dir: out_dir.join("dist"),
};
path::RelPath::BUILD.ensure_exists(&dirs);
{
// Make sure we always explicitly specify the target dir
let target =
path::RelPath::BUILD.join("target_dir_should_be_set_explicitly").to_path(&dirs);
env::set_var("CARGO_TARGET_DIR", &target);
let _ = std::fs::remove_file(&target);
std::fs::File::create(target).unwrap();
}
if command == Command::Prepare {
prepare::prepare(&dirs);
process::exit(0);
}
env::set_var("RUSTC", "rustc_should_be_set_explicitly");
env::set_var("RUSTDOC", "rustdoc_should_be_set_explicitly");
let cg_clif_dylib = build_backend::build_backend(
&dirs,
channel,
&bootstrap_host_compiler,
use_unstable_features,
);
match command {
Command::Prepare => {
// Handled above
}
Command::Test => {
tests::run_tests(
&dirs,
channel,
sysroot_kind,
&cg_clif_dylib,
&bootstrap_host_compiler,
target_triple.clone(),
);
}
Command::AbiCafe => {
if bootstrap_host_compiler.triple != target_triple {
eprintln!("Abi-cafe doesn't support cross-compilation");
process::exit(1);
}
abi_cafe::run(channel, sysroot_kind, &dirs, &cg_clif_dylib, &bootstrap_host_compiler);
}
Command::Build => {
build_sysroot::build_sysroot(
&dirs,
channel,
sysroot_kind,
&cg_clif_dylib,
&bootstrap_host_compiler,
target_triple,
);
}
Command::Bench => {
build_sysroot::build_sysroot(
&dirs,
channel,
sysroot_kind,
&cg_clif_dylib,
&bootstrap_host_compiler,
target_triple,
);
bench::benchmark(&dirs, &bootstrap_host_compiler);
}
}
}

View File

@ -9,6 +9,7 @@ pub(crate) struct Dirs {
pub(crate) download_dir: PathBuf,
pub(crate) build_dir: PathBuf,
pub(crate) dist_dir: PathBuf,
pub(crate) frozen: bool,
}
#[doc(hidden)]

View File

@ -3,77 +3,60 @@ use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use super::build_sysroot::{BUILD_SYSROOT, ORIG_BUILD_SYSROOT, SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
use super::build_sysroot::STDLIB_SRC;
use super::path::{Dirs, RelPath};
use super::rustc_info::{get_default_sysroot, get_rustc_version};
use super::tests::LIBCORE_TESTS_SRC;
use super::utils::{copy_dir_recursively, git_command, retry_spawn_and_wait, spawn_and_wait};
use super::rustc_info::get_default_sysroot;
use super::utils::{
copy_dir_recursively, git_command, remove_dir_if_exists, retry_spawn_and_wait, spawn_and_wait,
};
pub(crate) fn prepare(dirs: &Dirs) {
RelPath::DOWNLOAD.ensure_fresh(dirs);
spawn_and_wait(super::build_backend::CG_CLIF.fetch("cargo", "rustc", dirs));
prepare_stdlib(dirs);
spawn_and_wait(super::build_sysroot::STANDARD_LIBRARY.fetch("cargo", "rustc", dirs));
prepare_coretests(dirs);
spawn_and_wait(super::tests::LIBCORE_TESTS.fetch("cargo", "rustc", dirs));
RelPath::DOWNLOAD.ensure_exists(dirs);
super::tests::RAND_REPO.fetch(dirs);
spawn_and_wait(super::tests::RAND.fetch("cargo", "rustc", dirs));
super::tests::REGEX_REPO.fetch(dirs);
spawn_and_wait(super::tests::REGEX.fetch("cargo", "rustc", dirs));
super::tests::PORTABLE_SIMD_REPO.fetch(dirs);
spawn_and_wait(super::tests::PORTABLE_SIMD.fetch("cargo", "rustc", dirs));
}
fn prepare_stdlib(dirs: &Dirs) {
let sysroot_src_orig = get_default_sysroot(Path::new("rustc")).join("lib/rustlib/src/rust");
pub(crate) fn prepare_stdlib(dirs: &Dirs, rustc: &Path) {
let sysroot_src_orig = get_default_sysroot(rustc).join("lib/rustlib/src/rust");
assert!(sysroot_src_orig.exists());
eprintln!("[COPY] stdlib src");
apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs));
// FIXME ensure builds error out or update the copy if any of the files copied here change
BUILD_SYSROOT.ensure_fresh(dirs);
copy_dir_recursively(&ORIG_BUILD_SYSROOT.to_path(dirs), &BUILD_SYSROOT.to_path(dirs));
std::fs::write(
STDLIB_SRC.to_path(dirs).join("Cargo.toml"),
r#"
[workspace]
members = ["./library/sysroot"]
fs::create_dir_all(SYSROOT_SRC.to_path(dirs).join("library")).unwrap();
copy_dir_recursively(
&sysroot_src_orig.join("library"),
&SYSROOT_SRC.to_path(dirs).join("library"),
);
[patch.crates-io]
rustc-std-workspace-core = { path = "./library/rustc-std-workspace-core" }
rustc-std-workspace-alloc = { path = "./library/rustc-std-workspace-alloc" }
rustc-std-workspace-std = { path = "./library/rustc-std-workspace-std" }
let rustc_version = get_rustc_version(Path::new("rustc"));
fs::write(SYSROOT_RUSTC_VERSION.to_path(dirs), &rustc_version).unwrap();
# Mandatory for correctly compiling compiler-builtins
[profile.dev.package.compiler_builtins]
debug-assertions = false
overflow-checks = false
codegen-units = 10000
eprintln!("[GIT] init");
init_git_repo(&SYSROOT_SRC.to_path(dirs));
[profile.release.package.compiler_builtins]
debug-assertions = false
overflow-checks = false
codegen-units = 10000
"#,
)
.unwrap();
apply_patches(dirs, "stdlib", &SYSROOT_SRC.to_path(dirs));
}
fn prepare_coretests(dirs: &Dirs) {
let sysroot_src_orig = get_default_sysroot(Path::new("rustc")).join("lib/rustlib/src/rust");
assert!(sysroot_src_orig.exists());
eprintln!("[COPY] coretests src");
fs::create_dir_all(LIBCORE_TESTS_SRC.to_path(dirs)).unwrap();
copy_dir_recursively(
&sysroot_src_orig.join("library/core/tests"),
&LIBCORE_TESTS_SRC.to_path(dirs),
);
eprintln!("[GIT] init");
init_git_repo(&LIBCORE_TESTS_SRC.to_path(dirs));
apply_patches(dirs, "coretests", &LIBCORE_TESTS_SRC.to_path(dirs));
let source_lockfile = RelPath::PATCHES.to_path(dirs).join("stdlib-lock.toml");
let target_lockfile = STDLIB_SRC.to_path(dirs).join("Cargo.lock");
fs::copy(source_lockfile, target_lockfile).unwrap();
}
pub(crate) struct GitRepo {
url: GitRepoUrl,
rev: &'static str,
content_hash: &'static str,
patch_name: &'static str,
}
@ -81,35 +64,107 @@ enum GitRepoUrl {
Github { user: &'static str, repo: &'static str },
}
// Note: This uses a hasher which is not cryptographically secure. This is fine as the hash is meant
// to protect against accidental modification and outdated downloads, not against manipulation.
fn hash_file(file: &std::path::Path) -> u64 {
let contents = std::fs::read(file).unwrap();
#[allow(deprecated)]
let mut hasher = std::hash::SipHasher::new();
std::hash::Hash::hash(&contents, &mut hasher);
std::hash::Hasher::finish(&hasher)
}
fn hash_dir(dir: &std::path::Path) -> u64 {
let mut sub_hashes = std::collections::BTreeMap::new();
for entry in std::fs::read_dir(dir).unwrap() {
let entry = entry.unwrap();
if entry.file_type().unwrap().is_dir() {
sub_hashes
.insert(entry.file_name().to_str().unwrap().to_owned(), hash_dir(&entry.path()));
} else {
sub_hashes
.insert(entry.file_name().to_str().unwrap().to_owned(), hash_file(&entry.path()));
}
}
#[allow(deprecated)]
let mut hasher = std::hash::SipHasher::new();
std::hash::Hash::hash(&sub_hashes, &mut hasher);
std::hash::Hasher::finish(&hasher)
}
impl GitRepo {
pub(crate) const fn github(
user: &'static str,
repo: &'static str,
rev: &'static str,
content_hash: &'static str,
patch_name: &'static str,
) -> GitRepo {
GitRepo { url: GitRepoUrl::Github { user, repo }, rev, patch_name }
GitRepo { url: GitRepoUrl::Github { user, repo }, rev, content_hash, patch_name }
}
fn download_dir(&self, dirs: &Dirs) -> PathBuf {
match self.url {
GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo).to_path(dirs),
}
}
pub(crate) const fn source_dir(&self) -> RelPath {
match self.url {
GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo),
GitRepoUrl::Github { user: _, repo } => RelPath::BUILD.join(repo),
}
}
pub(crate) fn fetch(&self, dirs: &Dirs) {
match self.url {
GitRepoUrl::Github { user, repo } => {
clone_repo_shallow_github(
dirs,
&self.source_dir().to_path(dirs),
user,
repo,
self.rev,
let download_dir = self.download_dir(dirs);
if download_dir.exists() {
let actual_hash = format!("{:016x}", hash_dir(&download_dir));
if actual_hash == self.content_hash {
println!("[FRESH] {}", download_dir.display());
return;
} else {
println!(
"Mismatched content hash for {download_dir}: {actual_hash} != {content_hash}. Downloading again.",
download_dir = download_dir.display(),
content_hash = self.content_hash,
);
}
}
apply_patches(dirs, self.patch_name, &self.source_dir().to_path(dirs));
match self.url {
GitRepoUrl::Github { user, repo } => {
clone_repo_shallow_github(dirs, &download_dir, user, repo, self.rev);
}
}
let source_lockfile =
RelPath::PATCHES.to_path(dirs).join(format!("{}-lock.toml", self.patch_name));
let target_lockfile = download_dir.join("Cargo.lock");
if source_lockfile.exists() {
fs::copy(source_lockfile, target_lockfile).unwrap();
} else {
assert!(target_lockfile.exists());
}
let actual_hash = format!("{:016x}", hash_dir(&download_dir));
if actual_hash != self.content_hash {
println!(
"Download of {download_dir} failed with mismatched content hash: {actual_hash} != {content_hash}",
download_dir = download_dir.display(),
content_hash = self.content_hash,
);
std::process::exit(1);
}
}
pub(crate) fn patch(&self, dirs: &Dirs) {
apply_patches(
dirs,
self.patch_name,
&self.download_dir(dirs),
&self.source_dir().to_path(dirs),
);
}
}
@ -126,6 +181,8 @@ fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
let mut checkout_cmd = git_command(download_dir, "checkout");
checkout_cmd.arg("-q").arg(rev);
spawn_and_wait(checkout_cmd);
std::fs::remove_dir_all(download_dir.join(".git")).unwrap();
}
fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo: &str, rev: &str) {
@ -173,8 +230,6 @@ fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo:
// Rename unpacked dir to the expected name
std::fs::rename(archive_dir, &download_dir).unwrap();
init_git_repo(&download_dir);
// Cleanup
std::fs::remove_file(archive_file).unwrap();
}
@ -213,7 +268,22 @@ fn get_patches(dirs: &Dirs, crate_name: &str) -> Vec<PathBuf> {
patches
}
fn apply_patches(dirs: &Dirs, crate_name: &str, target_dir: &Path) {
pub(crate) fn apply_patches(dirs: &Dirs, crate_name: &str, source_dir: &Path, target_dir: &Path) {
// FIXME avoid copy and patch if src, patches and target are unchanged
eprintln!("[COPY] {crate_name} source");
remove_dir_if_exists(target_dir);
fs::create_dir_all(target_dir).unwrap();
if crate_name == "stdlib" {
fs::create_dir(target_dir.join("library")).unwrap();
copy_dir_recursively(&source_dir.join("library"), &target_dir.join("library"));
} else {
copy_dir_recursively(source_dir, target_dir);
}
init_git_repo(target_dir);
if crate_name == "<none>" {
return;
}

View File

@ -1,15 +1,9 @@
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
pub(crate) fn get_rustc_version(rustc: &Path) -> String {
pub(crate) fn get_host_triple(rustc: &Path) -> String {
let version_info =
Command::new(rustc).stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout;
String::from_utf8(version_info).unwrap()
}
pub(crate) fn get_host_triple() -> String {
let version_info =
Command::new("rustc").stderr(Stdio::inherit()).args(&["-vV"]).output().unwrap().stdout;
Command::new(rustc).stderr(Stdio::inherit()).args(&["-vV"]).output().unwrap().stdout;
String::from_utf8(version_info)
.unwrap()
.lines()
@ -34,6 +28,9 @@ pub(crate) fn get_toolchain_name() -> String {
}
pub(crate) fn get_cargo_path() -> PathBuf {
if let Ok(cargo) = std::env::var("CARGO") {
return PathBuf::from(cargo);
}
let cargo_path = Command::new("rustup")
.stderr(Stdio::inherit())
.args(&["which", "cargo"])
@ -44,6 +41,9 @@ pub(crate) fn get_cargo_path() -> PathBuf {
}
pub(crate) fn get_rustc_path() -> PathBuf {
if let Ok(rustc) = std::env::var("RUSTC") {
return PathBuf::from(rustc);
}
let rustc_path = Command::new("rustup")
.stderr(Stdio::inherit())
.args(&["which", "rustc"])
@ -54,6 +54,9 @@ pub(crate) fn get_rustc_path() -> PathBuf {
}
pub(crate) fn get_rustdoc_path() -> PathBuf {
if let Ok(rustdoc) = std::env::var("RUSTDOC") {
return PathBuf::from(rustdoc);
}
let rustc_path = Command::new("rustup")
.stderr(Stdio::inherit())
.args(&["which", "rustdoc"])
@ -73,8 +76,9 @@ pub(crate) fn get_default_sysroot(rustc: &Path) -> PathBuf {
Path::new(String::from_utf8(default_sysroot).unwrap().trim()).to_owned()
}
pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String {
let file_name = Command::new("rustc")
// FIXME call once for each target and pass result around in struct
pub(crate) fn get_file_name(rustc: &Path, crate_name: &str, crate_type: &str) -> String {
let file_name = Command::new(rustc)
.stderr(Stdio::inherit())
.args(&[
"--crate-name",

View File

@ -1,13 +1,14 @@
use super::build_sysroot;
use super::config;
use super::path::{Dirs, RelPath};
use super::prepare::GitRepo;
use super::prepare::{apply_patches, GitRepo};
use super::rustc_info::get_default_sysroot;
use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler};
use super::SysrootKind;
use super::{CodegenBackend, SysrootKind};
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
@ -18,7 +19,7 @@ struct TestCase {
}
enum TestCaseCmd {
Custom { func: &'static dyn Fn(&TestRunner) },
Custom { func: &'static dyn Fn(&TestRunner<'_>) },
BuildLib { source: &'static str, crate_types: &'static str },
BuildBinAndRun { source: &'static str, args: &'static [&'static str] },
JitBin { source: &'static str, args: &'static str },
@ -26,7 +27,7 @@ enum TestCaseCmd {
impl TestCase {
// FIXME reduce usage of custom test case commands
const fn custom(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
const fn custom(config: &'static str, func: &'static dyn Fn(&TestRunner<'_>)) -> Self {
Self { config, cmd: TestCaseCmd::Custom { func } }
}
@ -95,32 +96,45 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
// FIXME(rust-random/rand#1293): Newer rand versions fail to test on Windows. Update once this is
// fixed.
pub(crate) static RAND_REPO: GitRepo =
GitRepo::github("rust-random", "rand", "50b9a447410860af8d6db9a208c3576886955874", "rand");
pub(crate) static RAND_REPO: GitRepo = GitRepo::github(
"rust-random",
"rand",
"50b9a447410860af8d6db9a208c3576886955874",
"446203b96054891e",
"rand",
);
pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand_target");
pub(crate) static REGEX_REPO: GitRepo =
GitRepo::github("rust-lang", "regex", "32fed9429eafba0ae92a64b01796a0c5a75b88c8", "regex");
pub(crate) static REGEX_REPO: GitRepo = GitRepo::github(
"rust-lang",
"regex",
"32fed9429eafba0ae92a64b01796a0c5a75b88c8",
"fcc4df7c5b902633",
"regex",
);
pub(crate) static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex");
pub(crate) static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex_target");
pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
"rust-lang",
"portable-simd",
"ad8afa8c81273b3b49acbea38cd3bcf17a34cf2b",
"800548f8000e31bd",
"portable-simd",
);
pub(crate) static PORTABLE_SIMD: CargoProject =
CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable_simd");
CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable-simd_target");
pub(crate) static LIBCORE_TESTS_SRC: RelPath = RelPath::DOWNLOAD.join("coretests_src");
static LIBCORE_TESTS_SRC: RelPath = RelPath::BUILD.join("coretests");
pub(crate) static LIBCORE_TESTS: CargoProject = CargoProject::new(&LIBCORE_TESTS_SRC, "core_tests");
static LIBCORE_TESTS: CargoProject = CargoProject::new(&LIBCORE_TESTS_SRC, "coretests_target");
const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
TestCase::custom("test.rust-random/rand", &|runner| {
RAND_REPO.patch(&runner.dirs);
RAND.clean(&runner.dirs);
if runner.is_native {
@ -135,6 +149,17 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
}
}),
TestCase::custom("test.libcore", &|runner| {
apply_patches(
&runner.dirs,
"coretests",
&runner.stdlib_source.join("library/core/tests"),
&LIBCORE_TESTS_SRC.to_path(&runner.dirs),
);
let source_lockfile = RelPath::PATCHES.to_path(&runner.dirs).join("coretests-lock.toml");
let target_lockfile = LIBCORE_TESTS_SRC.to_path(&runner.dirs).join("Cargo.lock");
fs::copy(source_lockfile, target_lockfile).unwrap();
LIBCORE_TESTS.clean(&runner.dirs);
if runner.is_native {
@ -149,6 +174,8 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
}
}),
TestCase::custom("test.regex-shootout-regex-dna", &|runner| {
REGEX_REPO.patch(&runner.dirs);
REGEX.clean(&runner.dirs);
let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
@ -181,6 +208,8 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
}
}),
TestCase::custom("test.regex", &|runner| {
REGEX_REPO.patch(&runner.dirs);
REGEX.clean(&runner.dirs);
if runner.is_native {
@ -197,6 +226,8 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
}
}),
TestCase::custom("test.portable-simd", &|runner| {
PORTABLE_SIMD_REPO.patch(&runner.dirs);
PORTABLE_SIMD.clean(&runner.dirs);
let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs);
@ -215,24 +246,35 @@ pub(crate) fn run_tests(
dirs: &Dirs,
channel: &str,
sysroot_kind: SysrootKind,
cg_clif_dylib: &Path,
use_unstable_features: bool,
skip_tests: &[&str],
cg_clif_dylib: &CodegenBackend,
bootstrap_host_compiler: &Compiler,
rustup_toolchain_name: Option<&str>,
target_triple: String,
) {
if config::get_bool("testsuite.no_sysroot") {
let stdlib_source =
get_default_sysroot(&bootstrap_host_compiler.rustc).join("lib/rustlib/src/rust");
assert!(stdlib_source.exists());
if config::get_bool("testsuite.no_sysroot") && !skip_tests.contains(&"testsuite.no_sysroot") {
let target_compiler = build_sysroot::build_sysroot(
dirs,
channel,
SysrootKind::None,
cg_clif_dylib,
bootstrap_host_compiler,
rustup_toolchain_name,
target_triple.clone(),
);
let runner = TestRunner::new(
dirs.clone(),
target_compiler,
use_unstable_features,
skip_tests,
bootstrap_host_compiler.triple == target_triple,
stdlib_source.clone(),
);
BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
@ -241,23 +283,32 @@ pub(crate) fn run_tests(
eprintln!("[SKIP] no_sysroot tests");
}
let run_base_sysroot = config::get_bool("testsuite.base_sysroot");
let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot");
let run_base_sysroot = config::get_bool("testsuite.base_sysroot")
&& !skip_tests.contains(&"testsuite.base_sysroot");
let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot")
&& !skip_tests.contains(&"testsuite.extended_sysroot");
if run_base_sysroot || run_extended_sysroot {
let target_compiler = build_sysroot::build_sysroot(
let mut target_compiler = build_sysroot::build_sysroot(
dirs,
channel,
sysroot_kind,
cg_clif_dylib,
bootstrap_host_compiler,
rustup_toolchain_name,
target_triple.clone(),
);
// Rust's build system denies a couple of lints that trigger on several of the test
// projects. Changing the code to fix them is not worth it, so just silence all lints.
target_compiler.rustflags += " --cap-lints=allow";
let runner = TestRunner::new(
dirs.clone(),
target_compiler,
use_unstable_features,
skip_tests,
bootstrap_host_compiler.triple == target_triple,
stdlib_source,
);
if run_base_sysroot {
@ -274,15 +325,25 @@ pub(crate) fn run_tests(
}
}
struct TestRunner {
struct TestRunner<'a> {
is_native: bool,
jit_supported: bool,
use_unstable_features: bool,
skip_tests: &'a [&'a str],
dirs: Dirs,
target_compiler: Compiler,
stdlib_source: PathBuf,
}
impl TestRunner {
fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self {
impl<'a> TestRunner<'a> {
fn new(
dirs: Dirs,
mut target_compiler: Compiler,
use_unstable_features: bool,
skip_tests: &'a [&'a str],
is_native: bool,
stdlib_source: PathBuf,
) -> Self {
if let Ok(rustflags) = env::var("RUSTFLAGS") {
target_compiler.rustflags.push(' ');
target_compiler.rustflags.push_str(&rustflags);
@ -297,11 +358,20 @@ impl TestRunner {
target_compiler.rustflags.push_str(" -Clink-arg=-undefined -Clink-arg=dynamic_lookup");
}
let jit_supported = is_native
let jit_supported = use_unstable_features
&& is_native
&& target_compiler.triple.contains("x86_64")
&& !target_compiler.triple.contains("windows");
Self { is_native, jit_supported, dirs, target_compiler }
Self {
is_native,
jit_supported,
use_unstable_features,
skip_tests,
dirs,
target_compiler,
stdlib_source,
}
}
fn run_testsuite(&self, tests: &[TestCase]) {
@ -310,7 +380,10 @@ impl TestRunner {
let tag = tag.to_uppercase();
let is_jit_test = tag == "JIT";
if !config::get_bool(config) || (is_jit_test && !self.jit_supported) {
if !config::get_bool(config)
|| (is_jit_test && !self.jit_supported)
|| self.skip_tests.contains(&config)
{
eprintln!("[{tag}] {testname} (skipped)");
continue;
} else {
@ -320,10 +393,24 @@ impl TestRunner {
match *cmd {
TestCaseCmd::Custom { func } => func(self),
TestCaseCmd::BuildLib { source, crate_types } => {
self.run_rustc([source, "--crate-type", crate_types]);
if self.use_unstable_features {
self.run_rustc([source, "--crate-type", crate_types]);
} else {
self.run_rustc([
source,
"--crate-type",
crate_types,
"--cfg",
"no_unstable_features",
]);
}
}
TestCaseCmd::BuildBinAndRun { source, args } => {
self.run_rustc([source]);
if self.use_unstable_features {
self.run_rustc([source]);
} else {
self.run_rustc([source, "--cfg", "no_unstable_features"]);
}
self.run_out_command(
source.split('/').last().unwrap().split('.').next().unwrap(),
args,

View File

@ -1,11 +1,11 @@
The build system of cg_clif.
USAGE:
./y.rs prepare [--out-dir DIR]
./y.rs build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
./y.rs test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
./y.rs abi-cafe [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
./y.rs bench [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
./y.sh prepare [--out-dir DIR] [--download-dir DIR]
./y.sh build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen]
./y.sh test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] [--skip-test TESTNAME]
./y.sh abi-cafe [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen]
./y.sh bench [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen]
OPTIONS:
--debug
@ -22,14 +22,28 @@ OPTIONS:
Specify the directory in which the download, build and dist directories are stored.
By default this is the working directory.
--download-dir DIR
Specify the directory in which the download directory is stored. Overrides --out-dir.
--no-unstable-features
Some features are not yet ready for production usage. This option will disable these
features. This includes the JIT mode and inline assembly support.
--frozen
Require Cargo.lock and cache are up to date
--skip-test TESTNAME
Skip testing the TESTNAME test. The test name format is the same as config.txt.
--use-backend NAME
Use the existing Cranelift (or other) backend of the rustc with which we built.
Warning: This is meant for use in rust's CI only!
REQUIREMENTS:
* Rustup: The build system has a hard coded dependency on rustup to install the right nightly
version and make sure it is used where necessary.
* Git: `./y.rs prepare` uses git for applying patches and on Windows for downloading test repos.
* Curl and tar (non-Windows only): Used by `./y.rs prepare` to download a single commit for
* Rustup: By default rustup is used to install the right nightly version. If you don't want to
use rustup, you can manually install the nightly version indicated by rust-toolchain.toml and
point the CARGO, RUSTC and RUSTDOC env vars to the right executables.
* Git: `./y.sh prepare` uses git for applying patches and on Windows for downloading test repos.
* Curl and tar (non-Windows only): Used by `./y.sh prepare` to download a single commit for
repos. Git will be used to clone the whole repo when using Windows.
* [Hyperfine](https://github.com/sharkdp/hyperfine/): Used for benchmarking with `./y.rs bench`.
* [Hyperfine](https://github.com/sharkdp/hyperfine/): Used for benchmarking with `./y.sh bench`.

View File

@ -5,7 +5,6 @@ use std::path::{Path, PathBuf};
use std::process::{self, Command, Stdio};
use super::path::{Dirs, RelPath};
use super::rustc_info::{get_cargo_path, get_rustc_path, get_rustdoc_path};
#[derive(Clone, Debug)]
pub(crate) struct Compiler {
@ -19,18 +18,6 @@ pub(crate) struct Compiler {
}
impl Compiler {
pub(crate) fn bootstrap_with_triple(triple: String) -> Compiler {
Compiler {
cargo: get_cargo_path(),
rustc: get_rustc_path(),
rustdoc: get_rustdoc_path(),
rustflags: String::new(),
rustdocflags: String::new(),
triple,
runner: vec![],
}
}
pub(crate) fn set_cross_linker_and_runner(&mut self) {
match self.triple.as_str() {
"aarch64-unknown-linux-gnu" => {
@ -95,7 +82,11 @@ impl CargoProject {
.arg(self.manifest_path(dirs))
.arg("--target-dir")
.arg(self.target_dir(dirs))
.arg("--frozen");
.arg("--locked");
if dirs.frozen {
cmd.arg("--frozen");
}
cmd
}
@ -120,23 +111,6 @@ impl CargoProject {
cmd
}
#[must_use]
pub(crate) fn fetch(
&self,
cargo: impl AsRef<Path>,
rustc: impl AsRef<Path>,
dirs: &Dirs,
) -> Command {
let mut cmd = Command::new(cargo.as_ref());
cmd.env("RUSTC", rustc.as_ref())
.arg("fetch")
.arg("--manifest-path")
.arg(self.manifest_path(dirs));
cmd
}
pub(crate) fn clean(&self, dirs: &Dirs) {
let _ = fs::remove_dir_all(self.target_dir(dirs));
}
@ -162,8 +136,7 @@ pub(crate) fn hyperfine_command(
warmup: u64,
runs: u64,
prepare: Option<&str>,
a: &str,
b: &str,
cmds: &[&str],
) -> Command {
let mut bench = Command::new("hyperfine");
@ -179,7 +152,7 @@ pub(crate) fn hyperfine_command(
bench.arg("--prepare").arg(prepare);
}
bench.arg(a).arg(b);
bench.args(cmds);
bench
}
@ -285,3 +258,13 @@ pub(crate) fn is_ci() -> bool {
pub(crate) fn is_ci_opt() -> bool {
env::var("CI_OPT").is_ok()
}
pub(crate) fn maybe_incremental(cmd: &mut Command) {
if is_ci() || std::env::var("CARGO_BUILD_INCREMENTAL").map_or(false, |val| val == "false") {
// Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
cmd.env("CARGO_BUILD_INCREMENTAL", "false");
} else {
// Force incr comp even in release mode unless in CI or incremental builds are explicitly disabled
cmd.env("CARGO_BUILD_INCREMENTAL", "true");
}
}

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -e
rm -rf target/ download/ build/ dist/ y.bin y.bin.dSYM y.exe y.pdb
rm -rf target/ build_system/target download/ build/ dist/ y.bin y.bin.dSYM y.exe y.pdb
# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
# FIXME remove at some point in the future

View File

@ -2,7 +2,7 @@
rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects.
Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`y.rs prepare` and `y.rs build` or `test.sh`).
Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`y.sh prepare` and `y.sh build` or `test.sh`).
## Cargo

View File

@ -1,4 +1,4 @@
#![feature(start, core_intrinsics, alloc_error_handler)]
#![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
#![no_std]
extern crate alloc;
@ -27,6 +27,11 @@ fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
core::intrinsics::abort();
}
#[lang = "eh_personality"]
fn eh_personality() -> ! {
loop {}
}
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
let world: Box<&str> = Box::new("Hello World!\0");

View File

@ -502,6 +502,9 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
drop_in_place(to_drop);
}
#[lang = "unpin"]
pub auto trait Unpin {}
#[lang = "deref"]
pub trait Deref {
type Target: ?Sized;
@ -526,7 +529,7 @@ impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsiz
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
#[lang = "owned_box"]
pub struct Box<T: ?Sized>(Unique<T>, ());
pub struct Box<T: ?Sized, A = ()>(Unique<T>, A);
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
@ -541,9 +544,10 @@ impl<T> Box<T> {
}
}
impl<T: ?Sized> Drop for Box<T> {
impl<T: ?Sized, A> Drop for Box<T, A> {
fn drop(&mut self) {
// drop is currently performed by compiler.
// inner value is dropped by compiler
libc::free(self.0.pointer.0 as *mut u8);
}
}
@ -560,11 +564,6 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
libc::malloc(size)
}
#[lang = "box_free"]
unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, _alloc: ()) {
libc::free(ptr.pointer.0 as *mut u8);
}
#[lang = "drop"]
pub trait Drop {
fn drop(&mut self);

Some files were not shown because too many files have changed in this diff Show More