commit
e82a604a88
1013 changed files with 13050 additions and 8441 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -430,7 +430,7 @@ jobs:
|
|||
os: windows-latest-xl
|
||||
- name: dist-x86_64-msvc
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler --set rust.lto=thin"
|
||||
SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
os: windows-latest-xl
|
||||
|
|
|
|||
|
|
@ -809,9 +809,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.84"
|
||||
version = "0.1.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "989b2c1ca6e90ad06fdc69d1d1862fa28d27a977be6d92ae2fa762cf61fe0b10"
|
||||
checksum = "13e81c6cd7ab79f51a0c927d22858d61ad12bd0b3865f0b13ece02a4486aeabb"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
@ -4627,9 +4627,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.3"
|
||||
version = "0.36.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b1fbb4dfc4eb1d390c02df47760bb19a84bb80b301ecc947ab5406394d8223e"
|
||||
checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
|
|
|
|||
91
RELEASES.md
91
RELEASES.md
|
|
@ -1,3 +1,94 @@
|
|||
Version 1.66.0 (2022-12-15)
|
||||
==========================
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Permit specifying explicit discriminants on all `repr(Int)` enums](https://github.com/rust-lang/rust/pull/95710/)
|
||||
```rust
|
||||
#[repr(u8)]
|
||||
enum Foo {
|
||||
A(u8) = 0,
|
||||
B(i8) = 1,
|
||||
C(bool) = 42,
|
||||
}
|
||||
```
|
||||
- [Allow transmutes between the same type differing only in lifetimes](https://github.com/rust-lang/rust/pull/101520/)
|
||||
- [Change constant evaluation errors from a deny-by-default lint to a hard error](https://github.com/rust-lang/rust/pull/102091/)
|
||||
- [Trigger `must_use` on `impl Trait` for supertraits](https://github.com/rust-lang/rust/pull/102287/)
|
||||
This makes `impl ExactSizeIterator` respect the existing `#[must_use]` annotation on `Iterator`.
|
||||
- [Allow `..=X` in patterns](https://github.com/rust-lang/rust/pull/102275/)
|
||||
- [Uplift `clippy::for_loops_over_fallibles` lint into rustc](https://github.com/rust-lang/rust/pull/99696/)
|
||||
- [Stabilize `sym` operands in inline assembly](https://github.com/rust-lang/rust/pull/103168/)
|
||||
- [Update to Unicode 15](https://github.com/rust-lang/rust/pull/101912/)
|
||||
- [Opaque types no longer imply lifetime bounds](https://github.com/rust-lang/rust/pull/95474/)
|
||||
This is a soundness fix which may break code that was erroneously relying on this behavior.
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Add armv5te-none-eabi and thumbv5te-none-eabi tier 3 targets](https://github.com/rust-lang/rust/pull/101329/)
|
||||
- Refer to Rust's [platform support page][platform-support-doc] for more
|
||||
information on Rust's tiered platform support.
|
||||
- [Add support for linking against macOS universal libraries](https://github.com/rust-lang/rust/pull/98736)
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Fix `#[derive(Default)]` on a generic `#[default]` enum adding unnecessary `Default` bounds](https://github.com/rust-lang/rust/pull/101040/)
|
||||
- [Update to Unicode 15](https://github.com/rust-lang/rust/pull/101821/)
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`proc_macro::Span::source_text`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.source_text)
|
||||
- [`uX::{checked_add_signed, overflowing_add_signed, saturating_add_signed, wrapping_add_signed}`](https://doc.rust-lang.org/stable/std/primitive.u8.html#method.checked_add_signed)
|
||||
- [`iX::{checked_add_unsigned, overflowing_add_unsigned, saturating_add_unsigned, wrapping_add_unsigned}`](https://doc.rust-lang.org/stable/std/primitive.i8.html#method.checked_add_unsigned)
|
||||
- [`iX::{checked_sub_unsigned, overflowing_sub_unsigned, saturating_sub_unsigned, wrapping_sub_unsigned}`](https://doc.rust-lang.org/stable/std/primitive.i8.html#method.checked_sub_unsigned)
|
||||
- [`BTreeSet::{first, last, pop_first, pop_last}`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html#method.first)
|
||||
- [`BTreeMap::{first_key_value, last_key_value, first_entry, last_entry, pop_first, pop_last}`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html#method.first_key_value)
|
||||
- [Add `AsFd` implementations for stdio lock types on WASI.](https://github.com/rust-lang/rust/pull/101768/)
|
||||
- [`impl TryFrom<Vec<T>> for Box<[T; N]>`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#impl-TryFrom%3CVec%3CT%2C%20Global%3E%3E-for-Box%3C%5BT%3B%20N%5D%2C%20Global%3E)
|
||||
- [`core::hint::black_box`](https://doc.rust-lang.org/stable/std/hint/fn.black_box.html)
|
||||
- [`Duration::try_from_secs_{f32,f64}`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.try_from_secs_f32)
|
||||
- [`Option::unzip`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unzip)
|
||||
- [`std::os::fd`](https://doc.rust-lang.org/stable/std/os/fd/index.html)
|
||||
|
||||
|
||||
Rustdoc
|
||||
-------
|
||||
|
||||
- [Add Rustdoc warning for invalid HTML tags in the documentation](https://github.com/rust-lang/rust/pull/101720/)
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
- [Added `cargo remove` to remove dependencies from Cargo.toml](https://doc.rust-lang.org/nightly/cargo/commands/cargo-remove.html)
|
||||
- [`cargo publish` now waits for the new version to be downloadable before exiting](https://github.com/rust-lang/cargo/pull/11062)
|
||||
|
||||
See [detailed release notes](https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-166-2022-12-15) for more.
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
|
||||
- [Only apply `ProceduralMasquerade` hack to older versions of `rental`](https://github.com/rust-lang/rust/pull/94063/)
|
||||
- [Don't export `__heap_base` and `__data_end` on wasm32-wasi.](https://github.com/rust-lang/rust/pull/102385/)
|
||||
- [Don't export `__wasm_init_memory` on WebAssembly.](https://github.com/rust-lang/rust/pull/102426/)
|
||||
- [Only export `__tls_*` on wasm32-unknown-unknown.](https://github.com/rust-lang/rust/pull/102440/)
|
||||
- [Don't link to `libresolv` in libstd on Darwin](https://github.com/rust-lang/rust/pull/102766/)
|
||||
- [Update libstd's libc to 0.2.135 (to make `libstd` no longer pull in `libiconv.dylib` on Darwin)](https://github.com/rust-lang/rust/pull/103277/)
|
||||
- [Opaque types no longer imply lifetime bounds](https://github.com/rust-lang/rust/pull/95474/)
|
||||
This is a soundness fix which may break code that was erroneously relying on this behavior.
|
||||
- [Make `order_dependent_trait_objects` show up in future-breakage reports](https://github.com/rust-lang/rust/pull/102635/)
|
||||
- [Change std::process::Command spawning to default to inheriting the parent's signal mask](https://github.com/rust-lang/rust/pull/101077/)
|
||||
|
||||
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.
|
||||
|
||||
- [Enable BOLT for LLVM compilation](https://github.com/rust-lang/rust/pull/94381/)
|
||||
- [Enable LTO for rustc_driver.so](https://github.com/rust-lang/rust/pull/101403/)
|
||||
|
||||
Version 1.65.0 (2022-11-03)
|
||||
==========================
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#![cfg_attr(feature = "nightly", feature(step_trait, rustc_attrs, min_specialization))]
|
||||
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::fmt;
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::iter::Step;
|
||||
|
|
@ -803,12 +802,9 @@ impl Integer {
|
|||
pub fn for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer> {
|
||||
let dl = cx.data_layout();
|
||||
|
||||
for candidate in [I8, I16, I32, I64, I128] {
|
||||
if wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes() {
|
||||
return Some(candidate);
|
||||
}
|
||||
}
|
||||
None
|
||||
[I8, I16, I32, I64, I128].into_iter().find(|&candidate| {
|
||||
wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes()
|
||||
})
|
||||
}
|
||||
|
||||
/// Find the largest integer with the given alignment or less.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use crate::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO};
|
|||
use crate::{Float, FloatConvert, ParseError, Round, Status, StatusAnd};
|
||||
|
||||
use core::cmp::{self, Ordering};
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt::{self, Write};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use smallvec::SmallVec;
|
|||
use std::alloc::Layout;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cmp;
|
||||
use std::marker::{PhantomData, Send};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use std::ptr::{self, NonNull};
|
||||
use std::slice;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
|||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
|
@ -1735,8 +1734,10 @@ pub enum StrStyle {
|
|||
/// A literal in a meta item.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct MetaItemLit {
|
||||
/// The original literal token as written in source code.
|
||||
pub token_lit: token::Lit,
|
||||
/// The original literal as written in the source code.
|
||||
pub symbol: Symbol,
|
||||
/// The original suffix as written in the source code.
|
||||
pub suffix: Option<Symbol>,
|
||||
/// The "semantic" representation of the literal lowered from the original tokens.
|
||||
/// Strings are unescaped, hexadecimal forms are eliminated, etc.
|
||||
pub kind: LitKind,
|
||||
|
|
@ -1746,13 +1747,14 @@ pub struct MetaItemLit {
|
|||
/// Similar to `MetaItemLit`, but restricted to string literals.
|
||||
#[derive(Clone, Copy, Encodable, Decodable, Debug)]
|
||||
pub struct StrLit {
|
||||
/// The original literal token as written in source code.
|
||||
pub style: StrStyle,
|
||||
/// The original literal as written in source code.
|
||||
pub symbol: Symbol,
|
||||
/// The original suffix as written in source code.
|
||||
pub suffix: Option<Symbol>,
|
||||
pub span: Span,
|
||||
/// The unescaped "semantic" representation of the literal lowered from the original token.
|
||||
/// The semantic (unescaped) representation of the literal.
|
||||
pub symbol_unescaped: Symbol,
|
||||
pub style: StrStyle,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl StrLit {
|
||||
|
|
@ -1798,8 +1800,9 @@ pub enum LitKind {
|
|||
/// A string literal (`"foo"`). The symbol is unescaped, and so may differ
|
||||
/// from the original token's symbol.
|
||||
Str(Symbol, StrStyle),
|
||||
/// A byte string (`b"foo"`).
|
||||
ByteStr(Lrc<[u8]>),
|
||||
/// A byte string (`b"foo"`). Not stored as a symbol because it might be
|
||||
/// non-utf8, and symbols only allow utf8 strings.
|
||||
ByteStr(Lrc<[u8]>, StrStyle),
|
||||
/// A byte char (`b'f'`).
|
||||
Byte(u8),
|
||||
/// A character literal (`'a'`).
|
||||
|
|
@ -1824,7 +1827,7 @@ impl LitKind {
|
|||
|
||||
/// Returns `true` if this literal is byte literal string.
|
||||
pub fn is_bytestr(&self) -> bool {
|
||||
matches!(self, LitKind::ByteStr(_))
|
||||
matches!(self, LitKind::ByteStr(..))
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a numeric literal.
|
||||
|
|
@ -2463,7 +2466,7 @@ pub enum ModKind {
|
|||
Unloaded,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
|
||||
pub struct ModSpans {
|
||||
/// `inner_span` covers the body of the module; for a file module, its the whole file.
|
||||
/// For an inline module, its the span inside the `{ ... }`, not including the curly braces.
|
||||
|
|
@ -2471,12 +2474,6 @@ pub struct ModSpans {
|
|||
pub inject_use_span: Span,
|
||||
}
|
||||
|
||||
impl Default for ModSpans {
|
||||
fn default() -> ModSpans {
|
||||
ModSpans { inner_span: Default::default(), inject_use_span: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Foreign module declaration.
|
||||
///
|
||||
/// E.g., `extern { .. }` or `extern "C" { .. }`.
|
||||
|
|
@ -3101,7 +3098,7 @@ mod size_asserts {
|
|||
static_assert_size!(ItemKind, 112);
|
||||
static_assert_size!(LitKind, 24);
|
||||
static_assert_size!(Local, 72);
|
||||
static_assert_size!(MetaItemLit, 48);
|
||||
static_assert_size!(MetaItemLit, 40);
|
||||
static_assert_size!(Param, 40);
|
||||
static_assert_size!(Pat, 88);
|
||||
static_assert_size!(Path, 24);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
//! Functions dealing with attributes and meta items.
|
||||
|
||||
use crate::ast;
|
||||
use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute};
|
||||
use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit};
|
||||
use crate::ast::{MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem, NormalAttr};
|
||||
use crate::ast::{Path, PathSegment, StrStyle, DUMMY_NODE_ID};
|
||||
use crate::ast::{Path, PathSegment, DUMMY_NODE_ID};
|
||||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter, Token};
|
||||
use crate::tokenstream::{DelimSpan, Spacing, TokenTree};
|
||||
use crate::tokenstream::{LazyAttrTokenStream, TokenStream};
|
||||
use crate::util::comments;
|
||||
use crate::util::literal::escape_string_symbol;
|
||||
use rustc_data_structures::sync::WorkerLocal;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
|
|
@ -321,18 +321,6 @@ impl Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
/* Constructors */
|
||||
|
||||
pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> MetaItem {
|
||||
mk_name_value_item(ident, LitKind::Str(str, ast::StrStyle::Cooked), str_span)
|
||||
}
|
||||
|
||||
pub fn mk_name_value_item(ident: Ident, kind: LitKind, lit_span: Span) -> MetaItem {
|
||||
let lit = MetaItemLit { token_lit: kind.to_token_lit(), kind, span: lit_span };
|
||||
let span = ident.span.to(lit_span);
|
||||
MetaItem { path: Path::from_ident(ident), kind: MetaItemKind::NameValue(lit), span }
|
||||
}
|
||||
|
||||
pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
@ -408,7 +396,7 @@ pub fn mk_attr_name_value_str(
|
|||
val: Symbol,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
let lit = LitKind::Str(val, StrStyle::Cooked).to_token_lit();
|
||||
let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
|
||||
let expr = P(Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ExprKind::Lit(lit),
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
//! Moreover, a switch to, e.g., `P<'a, T>` would be easy and mostly automated.
|
||||
|
||||
use std::fmt::{self, Debug, Display};
|
||||
use std::iter::FromIterator;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::{slice, vec};
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ impl Lit {
|
|||
if let NtExpr(expr) | NtLiteral(expr) = &**nt
|
||||
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
|
||||
{
|
||||
Some(token_lit.clone())
|
||||
Some(token_lit)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ impl TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
impl iter::FromIterator<TokenTree> for TokenStream {
|
||||
impl FromIterator<TokenTree> for TokenStream {
|
||||
fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
|
||||
TokenStream::new(iter.into_iter().collect::<Vec<TokenTree>>())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,31 @@
|
|||
//! Code related to parsing literals.
|
||||
|
||||
use crate::ast::{self, LitKind, MetaItemLit};
|
||||
use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
|
||||
use crate::token::{self, Token};
|
||||
use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use std::ascii;
|
||||
use std::{ascii, fmt, str};
|
||||
|
||||
// Escapes a string, represented as a symbol. Reuses the original symbol,
|
||||
// avoiding interning, if no changes are required.
|
||||
pub fn escape_string_symbol(symbol: Symbol) -> Symbol {
|
||||
let s = symbol.as_str();
|
||||
let escaped = s.escape_default().to_string();
|
||||
if s == escaped { symbol } else { Symbol::intern(&escaped) }
|
||||
}
|
||||
|
||||
// Escapes a char.
|
||||
pub fn escape_char_symbol(ch: char) -> Symbol {
|
||||
let s: String = ch.escape_default().map(Into::<char>::into).collect();
|
||||
Symbol::intern(&s)
|
||||
}
|
||||
|
||||
// Escapes a byte string.
|
||||
pub fn escape_byte_str_symbol(bytes: &[u8]) -> Symbol {
|
||||
let s = bytes.escape_ascii().to_string();
|
||||
Symbol::intern(&s)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LitError {
|
||||
|
|
@ -115,9 +135,9 @@ impl LitKind {
|
|||
}
|
||||
});
|
||||
error?;
|
||||
LitKind::ByteStr(buf.into())
|
||||
LitKind::ByteStr(buf.into(), StrStyle::Cooked)
|
||||
}
|
||||
token::ByteStrRaw(_) => {
|
||||
token::ByteStrRaw(n) => {
|
||||
let s = symbol.as_str();
|
||||
let bytes = if s.contains('\r') {
|
||||
let mut buf = Vec::with_capacity(s.len());
|
||||
|
|
@ -136,69 +156,95 @@ impl LitKind {
|
|||
symbol.to_string().into_bytes()
|
||||
};
|
||||
|
||||
LitKind::ByteStr(bytes.into())
|
||||
LitKind::ByteStr(bytes.into(), StrStyle::Raw(n))
|
||||
}
|
||||
token::Err => LitKind::Err,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to recover a token from semantic literal.
|
||||
/// This function is used when the original token doesn't exist (e.g. the literal is created
|
||||
/// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
|
||||
pub fn to_token_lit(&self) -> token::Lit {
|
||||
let (kind, symbol, suffix) = match *self {
|
||||
LitKind::Str(symbol, ast::StrStyle::Cooked) => {
|
||||
// Don't re-intern unless the escaped string is different.
|
||||
let s = symbol.as_str();
|
||||
let escaped = s.escape_default().to_string();
|
||||
let symbol = if s == escaped { symbol } else { Symbol::intern(&escaped) };
|
||||
(token::Str, symbol, None)
|
||||
impl fmt::Display for LitKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
LitKind::Byte(b) => {
|
||||
let b: String = ascii::escape_default(b).map(Into::<char>::into).collect();
|
||||
write!(f, "b'{}'", b)?;
|
||||
}
|
||||
LitKind::Str(symbol, ast::StrStyle::Raw(n)) => (token::StrRaw(n), symbol, None),
|
||||
LitKind::ByteStr(ref bytes) => {
|
||||
let string = bytes.escape_ascii().to_string();
|
||||
(token::ByteStr, Symbol::intern(&string), None)
|
||||
LitKind::Char(ch) => write!(f, "'{}'", escape_char_symbol(ch))?,
|
||||
LitKind::Str(sym, StrStyle::Cooked) => write!(f, "\"{}\"", escape_string_symbol(sym))?,
|
||||
LitKind::Str(sym, StrStyle::Raw(n)) => write!(
|
||||
f,
|
||||
"r{delim}\"{string}\"{delim}",
|
||||
delim = "#".repeat(n as usize),
|
||||
string = sym
|
||||
)?,
|
||||
LitKind::ByteStr(ref bytes, StrStyle::Cooked) => {
|
||||
write!(f, "b\"{}\"", escape_byte_str_symbol(bytes))?
|
||||
}
|
||||
LitKind::Byte(byte) => {
|
||||
let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect();
|
||||
(token::Byte, Symbol::intern(&string), None)
|
||||
}
|
||||
LitKind::Char(ch) => {
|
||||
let string: String = ch.escape_default().map(Into::<char>::into).collect();
|
||||
(token::Char, Symbol::intern(&string), None)
|
||||
LitKind::ByteStr(ref bytes, StrStyle::Raw(n)) => {
|
||||
// Unwrap because raw byte string literals can only contain ASCII.
|
||||
let symbol = str::from_utf8(bytes).unwrap();
|
||||
write!(
|
||||
f,
|
||||
"br{delim}\"{string}\"{delim}",
|
||||
delim = "#".repeat(n as usize),
|
||||
string = symbol
|
||||
)?;
|
||||
}
|
||||
LitKind::Int(n, ty) => {
|
||||
let suffix = match ty {
|
||||
ast::LitIntType::Unsigned(ty) => Some(ty.name()),
|
||||
ast::LitIntType::Signed(ty) => Some(ty.name()),
|
||||
ast::LitIntType::Unsuffixed => None,
|
||||
};
|
||||
(token::Integer, sym::integer(n), suffix)
|
||||
write!(f, "{}", n)?;
|
||||
match ty {
|
||||
ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name())?,
|
||||
ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name())?,
|
||||
ast::LitIntType::Unsuffixed => {}
|
||||
}
|
||||
}
|
||||
LitKind::Float(symbol, ty) => {
|
||||
let suffix = match ty {
|
||||
ast::LitFloatType::Suffixed(ty) => Some(ty.name()),
|
||||
ast::LitFloatType::Unsuffixed => None,
|
||||
};
|
||||
(token::Float, symbol, suffix)
|
||||
write!(f, "{}", symbol)?;
|
||||
match ty {
|
||||
ast::LitFloatType::Suffixed(ty) => write!(f, "{}", ty.name())?,
|
||||
ast::LitFloatType::Unsuffixed => {}
|
||||
}
|
||||
}
|
||||
LitKind::Bool(value) => {
|
||||
let symbol = if value { kw::True } else { kw::False };
|
||||
(token::Bool, symbol, None)
|
||||
LitKind::Bool(b) => write!(f, "{}", if b { "true" } else { "false" })?,
|
||||
LitKind::Err => {
|
||||
// This only shows up in places like `-Zunpretty=hir` output, so we
|
||||
// don't bother to produce something useful.
|
||||
write!(f, "<bad-literal>")?;
|
||||
}
|
||||
// This only shows up in places like `-Zunpretty=hir` output, so we
|
||||
// don't bother to produce something useful.
|
||||
LitKind::Err => (token::Err, Symbol::intern("<bad-literal>"), None),
|
||||
};
|
||||
}
|
||||
|
||||
token::Lit::new(kind, symbol, suffix)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl MetaItemLit {
|
||||
/// Converts token literal into a meta item literal.
|
||||
/// Converts a token literal into a meta item literal.
|
||||
pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result<MetaItemLit, LitError> {
|
||||
Ok(MetaItemLit { token_lit, kind: LitKind::from_token_lit(token_lit)?, span })
|
||||
Ok(MetaItemLit {
|
||||
symbol: token_lit.symbol,
|
||||
suffix: token_lit.suffix,
|
||||
kind: LitKind::from_token_lit(token_lit)?,
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
/// Cheaply converts a meta item literal into a token literal.
|
||||
pub fn as_token_lit(&self) -> token::Lit {
|
||||
let kind = match self.kind {
|
||||
LitKind::Bool(_) => token::Bool,
|
||||
LitKind::Str(_, ast::StrStyle::Cooked) => token::Str,
|
||||
LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n),
|
||||
LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr,
|
||||
LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n),
|
||||
LitKind::Byte(_) => token::Byte,
|
||||
LitKind::Char(_) => token::Char,
|
||||
LitKind::Int(..) => token::Integer,
|
||||
LitKind::Float(..) => token::Float,
|
||||
LitKind::Err => token::Err,
|
||||
};
|
||||
|
||||
token::Lit::new(kind, self.symbol, self.suffix)
|
||||
}
|
||||
|
||||
/// Converts an arbitrary token into meta item literal.
|
||||
|
|
|
|||
|
|
@ -31,6 +31,44 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
|
||||
ensure_sufficient_stack(|| {
|
||||
match &e.kind {
|
||||
// Paranthesis expression does not have a HirId and is handled specially.
|
||||
ExprKind::Paren(ex) => {
|
||||
let mut ex = self.lower_expr_mut(ex);
|
||||
// Include parens in span, but only if it is a super-span.
|
||||
if e.span.contains(ex.span) {
|
||||
ex.span = self.lower_span(e.span);
|
||||
}
|
||||
// Merge attributes into the inner expression.
|
||||
if !e.attrs.is_empty() {
|
||||
let old_attrs =
|
||||
self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
|
||||
self.attrs.insert(
|
||||
ex.hir_id.local_id,
|
||||
&*self.arena.alloc_from_iter(
|
||||
e.attrs
|
||||
.iter()
|
||||
.map(|a| self.lower_attr(a))
|
||||
.chain(old_attrs.iter().cloned()),
|
||||
),
|
||||
);
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
// Desugar `ExprForLoop`
|
||||
// from: `[opt_ident]: for <pat> in <head> <body>`
|
||||
//
|
||||
// This also needs special handling because the HirId of the returned `hir::Expr` will not
|
||||
// correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
|
||||
ExprKind::ForLoop(pat, head, body, opt_label) => {
|
||||
return self.lower_expr_for(e, pat, head, body, *opt_label);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let hir_id = self.lower_node_id(e.id);
|
||||
self.lower_attrs(hir_id, &e.attrs);
|
||||
|
||||
let kind = match &e.kind {
|
||||
ExprKind::Box(inner) => hir::ExprKind::Box(self.lower_expr(inner)),
|
||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
|
|
@ -48,7 +86,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) {
|
||||
if let [inner] = &args[..] && e.attrs.len() == 1 {
|
||||
let kind = hir::ExprKind::Box(self.lower_expr(&inner));
|
||||
let hir_id = self.lower_node_id(e.id);
|
||||
return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
|
||||
} else {
|
||||
self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span });
|
||||
|
|
@ -97,7 +134,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
ExprKind::IncludedBytes(bytes) => hir::ExprKind::Lit(respan(
|
||||
self.lower_span(e.span),
|
||||
LitKind::ByteStr(bytes.clone()),
|
||||
LitKind::ByteStr(bytes.clone(), StrStyle::Cooked),
|
||||
)),
|
||||
ExprKind::Cast(expr, ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
|
|
@ -147,7 +184,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
),
|
||||
ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr(
|
||||
*capture_clause,
|
||||
None,
|
||||
hir_id,
|
||||
*closure_node_id,
|
||||
None,
|
||||
e.span,
|
||||
|
|
@ -184,6 +221,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
binder,
|
||||
*capture_clause,
|
||||
e.id,
|
||||
hir_id,
|
||||
*closure_id,
|
||||
fn_decl,
|
||||
body,
|
||||
|
|
@ -279,39 +317,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||
ExprKind::Err => hir::ExprKind::Err,
|
||||
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
|
||||
ExprKind::Paren(ex) => {
|
||||
let mut ex = self.lower_expr_mut(ex);
|
||||
// Include parens in span, but only if it is a super-span.
|
||||
if e.span.contains(ex.span) {
|
||||
ex.span = self.lower_span(e.span);
|
||||
}
|
||||
// Merge attributes into the inner expression.
|
||||
if !e.attrs.is_empty() {
|
||||
let old_attrs =
|
||||
self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
|
||||
self.attrs.insert(
|
||||
ex.hir_id.local_id,
|
||||
&*self.arena.alloc_from_iter(
|
||||
e.attrs
|
||||
.iter()
|
||||
.map(|a| self.lower_attr(a))
|
||||
.chain(old_attrs.iter().cloned()),
|
||||
),
|
||||
);
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
|
||||
// Desugar `ExprForLoop`
|
||||
// from: `[opt_ident]: for <pat> in <head> <body>`
|
||||
ExprKind::ForLoop(pat, head, body, opt_label) => {
|
||||
return self.lower_expr_for(e, pat, head, body, *opt_label);
|
||||
}
|
||||
ExprKind::Paren(_) | ExprKind::ForLoop(..) => unreachable!("already handled"),
|
||||
|
||||
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
|
||||
};
|
||||
|
||||
let hir_id = self.lower_node_id(e.id);
|
||||
self.lower_attrs(hir_id, &e.attrs);
|
||||
hir::Expr { hir_id, kind, span: self.lower_span(e.span) }
|
||||
})
|
||||
}
|
||||
|
|
@ -576,7 +587,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
pub(super) fn make_async_expr(
|
||||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
outer_hir_id: Option<hir::HirId>,
|
||||
outer_hir_id: hir::HirId,
|
||||
closure_node_id: NodeId,
|
||||
ret_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
|
|
@ -669,8 +680,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ExprKind::Closure(c)
|
||||
};
|
||||
|
||||
let track_caller = outer_hir_id
|
||||
.and_then(|id| self.attrs.get(&id.local_id))
|
||||
let track_caller = self
|
||||
.attrs
|
||||
.get(&outer_hir_id.local_id)
|
||||
.map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)));
|
||||
|
||||
let hir_id = self.lower_node_id(closure_node_id);
|
||||
|
|
@ -985,6 +997,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
binder: &ClosureBinder,
|
||||
capture_clause: CaptureBy,
|
||||
closure_id: NodeId,
|
||||
closure_hir_id: hir::HirId,
|
||||
inner_closure_id: NodeId,
|
||||
decl: &FnDecl,
|
||||
body: &Expr,
|
||||
|
|
@ -1018,9 +1031,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let async_body = this.make_async_expr(
|
||||
capture_clause,
|
||||
// FIXME(nbdd0121): This should also use a proper HIR id so `#[track_caller]`
|
||||
// can be applied on async closures as well.
|
||||
None,
|
||||
closure_hir_id,
|
||||
inner_closure_id,
|
||||
async_ret_ty,
|
||||
body.span,
|
||||
|
|
|
|||
|
|
@ -1139,7 +1139,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let async_expr = this.make_async_expr(
|
||||
CaptureBy::Value,
|
||||
Some(fn_id),
|
||||
fn_id,
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
|
|
|
|||
|
|
@ -456,8 +456,8 @@ pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> {
|
|||
}
|
||||
|
||||
// Drop AST to free memory
|
||||
std::mem::drop(ast_index);
|
||||
sess.time("drop_ast", || std::mem::drop(krate));
|
||||
drop(ast_index);
|
||||
sess.time("drop_ast", || drop(krate));
|
||||
|
||||
// Discard hygiene data, which isn't required after lowering to HIR.
|
||||
if !sess.opts.unstable_opts.keep_hygiene_data {
|
||||
|
|
@ -958,7 +958,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
lit
|
||||
} else {
|
||||
MetaItemLit {
|
||||
token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None),
|
||||
symbol: kw::Empty,
|
||||
suffix: None,
|
||||
kind: LitKind::Err,
|
||||
span: DUMMY_SP,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -630,7 +630,7 @@ fn check_incompatible_features(sess: &Session) {
|
|||
{
|
||||
let spans = vec![f1_span, f2_span];
|
||||
sess.struct_span_err(
|
||||
spans.clone(),
|
||||
spans,
|
||||
&format!(
|
||||
"features `{}` and `{}` are incompatible, using them at the same time \
|
||||
is not allowed",
|
||||
|
|
|
|||
|
|
@ -376,7 +376,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
|
||||
fn print_meta_item_lit(&mut self, lit: &ast::MetaItemLit) {
|
||||
self.print_token_literal(lit.token_lit, lit.span)
|
||||
self.print_token_literal(lit.as_token_lit(), lit.span)
|
||||
}
|
||||
|
||||
fn print_token_literal(&mut self, token_lit: token::Lit, span: Span) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use crate::pp::Breaks::Inconsistent;
|
|||
use crate::pprust::state::{AnnNode, IterDelimited, PrintState, State, INDENT_UNIT};
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||
use rustc_ast::util::parser::{self, AssocOp, Fixity};
|
||||
use rustc_ast::{self as ast, BlockCheckMode};
|
||||
|
||||
|
|
@ -323,7 +325,7 @@ impl<'a> State<'a> {
|
|||
self.print_token_literal(*token_lit, expr.span);
|
||||
}
|
||||
ast::ExprKind::IncludedBytes(bytes) => {
|
||||
let lit = ast::LitKind::ByteStr(bytes.clone()).to_token_lit();
|
||||
let lit = token::Lit::new(token::ByteStr, escape_byte_str_symbol(bytes), None);
|
||||
self.print_token_literal(lit, expr.span)
|
||||
}
|
||||
ast::ExprKind::Cast(expr, ty) => {
|
||||
|
|
|
|||
|
|
@ -697,8 +697,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
.map_bound(|p| p.predicates),
|
||||
None,
|
||||
),
|
||||
ty::Opaque(did, substs) => {
|
||||
find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*did), Some(*substs))
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*def_id), Some(*substs))
|
||||
}
|
||||
ty::Closure(_, substs) => match substs.as_closure().kind() {
|
||||
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
|
||||
|
|
@ -745,7 +745,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"consider cloning the value if the performance cost is acceptable",
|
||||
".clone()".to_string(),
|
||||
".clone()",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1059,17 +1059,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
if self.fn_self_span_reported.insert(fn_span) {
|
||||
err.span_note(
|
||||
// Check whether the source is accessible
|
||||
if self.infcx.tcx.sess.source_map().is_span_accessible(self_arg.span) {
|
||||
self_arg.span
|
||||
} else {
|
||||
fn_call_span
|
||||
},
|
||||
self_arg.span,
|
||||
"calling this operator moves the left-hand side",
|
||||
);
|
||||
}
|
||||
}
|
||||
CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
|
||||
CallKind::Normal { self_arg, desugaring, method_did } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
|
||||
|
|
@ -1139,14 +1134,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
),
|
||||
);
|
||||
}
|
||||
let tcx = self.infcx.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) {
|
||||
let func = tcx.def_path_str(method_did);
|
||||
err.span_note(
|
||||
self_arg.span,
|
||||
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
|
||||
&format!("`{func}` takes ownership of the receiver `self`, which moves {place_name}")
|
||||
);
|
||||
}
|
||||
let parent_did = tcx.parent(method_did);
|
||||
let parent_self_ty = (tcx.def_kind(parent_did)
|
||||
== rustc_hir::def::DefKind::Impl)
|
||||
.then_some(parent_did)
|
||||
.and_then(|did| match tcx.type_of(did).kind() {
|
||||
ty::Adt(def, ..) => Some(def.did()),
|
||||
_ => None,
|
||||
});
|
||||
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
|
||||
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
|
||||
});
|
||||
if is_option_or_result && maybe_reinitialized_locations_is_empty {
|
||||
err.span_label(
|
||||
var_span,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_middle::ty;
|
|||
use rustc_mir_dataflow::move_paths::{
|
||||
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
||||
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
|
||||
use crate::prefixes::PrefixSet;
|
||||
|
|
@ -148,7 +148,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
match_span: Span,
|
||||
statement_span: Span,
|
||||
) {
|
||||
debug!("append_binding_error(match_place={:?}, match_span={:?})", match_place, match_span);
|
||||
debug!(?match_place, ?match_span, "append_binding_error");
|
||||
|
||||
let from_simple_let = match_place.is_none();
|
||||
let match_place = match_place.unwrap_or(move_from);
|
||||
|
|
@ -160,7 +160,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge
|
||||
&& match_span == *span
|
||||
{
|
||||
debug!("appending local({:?}) to list", bind_to);
|
||||
debug!("appending local({bind_to:?}) to list");
|
||||
if !binds_to.is_empty() {
|
||||
binds_to.push(bind_to);
|
||||
}
|
||||
|
|
@ -198,7 +198,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
} = ge
|
||||
{
|
||||
if match_span == *span && mpi == *other_mpi {
|
||||
debug!("appending local({:?}) to list", bind_to);
|
||||
debug!("appending local({bind_to:?}) to list");
|
||||
binds_to.push(bind_to);
|
||||
return;
|
||||
}
|
||||
|
|
@ -410,15 +410,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) {
|
||||
match error {
|
||||
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
|
||||
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider borrowing here",
|
||||
format!("&{snippet}"),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
|
||||
self.add_borrow_suggestions(err, span);
|
||||
if binds_to.is_empty() {
|
||||
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
|
||||
let place_desc = match self.describe_place(move_from.as_ref()) {
|
||||
|
|
@ -461,39 +453,75 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_borrow_suggestions(&self, err: &mut Diagnostic, span: Span) {
|
||||
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
|
||||
Ok(snippet) if snippet.starts_with('*') => {
|
||||
err.span_suggestion_verbose(
|
||||
span.with_hi(span.lo() + BytePos(1)),
|
||||
"consider removing the dereference here",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"consider borrowing here",
|
||||
"&".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) {
|
||||
let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
|
||||
let mut suggestions: Vec<(Span, String, String)> = Vec::new();
|
||||
for local in binds_to {
|
||||
let bind_to = &self.body.local_decls[*local];
|
||||
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
||||
VarBindingForm { pat_span, .. },
|
||||
)))) = bind_to.local_info
|
||||
{
|
||||
if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
|
||||
let Ok(pat_snippet) =
|
||||
self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; };
|
||||
let Some(stripped) = pat_snippet.strip_prefix('&') else {
|
||||
suggestions.push((
|
||||
bind_to.source_info.span.shrink_to_lo(),
|
||||
"consider borrowing the pattern binding".to_string(),
|
||||
"ref ".to_string(),
|
||||
));
|
||||
continue;
|
||||
};
|
||||
let inner_pat_snippet = stripped.trim_start();
|
||||
let (pat_span, suggestion, to_remove) = if inner_pat_snippet.starts_with("mut")
|
||||
&& inner_pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
|
||||
{
|
||||
if let Some(stripped) = pat_snippet.strip_prefix('&') {
|
||||
let pat_snippet = stripped.trim_start();
|
||||
let (suggestion, to_remove) = if pat_snippet.starts_with("mut")
|
||||
&& pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
|
||||
{
|
||||
(pat_snippet["mut".len()..].trim_start(), "&mut")
|
||||
} else {
|
||||
(pat_snippet, "&")
|
||||
};
|
||||
suggestions.push((pat_span, to_remove, suggestion.to_owned()));
|
||||
}
|
||||
}
|
||||
let inner_pat_snippet = inner_pat_snippet["mut".len()..].trim_start();
|
||||
let pat_span = pat_span.with_hi(
|
||||
pat_span.lo()
|
||||
+ BytePos((pat_snippet.len() - inner_pat_snippet.len()) as u32),
|
||||
);
|
||||
(pat_span, String::new(), "mutable borrow")
|
||||
} else {
|
||||
let pat_span = pat_span.with_hi(
|
||||
pat_span.lo()
|
||||
+ BytePos(
|
||||
(pat_snippet.len() - inner_pat_snippet.trim_start().len()) as u32,
|
||||
),
|
||||
);
|
||||
(pat_span, String::new(), "borrow")
|
||||
};
|
||||
suggestions.push((
|
||||
pat_span,
|
||||
format!("consider removing the {to_remove}"),
|
||||
suggestion.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
suggestions.sort_unstable_by_key(|&(span, _, _)| span);
|
||||
suggestions.dedup_by_key(|&mut (span, _, _)| span);
|
||||
for (span, to_remove, suggestion) in suggestions {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&format!("consider removing the `{to_remove}`"),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
for (span, msg, suggestion) in suggestions {
|
||||
err.span_suggestion_verbose(span, &msg, suggestion, Applicability::MachineApplicable);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -521,8 +549,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
if binds_to.len() > 1 {
|
||||
err.note(
|
||||
"move occurs because these variables have types that \
|
||||
don't implement the `Copy` trait",
|
||||
"move occurs because these variables have types that don't implement the `Copy` \
|
||||
trait",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -504,7 +504,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
|
||||
|
||||
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
|
||||
if let ty::Opaque(def_id, _) = *output_ty.kind() {
|
||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *output_ty.kind() {
|
||||
output_ty = self.infcx.tcx.type_of(def_id)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -747,27 +747,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// Otherwise, we need to find the minimum remaining choice, if
|
||||
// any, and take that.
|
||||
debug!("choice_regions remaining are {:#?}", choice_regions);
|
||||
let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
|
||||
let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
|
||||
let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
|
||||
match (r1_outlives_r2, r2_outlives_r1) {
|
||||
(true, true) => Some(r1.min(r2)),
|
||||
(true, false) => Some(r2),
|
||||
(false, true) => Some(r1),
|
||||
(false, false) => None,
|
||||
}
|
||||
let Some(&min_choice) = choice_regions.iter().find(|&r1| {
|
||||
choice_regions.iter().all(|&r2| {
|
||||
self.universal_region_relations.outlives(r2, *r1)
|
||||
})
|
||||
}) else {
|
||||
debug!("no choice region outlived by all others");
|
||||
return false;
|
||||
};
|
||||
let mut min_choice = choice_regions[0];
|
||||
for &other_option in &choice_regions[1..] {
|
||||
debug!(?min_choice, ?other_option,);
|
||||
match min(min_choice, other_option) {
|
||||
Some(m) => min_choice = m,
|
||||
None => {
|
||||
debug!(?min_choice, ?other_option, "incomparable; no min choice",);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let min_choice_scc = self.constraint_sccs.scc(min_choice);
|
||||
debug!(?min_choice, ?min_choice_scc);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ pub fn expand(
|
|||
(item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
|
||||
} else {
|
||||
ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "alloc_error_handler must be a function");
|
||||
return vec![orig_item.clone()];
|
||||
return vec![orig_item];
|
||||
};
|
||||
|
||||
// Generate a bunch of new items using the AllocFnFactory
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ use rustc_expand::base::{self, DummyResult};
|
|||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
use std::string::String;
|
||||
|
||||
pub fn expand_concat(
|
||||
cx: &mut base::ExtCtxt<'_>,
|
||||
sp: rustc_span::Span,
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ fn invalid_type_err(
|
|||
Ok(ast::LitKind::Int(_, _)) => {
|
||||
cx.span_err(span, "numeric literal is not a `u8`");
|
||||
}
|
||||
Ok(ast::LitKind::ByteStr(_) | ast::LitKind::Byte(_)) => unreachable!(),
|
||||
Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(),
|
||||
Err(err) => {
|
||||
report_lit_error(&cx.sess.parse_sess, err, token_lit, span);
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ fn handle_array_element(
|
|||
)) if val <= u8::MAX.into() => Some(val as u8),
|
||||
|
||||
Ok(ast::LitKind::Byte(val)) => Some(val),
|
||||
Ok(ast::LitKind::ByteStr(_)) => {
|
||||
Ok(ast::LitKind::ByteStr(..)) => {
|
||||
if !*has_errors {
|
||||
cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
|
||||
.note("byte strings are treated as arrays of bytes")
|
||||
|
|
@ -174,7 +174,7 @@ pub fn expand_concat_bytes(
|
|||
Ok(ast::LitKind::Byte(val)) => {
|
||||
accumulator.push(val);
|
||||
}
|
||||
Ok(ast::LitKind::ByteStr(ref bytes)) => {
|
||||
Ok(ast::LitKind::ByteStr(ref bytes, _)) => {
|
||||
accumulator.extend_from_slice(&bytes);
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -196,7 +196,7 @@ pub fn expand_concat_bytes(
|
|||
}
|
||||
}
|
||||
if !missing_literals.is_empty() {
|
||||
let mut err = cx.struct_span_err(missing_literals.clone(), "expected a byte literal");
|
||||
let mut err = cx.struct_span_err(missing_literals, "expected a byte literal");
|
||||
err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`");
|
||||
err.emit();
|
||||
return base::MacEager::expr(DummyResult::raw_expr(sp, true));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::cfg_eval::cfg_eval;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
|
|
@ -130,9 +130,11 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
|
|||
}
|
||||
|
||||
fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) {
|
||||
let help_msg = match lit.token_lit.kind {
|
||||
token::Str if rustc_lexer::is_ident(lit.token_lit.symbol.as_str()) => {
|
||||
format!("try using `#[derive({})]`", lit.token_lit.symbol)
|
||||
let help_msg = match lit.kind {
|
||||
ast::LitKind::Str(_, ast::StrStyle::Cooked)
|
||||
if rustc_lexer::is_ident(lit.symbol.as_str()) =>
|
||||
{
|
||||
format!("try using `#[derive({})]`", lit.symbol)
|
||||
}
|
||||
_ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ task:
|
|||
folder: target
|
||||
prepare_script:
|
||||
- . $HOME/.cargo/env
|
||||
- git config --global user.email "user@example.com"
|
||||
- git config --global user.name "User"
|
||||
- ./y.rs prepare
|
||||
test_script:
|
||||
- . $HOME/.cargo/env
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ jobs:
|
|||
- name: Rustfmt
|
||||
run: |
|
||||
cargo fmt --check
|
||||
rustfmt --check build_system/mod.rs
|
||||
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
|
@ -28,7 +29,7 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
- os: ubuntu-20.04 # FIXME switch to ubuntu-22.04 once #1303 is fixed
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
|
|
@ -41,18 +42,22 @@ jobs:
|
|||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: aarch64-unknown-linux-gnu
|
||||
# s390x requires QEMU 6.1 or greater, we could build it from source, but ubuntu 22.04 comes with 6.2 by default
|
||||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: s390x-unknown-linux-gnu
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache cargo installed crates
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-cargo-installed-crates
|
||||
|
||||
- name: Cache cargo registry and index
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
|
|
@ -60,9 +65,9 @@ jobs:
|
|||
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
- name: Install MinGW toolchain and wine
|
||||
|
|
@ -78,11 +83,14 @@ jobs:
|
|||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-aarch64-linux-gnu qemu-user
|
||||
|
||||
- name: Prepare dependencies
|
||||
- name: Install s390x toolchain and qemu
|
||||
if: matrix.env.TARGET_TRIPLE == 's390x-unknown-linux-gnu'
|
||||
run: |
|
||||
git config --global user.email "user@example.com"
|
||||
git config --global user.name "User"
|
||||
./y.rs prepare
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
|
||||
|
||||
- name: Prepare dependencies
|
||||
run: ./y.rs prepare
|
||||
|
||||
- name: Build without unstable features
|
||||
env:
|
||||
|
|
@ -110,7 +118,7 @@ jobs:
|
|||
./y.rs test
|
||||
|
||||
- name: Package prebuilt cg_clif
|
||||
run: tar cvfJ cg_clif.tar.xz build
|
||||
run: tar cvfJ cg_clif.tar.xz dist
|
||||
|
||||
- name: Upload prebuilt cg_clif
|
||||
if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
|
||||
|
|
@ -121,7 +129,7 @@ jobs:
|
|||
|
||||
- name: Upload prebuilt cg_clif (cross compile)
|
||||
if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
|
||||
path: cg_clif.tar.xz
|
||||
|
|
@ -147,13 +155,13 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache cargo installed crates
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-installed-crates
|
||||
|
||||
- name: Cache cargo registry and index
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
|
|
@ -161,9 +169,9 @@ jobs:
|
|||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
- name: Set MinGW as the default toolchain
|
||||
|
|
@ -172,8 +180,6 @@ jobs:
|
|||
|
||||
- name: Prepare dependencies
|
||||
run: |
|
||||
git config --global user.email "user@example.com"
|
||||
git config --global user.name "User"
|
||||
git config --global core.autocrlf false
|
||||
rustc y.rs -o y.exe -g
|
||||
./y.exe prepare
|
||||
|
|
@ -198,24 +204,24 @@ jobs:
|
|||
|
||||
# Enable extra checks
|
||||
$Env:CG_CLIF_ENABLE_VERIFIER=1
|
||||
|
||||
|
||||
# WIP Disable some tests
|
||||
|
||||
|
||||
# This fails due to some weird argument handling by hyperfine, not an actual regression
|
||||
# more of a build system issue
|
||||
(Get-Content config.txt) -replace '(bench.simple-raytracer)', '# $1' | Out-File config.txt
|
||||
|
||||
# This fails with a different output than expected
|
||||
|
||||
# This fails with a different output than expected
|
||||
(Get-Content config.txt) -replace '(test.regex-shootout-regex-dna)', '# $1' | Out-File config.txt
|
||||
|
||||
./y.exe test
|
||||
|
||||
- name: Package prebuilt cg_clif
|
||||
# don't use compression as xzip isn't supported by tar on windows and bzip2 hangs
|
||||
run: tar cvf cg_clif.tar build
|
||||
run: tar cvf cg_clif.tar dist
|
||||
|
||||
- name: Upload prebuilt cg_clif
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
|
||||
path: cg_clif.tar
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache cargo installed crates
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ubuntu-latest-cargo-installed-crates
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache cargo installed crates
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-cargo-installed-crates
|
||||
|
||||
- name: Cache cargo registry and index
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
|
|
@ -25,9 +25,9 @@ jobs:
|
|||
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
- name: Prepare dependencies
|
||||
|
|
@ -49,13 +49,13 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache cargo installed crates
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-cargo-installed-crates
|
||||
|
||||
- name: Cache cargo registry and index
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
|
|
@ -63,9 +63,9 @@ jobs:
|
|||
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
- name: Prepare dependencies
|
||||
|
|
|
|||
1
compiler/rustc_codegen_cranelift/.gitignore
vendored
1
compiler/rustc_codegen_cranelift/.gitignore
vendored
|
|
@ -14,5 +14,6 @@ perf.data.old
|
|||
/build_sysroot/sysroot_src
|
||||
/build_sysroot/compiler-builtins
|
||||
/build_sysroot/rustc_version
|
||||
/dist
|
||||
/rust
|
||||
/download
|
||||
|
|
|
|||
|
|
@ -4,16 +4,10 @@
|
|||
"rust-analyzer.imports.granularity.enforce": true,
|
||||
"rust-analyzer.imports.granularity.group": "module",
|
||||
"rust-analyzer.imports.prefix": "crate",
|
||||
"rust-analyzer.cargo.features": ["unstable-features"],
|
||||
"rust-analyzer.cargo.features": ["unstable-features", "__check_build_system_using_ra"],
|
||||
"rust-analyzer.linkedProjects": [
|
||||
"./Cargo.toml",
|
||||
//"./build_sysroot/sysroot_src/library/std/Cargo.toml",
|
||||
{
|
||||
"roots": [
|
||||
"./example/mini_core.rs",
|
||||
"./example/mini_core_hello_world.rs",
|
||||
"./example/mod_bench.rs"
|
||||
],
|
||||
"crates": [
|
||||
{
|
||||
"root_module": "./example/mini_core.rs",
|
||||
|
|
@ -36,34 +30,11 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"roots": ["./example/std_example.rs"],
|
||||
"sysroot_src": "./build_sysroot/sysroot_src/library",
|
||||
"crates": [
|
||||
{
|
||||
"root_module": "./example/std_example.rs",
|
||||
"edition": "2018",
|
||||
"deps": [{ "crate": 1, "name": "std" }],
|
||||
"cfg": [],
|
||||
},
|
||||
{
|
||||
"root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
|
||||
"edition": "2018",
|
||||
"deps": [],
|
||||
"cfg": [],
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"roots": ["./y.rs"],
|
||||
"crates": [
|
||||
{
|
||||
"root_module": "./y.rs",
|
||||
"edition": "2018",
|
||||
"deps": [{ "crate": 1, "name": "std" }],
|
||||
"cfg": [],
|
||||
},
|
||||
{
|
||||
"root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
|
||||
"edition": "2018",
|
||||
"edition": "2015",
|
||||
"deps": [],
|
||||
"cfg": [],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.60"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
|
||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
|
|
@ -39,9 +39,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.11.0"
|
||||
version = "3.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
|
||||
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
|
|
@ -57,24 +57,25 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44409ccf2d0f663920cab563d2b79fcd6b2e9a2bcc6e929fef76c8f82ad6c17a"
|
||||
checksum = "b62c772976416112fa4484cbd688cb6fb35fd430005c1c586224fc014018abad"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98de2018ad96eb97f621f7d6b900a0cc661aec8d02ea4a50e56ecb48e5a2fcaf"
|
||||
checksum = "9b40ed2dd13c2ac7e24f88a3090c68ad3414eb1d066a95f8f1f7b3b819cb4e46"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bumpalo",
|
||||
"cranelift-bforest",
|
||||
"cranelift-codegen-meta",
|
||||
"cranelift-codegen-shared",
|
||||
"cranelift-egraph",
|
||||
"cranelift-entity",
|
||||
"cranelift-isle",
|
||||
"gimli",
|
||||
|
|
@ -86,30 +87,44 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5287ce36e6c4758fbaf298bd1a8697ad97a4f2375a3d1b61142ea538db4877e5"
|
||||
checksum = "bb927a8f1c27c34ee3759b6b0ffa528d2330405d5cc4511f0cab33fe2279f4b5"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2855c24219e2f08827f3f4ffb2da92e134ae8d8ecc185b11ec8f9878cf5f588e"
|
||||
checksum = "43dfa417b884a9ab488d95fd6b93b25e959321fe7bfd7a0a960ba5d7fb7ab927"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-egraph"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a66b39785efd8513d2cca967ede56d6cc57c8d7986a595c7c47d0c78de8dce"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
"fxhash",
|
||||
"hashbrown",
|
||||
"indexmap",
|
||||
"log",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b65673279d75d34bf11af9660ae2dbd1c22e6d28f163f5c72f4e1dc56d56103"
|
||||
checksum = "0637ffde963cb5d759bc4d454cfa364b6509e6c74cdaa21298add0ed9276f346"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed2b3d7a4751163f6c4a349205ab1b7d9c00eecf19dcea48592ef1f7688eefc"
|
||||
checksum = "fb72b8342685e850cb037350418f62cc4fc55d6c2eb9c7ca01b82f9f1a6f3d56"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
|
|
@ -119,15 +134,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-isle"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be64cecea9d90105fc6a2ba2d003e98c867c1d6c4c86cc878f97ad9fb916293"
|
||||
checksum = "850579cb9e4b448f7c301f1e6e6cbad99abe3f1f1d878a4994cb66e33c6db8cd"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-jit"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f98ed42a70a0c9c388e34ec9477f57fc7300f541b1e5136a0e2ea02b1fac6015"
|
||||
checksum = "9add822ad66dcbe152b5ab57de10240a2df4505099f2f6c27159acb711890bd4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -138,14 +153,15 @@ dependencies = [
|
|||
"log",
|
||||
"region",
|
||||
"target-lexicon",
|
||||
"wasmtime-jit-icache-coherence",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-module"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d658ac7f156708bfccb647216cc8b9387469f50d352ba4ad80150541e4ae2d49"
|
||||
checksum = "406b772626fc2664864cf947f3895a23b619895c7fff635f3622e2d857f4492f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -153,9 +169,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4a03a6ac1b063e416ca4b93f6247978c991475e8271465340caa6f92f3c16a4"
|
||||
checksum = "2d0a279e5bcba3e0466c734d8d8eb6bfc1ad29e95c37f3e4955b492b5616335e"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
|
|
@ -164,9 +180,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-object"
|
||||
version = "0.88.1"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eef0b4119b645b870a43a036d76c0ada3a076b1f82e8b8487659304c8b09049b"
|
||||
checksum = "39793c550f0c1d7db96c2fc1324583670c8143befe6edbfbaf1c68aba53be983"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -185,6 +201,12 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||
|
||||
[[package]]
|
||||
name = "fxhash"
|
||||
version = "0.2.1"
|
||||
|
|
@ -196,9 +218,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.7"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
|
@ -211,7 +233,9 @@ version = "0.26.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
|
||||
dependencies = [
|
||||
"fallible-iterator",
|
||||
"indexmap",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -225,9 +249,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
|
@ -235,15 +259,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.127"
|
||||
version = "0.2.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
|
||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
|
||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
|
|
@ -287,15 +311,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.13.0"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||
|
||||
[[package]]
|
||||
name = "regalloc2"
|
||||
version = "0.3.2"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779"
|
||||
checksum = "91b2eab54204ea0117fe9a060537e0b07a4e72f7c7d182361ecc346cab2240e5"
|
||||
dependencies = [
|
||||
"fxhash",
|
||||
"log",
|
||||
|
|
@ -342,15 +366,21 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec"
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.4"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1"
|
||||
checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
|
|
@ -364,6 +394,17 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-jit-icache-coherence"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6bbabb309c06cc238ee91b1455b748c45f0bdcab0dda2c2db85b0a1e69fcb66"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
|
|
|||
|
|
@ -3,17 +3,24 @@ 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.88.1", features = ["unwind", "all-arch"] }
|
||||
cranelift-frontend = "0.88.1"
|
||||
cranelift-module = "0.88.1"
|
||||
cranelift-native = "0.88.1"
|
||||
cranelift-jit = { version = "0.88.1", optional = true }
|
||||
cranelift-object = "0.88.1"
|
||||
cranelift-codegen = { version = "0.90.1", features = ["unwind", "all-arch"] }
|
||||
cranelift-frontend = "0.90.1"
|
||||
cranelift-module = "0.90.1"
|
||||
cranelift-native = "0.90.1"
|
||||
cranelift-jit = { version = "0.90.1", optional = true }
|
||||
cranelift-object = "0.90.1"
|
||||
target-lexicon = "0.12.0"
|
||||
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
|
||||
object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||
|
|
@ -39,6 +46,7 @@ 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
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo
|
|||
In the directory with your project (where you can do the usual `cargo build`), run:
|
||||
|
||||
```bash
|
||||
$ $cg_clif_dir/build/cargo-clif build
|
||||
$ $cg_clif_dir/dist/cargo-clif build
|
||||
```
|
||||
|
||||
This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.16.0"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
|
||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"gimli",
|
||||
|
|
@ -32,27 +32,11 @@ dependencies = [
|
|||
"core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
version = "1.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
|
@ -66,9 +50,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.82"
|
||||
version = "0.1.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18cd7635fea7bb481ea543b392789844c1ad581299da70184c7175ce3af76603"
|
||||
checksum = "13e81c6cd7ab79f51a0c927d22858d61ad12bd0b3865f0b13ece02a4486aeabb"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
@ -111,9 +95,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.25.0"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
|
||||
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
|
|
@ -145,9 +129,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.135"
|
||||
version = "0.2.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
|
||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
@ -164,12 +148,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
||||
checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"autocfg",
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
@ -177,9 +160,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.26.2"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
|
||||
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"memchr",
|
||||
|
|
@ -192,7 +175,7 @@ name = "panic_abort"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc",
|
||||
"cfg-if 0.1.10",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"core",
|
||||
"libc",
|
||||
|
|
@ -203,7 +186,7 @@ name = "panic_unwind"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc",
|
||||
"cfg-if 0.1.10",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"core",
|
||||
"libc",
|
||||
|
|
@ -255,7 +238,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"addr2line",
|
||||
"alloc",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"core",
|
||||
"dlmalloc",
|
||||
|
|
@ -277,7 +260,7 @@ dependencies = [
|
|||
name = "std_detect"
|
||||
version = "0.1.5"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
"rustc-std-workspace-alloc",
|
||||
|
|
@ -299,7 +282,7 @@ dependencies = [
|
|||
name = "test"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"cfg-if",
|
||||
"core",
|
||||
"getopts",
|
||||
"libc",
|
||||
|
|
@ -325,7 +308,7 @@ name = "unwind"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if 0.1.10",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"core",
|
||||
"libc",
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
use super::build_sysroot;
|
||||
use super::config;
|
||||
use super::prepare;
|
||||
use super::utils::{cargo_command, spawn_and_wait};
|
||||
use super::path::Dirs;
|
||||
use super::prepare::GitRepo;
|
||||
use super::utils::{spawn_and_wait, CargoProject, Compiler};
|
||||
use super::SysrootKind;
|
||||
|
||||
pub(crate) static ABI_CAFE_REPO: GitRepo =
|
||||
GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
|
||||
|
||||
static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe");
|
||||
|
||||
pub(crate) fn run(
|
||||
channel: &str,
|
||||
sysroot_kind: SysrootKind,
|
||||
target_dir: &Path,
|
||||
dirs: &Dirs,
|
||||
cg_clif_dylib: &Path,
|
||||
host_triple: &str,
|
||||
target_triple: &str,
|
||||
|
|
@ -27,26 +32,25 @@ pub(crate) fn run(
|
|||
|
||||
eprintln!("Building sysroot for abi-cafe");
|
||||
build_sysroot::build_sysroot(
|
||||
dirs,
|
||||
channel,
|
||||
sysroot_kind,
|
||||
target_dir,
|
||||
cg_clif_dylib,
|
||||
host_triple,
|
||||
target_triple,
|
||||
);
|
||||
|
||||
eprintln!("Running abi-cafe");
|
||||
let abi_cafe_path = prepare::ABI_CAFE.source_dir();
|
||||
env::set_current_dir(abi_cafe_path.clone()).unwrap();
|
||||
|
||||
let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
|
||||
|
||||
let mut cmd = cargo_command("cargo", "run", Some(target_triple), &abi_cafe_path);
|
||||
let mut cmd = ABI_CAFE.run(&Compiler::host(), dirs);
|
||||
cmd.arg("--");
|
||||
cmd.arg("--pairs");
|
||||
cmd.args(pairs);
|
||||
cmd.arg("--add-rustc-codegen-backend");
|
||||
cmd.arg(format!("cgclif:{}", cg_clif_dylib.display()));
|
||||
cmd.current_dir(ABI_CAFE.source_dir(dirs));
|
||||
|
||||
spawn_and_wait(cmd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::rustc_info::get_file_name;
|
||||
use super::utils::{cargo_command, is_ci};
|
||||
use super::utils::{is_ci, CargoProject, Compiler};
|
||||
|
||||
static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
|
||||
|
||||
pub(crate) fn build_backend(
|
||||
dirs: &Dirs,
|
||||
channel: &str,
|
||||
host_triple: &str,
|
||||
use_unstable_features: bool,
|
||||
) -> PathBuf {
|
||||
let source_dir = std::env::current_dir().unwrap();
|
||||
let mut cmd = cargo_command("cargo", "build", Some(host_triple), &source_dir);
|
||||
let mut cmd = CG_CLIF.build(&Compiler::host(), dirs);
|
||||
|
||||
cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
|
||||
|
||||
|
|
@ -41,8 +44,8 @@ pub(crate) fn build_backend(
|
|||
eprintln!("[BUILD] rustc_codegen_cranelift");
|
||||
super::utils::spawn_and_wait(cmd);
|
||||
|
||||
source_dir
|
||||
.join("target")
|
||||
CG_CLIF
|
||||
.target_dir(dirs)
|
||||
.join(host_triple)
|
||||
.join(channel)
|
||||
.join(get_file_name("rustc_codegen_cranelift", "dylib"))
|
||||
|
|
|
|||
|
|
@ -1,57 +1,60 @@
|
|||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
use std::process::{self, Command};
|
||||
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name};
|
||||
use super::utils::{cargo_command, spawn_and_wait, try_hard_link};
|
||||
use super::utils::{spawn_and_wait, try_hard_link, CargoProject, Compiler};
|
||||
use super::SysrootKind;
|
||||
|
||||
static DIST_DIR: RelPath = RelPath::DIST;
|
||||
static BIN_DIR: RelPath = RelPath::DIST.join("bin");
|
||||
static LIB_DIR: RelPath = RelPath::DIST.join("lib");
|
||||
static RUSTLIB_DIR: RelPath = LIB_DIR.join("rustlib");
|
||||
|
||||
pub(crate) fn build_sysroot(
|
||||
dirs: &Dirs,
|
||||
channel: &str,
|
||||
sysroot_kind: SysrootKind,
|
||||
target_dir: &Path,
|
||||
cg_clif_dylib_src: &Path,
|
||||
host_triple: &str,
|
||||
target_triple: &str,
|
||||
) {
|
||||
eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
|
||||
|
||||
if target_dir.exists() {
|
||||
fs::remove_dir_all(target_dir).unwrap();
|
||||
}
|
||||
fs::create_dir_all(target_dir.join("bin")).unwrap();
|
||||
fs::create_dir_all(target_dir.join("lib")).unwrap();
|
||||
DIST_DIR.ensure_fresh(dirs);
|
||||
BIN_DIR.ensure_exists(dirs);
|
||||
LIB_DIR.ensure_exists(dirs);
|
||||
|
||||
// Copy the backend
|
||||
let cg_clif_dylib_path = target_dir
|
||||
.join(if cfg!(windows) {
|
||||
// Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
|
||||
// binaries.
|
||||
"bin"
|
||||
} else {
|
||||
"lib"
|
||||
})
|
||||
.join(get_file_name("rustc_codegen_cranelift", "dylib"));
|
||||
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(get_file_name("rustc_codegen_cranelift", "dylib"));
|
||||
try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path);
|
||||
|
||||
// Build and copy rustc and cargo wrappers
|
||||
for wrapper in ["rustc-clif", "cargo-clif"] {
|
||||
for wrapper in ["rustc-clif", "rustdoc-clif", "cargo-clif"] {
|
||||
let wrapper_name = get_wrapper_file_name(wrapper, "bin");
|
||||
|
||||
let mut build_cargo_wrapper_cmd = Command::new("rustc");
|
||||
build_cargo_wrapper_cmd
|
||||
.arg(PathBuf::from("scripts").join(format!("{wrapper}.rs")))
|
||||
.arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
|
||||
.arg("-o")
|
||||
.arg(target_dir.join(wrapper_name))
|
||||
.arg(DIST_DIR.to_path(dirs).join(wrapper_name))
|
||||
.arg("-g");
|
||||
spawn_and_wait(build_cargo_wrapper_cmd);
|
||||
}
|
||||
|
||||
let default_sysroot = super::rustc_info::get_default_sysroot();
|
||||
|
||||
let rustlib = target_dir.join("lib").join("rustlib");
|
||||
let host_rustlib_lib = rustlib.join(host_triple).join("lib");
|
||||
let target_rustlib_lib = rustlib.join(target_triple).join("lib");
|
||||
let host_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(host_triple).join("lib");
|
||||
let target_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(target_triple).join("lib");
|
||||
fs::create_dir_all(&host_rustlib_lib).unwrap();
|
||||
fs::create_dir_all(&target_rustlib_lib).unwrap();
|
||||
|
||||
|
|
@ -112,24 +115,18 @@ pub(crate) fn build_sysroot(
|
|||
}
|
||||
}
|
||||
SysrootKind::Clif => {
|
||||
build_clif_sysroot_for_triple(
|
||||
channel,
|
||||
target_dir,
|
||||
host_triple,
|
||||
&cg_clif_dylib_path,
|
||||
None,
|
||||
);
|
||||
build_clif_sysroot_for_triple(dirs, channel, host_triple, &cg_clif_dylib_path, None);
|
||||
|
||||
if host_triple != target_triple {
|
||||
// When cross-compiling it is often necessary to manually pick the right linker
|
||||
let linker = if target_triple == "aarch64-unknown-linux-gnu" {
|
||||
Some("aarch64-linux-gnu-gcc")
|
||||
} else {
|
||||
None
|
||||
let linker = match target_triple {
|
||||
"aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu-gcc"),
|
||||
"s390x-unknown-linux-gnu" => Some("s390x-linux-gnu-gcc"),
|
||||
_ => None,
|
||||
};
|
||||
build_clif_sysroot_for_triple(
|
||||
dirs,
|
||||
channel,
|
||||
target_dir,
|
||||
target_triple,
|
||||
&cg_clif_dylib_path,
|
||||
linker,
|
||||
|
|
@ -142,21 +139,26 @@ pub(crate) fn build_sysroot(
|
|||
let file = file.unwrap().path();
|
||||
let filename = file.file_name().unwrap().to_str().unwrap();
|
||||
if filename.contains("std-") && !filename.contains(".rlib") {
|
||||
try_hard_link(&file, target_dir.join("lib").join(file.file_name().unwrap()));
|
||||
try_hard_link(&file, LIB_DIR.to_path(dirs).join(file.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME move to download/ or dist/
|
||||
pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = RelPath::BUILD_SYSROOT.join("rustc_version");
|
||||
pub(crate) static SYSROOT_SRC: RelPath = RelPath::BUILD_SYSROOT.join("sysroot_src");
|
||||
static STANDARD_LIBRARY: CargoProject = CargoProject::new(&RelPath::BUILD_SYSROOT, "build_sysroot");
|
||||
|
||||
fn build_clif_sysroot_for_triple(
|
||||
dirs: &Dirs,
|
||||
channel: &str,
|
||||
target_dir: &Path,
|
||||
triple: &str,
|
||||
cg_clif_dylib_path: &Path,
|
||||
linker: Option<&str>,
|
||||
) {
|
||||
match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) {
|
||||
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");
|
||||
|
|
@ -174,7 +176,7 @@ fn build_clif_sysroot_for_triple(
|
|||
}
|
||||
}
|
||||
|
||||
let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
|
||||
let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(triple).join(channel);
|
||||
|
||||
if !super::config::get_bool("keep_sysroot") {
|
||||
// Cleanup the deps dir, but keep build scripts and the incremental cache for faster
|
||||
|
|
@ -185,27 +187,27 @@ fn build_clif_sysroot_for_triple(
|
|||
}
|
||||
|
||||
// Build sysroot
|
||||
let mut build_cmd = cargo_command("cargo", "build", Some(triple), Path::new("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()));
|
||||
rustflags.push_str(&format!(" --sysroot={}", target_dir.to_str().unwrap()));
|
||||
rustflags.push_str(&format!(" --sysroot={}", DIST_DIR.to_path(dirs).to_str().unwrap()));
|
||||
if channel == "release" {
|
||||
build_cmd.arg("--release");
|
||||
rustflags.push_str(" -Zmir-opt-level=3");
|
||||
}
|
||||
if let Some(linker) = linker {
|
||||
use std::fmt::Write;
|
||||
write!(rustflags, " -Clinker={}", linker).unwrap();
|
||||
}
|
||||
build_cmd.env("RUSTFLAGS", rustflags);
|
||||
let mut compiler = Compiler::with_triple(triple.to_owned());
|
||||
compiler.rustflags = rustflags;
|
||||
let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
|
||||
if channel == "release" {
|
||||
build_cmd.arg("--release");
|
||||
}
|
||||
build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
|
||||
spawn_and_wait(build_cmd);
|
||||
|
||||
// Copy all relevant files to the sysroot
|
||||
for entry in
|
||||
fs::read_dir(Path::new("build_sysroot/target").join(triple).join(channel).join("deps"))
|
||||
.unwrap()
|
||||
{
|
||||
for entry in fs::read_dir(build_dir.join("deps")).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
if let Some(ext) = entry.path().extension() {
|
||||
if ext == "rmeta" || ext == "d" || ext == "dSYM" || ext == "clif" {
|
||||
|
|
@ -216,7 +218,7 @@ fn build_clif_sysroot_for_triple(
|
|||
};
|
||||
try_hard_link(
|
||||
entry.path(),
|
||||
target_dir.join("lib").join("rustlib").join(triple).join("lib").join(entry.file_name()),
|
||||
RUSTLIB_DIR.to_path(dirs).join(triple).join("lib").join(entry.file_name()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,20 +8,37 @@ mod abi_cafe;
|
|||
mod build_backend;
|
||||
mod build_sysroot;
|
||||
mod config;
|
||||
mod path;
|
||||
mod prepare;
|
||||
mod rustc_info;
|
||||
mod tests;
|
||||
mod utils;
|
||||
|
||||
const USAGE: &str = r#"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]
|
||||
|
||||
OPTIONS:
|
||||
--sysroot none|clif|llvm
|
||||
Which sysroot libraries to use:
|
||||
`none` will not include any standard library in the sysroot.
|
||||
`clif` will build the standard library using Cranelift.
|
||||
`llvm` will use the pre-compiled standard library of rustc which is compiled with LLVM.
|
||||
|
||||
--out-dir DIR
|
||||
Specify the directory in which the download, build and dist directories are stored.
|
||||
By default this is the working directory.
|
||||
|
||||
--no-unstable-features
|
||||
fSome features are not yet ready for production usage. This option will disable these
|
||||
features. This includes the JIT mode and inline assembly support.
|
||||
"#;
|
||||
|
||||
fn usage() {
|
||||
eprintln!("Usage:");
|
||||
eprintln!(" ./y.rs prepare");
|
||||
eprintln!(
|
||||
" ./y.rs build [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
|
||||
);
|
||||
eprintln!(
|
||||
" ./y.rs test [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
|
||||
);
|
||||
eprintln!("{USAGE}");
|
||||
}
|
||||
|
||||
macro_rules! arg_error {
|
||||
|
|
@ -34,6 +51,7 @@ macro_rules! arg_error {
|
|||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum Command {
|
||||
Prepare,
|
||||
Build,
|
||||
Test,
|
||||
}
|
||||
|
|
@ -48,8 +66,6 @@ pub(crate) enum SysrootKind {
|
|||
pub fn main() {
|
||||
env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
|
||||
env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
|
||||
// The target dir is expected in the default location. Guard against the user changing it.
|
||||
env::set_var("CARGO_TARGET_DIR", "target");
|
||||
|
||||
if is_ci() {
|
||||
// Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
|
||||
|
|
@ -58,13 +74,7 @@ pub fn main() {
|
|||
|
||||
let mut args = env::args().skip(1);
|
||||
let command = match args.next().as_deref() {
|
||||
Some("prepare") => {
|
||||
if args.next().is_some() {
|
||||
arg_error!("./y.rs prepare doesn't expect arguments");
|
||||
}
|
||||
prepare::prepare();
|
||||
process::exit(0);
|
||||
}
|
||||
Some("prepare") => Command::Prepare,
|
||||
Some("build") => Command::Build,
|
||||
Some("test") => Command::Test,
|
||||
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
|
||||
|
|
@ -75,15 +85,15 @@ pub fn main() {
|
|||
}
|
||||
};
|
||||
|
||||
let mut target_dir = PathBuf::from("build");
|
||||
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 {
|
||||
"--target-dir" => {
|
||||
target_dir = PathBuf::from(args.next().unwrap_or_else(|| {
|
||||
arg_error!("--target-dir requires argument");
|
||||
"--out-dir" => {
|
||||
out_dir = PathBuf::from(args.next().unwrap_or_else(|| {
|
||||
arg_error!("--out-dir requires argument");
|
||||
}))
|
||||
}
|
||||
"--debug" => channel = "debug",
|
||||
|
|
@ -101,7 +111,6 @@ pub fn main() {
|
|||
arg => arg_error!("Unexpected argument {}", arg),
|
||||
}
|
||||
}
|
||||
target_dir = std::env::current_dir().unwrap().join(target_dir);
|
||||
|
||||
let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
|
||||
host_triple
|
||||
|
|
@ -122,13 +131,43 @@ pub fn main() {
|
|||
host_triple.clone()
|
||||
};
|
||||
|
||||
let cg_clif_dylib = build_backend::build_backend(channel, &host_triple, use_unstable_features);
|
||||
// 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);
|
||||
}
|
||||
|
||||
let cg_clif_dylib =
|
||||
build_backend::build_backend(&dirs, channel, &host_triple, use_unstable_features);
|
||||
match command {
|
||||
Command::Prepare => {
|
||||
// Handled above
|
||||
}
|
||||
Command::Test => {
|
||||
tests::run_tests(
|
||||
&dirs,
|
||||
channel,
|
||||
sysroot_kind,
|
||||
&target_dir,
|
||||
&cg_clif_dylib,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
|
|
@ -137,7 +176,7 @@ pub fn main() {
|
|||
abi_cafe::run(
|
||||
channel,
|
||||
sysroot_kind,
|
||||
&target_dir,
|
||||
&dirs,
|
||||
&cg_clif_dylib,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
|
|
@ -145,9 +184,9 @@ pub fn main() {
|
|||
}
|
||||
Command::Build => {
|
||||
build_sysroot::build_sysroot(
|
||||
&dirs,
|
||||
channel,
|
||||
sysroot_kind,
|
||||
&target_dir,
|
||||
&cg_clif_dylib,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
|
|
|
|||
70
compiler/rustc_codegen_cranelift/build_system/path.rs
Normal file
70
compiler/rustc_codegen_cranelift/build_system/path.rs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Dirs {
|
||||
pub(crate) source_dir: PathBuf,
|
||||
pub(crate) download_dir: PathBuf,
|
||||
pub(crate) build_dir: PathBuf,
|
||||
pub(crate) dist_dir: PathBuf,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum PathBase {
|
||||
Source,
|
||||
Download,
|
||||
Build,
|
||||
Dist,
|
||||
}
|
||||
|
||||
impl PathBase {
|
||||
fn to_path(self, dirs: &Dirs) -> PathBuf {
|
||||
match self {
|
||||
PathBase::Source => dirs.source_dir.clone(),
|
||||
PathBase::Download => dirs.download_dir.clone(),
|
||||
PathBase::Build => dirs.build_dir.clone(),
|
||||
PathBase::Dist => dirs.dist_dir.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum RelPath {
|
||||
Base(PathBase),
|
||||
Join(&'static RelPath, &'static str),
|
||||
}
|
||||
|
||||
impl RelPath {
|
||||
pub(crate) const SOURCE: RelPath = RelPath::Base(PathBase::Source);
|
||||
pub(crate) const DOWNLOAD: RelPath = RelPath::Base(PathBase::Download);
|
||||
pub(crate) const BUILD: RelPath = RelPath::Base(PathBase::Build);
|
||||
pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist);
|
||||
|
||||
pub(crate) const SCRIPTS: RelPath = RelPath::SOURCE.join("scripts");
|
||||
pub(crate) const BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot");
|
||||
pub(crate) const PATCHES: RelPath = RelPath::SOURCE.join("patches");
|
||||
|
||||
pub(crate) const fn join(&'static self, suffix: &'static str) -> RelPath {
|
||||
RelPath::Join(self, suffix)
|
||||
}
|
||||
|
||||
pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf {
|
||||
match self {
|
||||
RelPath::Base(base) => base.to_path(dirs),
|
||||
RelPath::Join(base, suffix) => base.to_path(dirs).join(suffix),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_exists(&self, dirs: &Dirs) {
|
||||
fs::create_dir_all(self.to_path(dirs)).unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_fresh(&self, dirs: &Dirs) {
|
||||
let path = self.to_path(dirs);
|
||||
if path.exists() {
|
||||
fs::remove_dir_all(&path).unwrap();
|
||||
}
|
||||
fs::create_dir_all(path).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,92 +1,75 @@
|
|||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use super::build_sysroot::{SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
|
||||
use super::utils::{cargo_command, copy_dir_recursively, spawn_and_wait};
|
||||
use super::utils::{copy_dir_recursively, spawn_and_wait, Compiler};
|
||||
|
||||
pub(crate) const ABI_CAFE: GitRepo =
|
||||
GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
|
||||
|
||||
pub(crate) const RAND: GitRepo =
|
||||
GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
|
||||
|
||||
pub(crate) const REGEX: GitRepo =
|
||||
GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
|
||||
|
||||
pub(crate) const PORTABLE_SIMD: GitRepo = GitRepo::github(
|
||||
"rust-lang",
|
||||
"portable-simd",
|
||||
"d5cd4a8112d958bd3a252327e0d069a6363249bd",
|
||||
"portable-simd",
|
||||
);
|
||||
|
||||
pub(crate) const SIMPLE_RAYTRACER: GitRepo = GitRepo::github(
|
||||
"ebobby",
|
||||
"simple-raytracer",
|
||||
"804a7a21b9e673a482797aa289a18ed480e4d813",
|
||||
"<none>",
|
||||
);
|
||||
|
||||
pub(crate) fn prepare() {
|
||||
if Path::new("download").exists() {
|
||||
std::fs::remove_dir_all(Path::new("download")).unwrap();
|
||||
pub(crate) fn prepare(dirs: &Dirs) {
|
||||
if RelPath::DOWNLOAD.to_path(dirs).exists() {
|
||||
std::fs::remove_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
|
||||
}
|
||||
std::fs::create_dir_all(Path::new("download")).unwrap();
|
||||
std::fs::create_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
|
||||
|
||||
prepare_sysroot();
|
||||
prepare_sysroot(dirs);
|
||||
|
||||
// FIXME maybe install this only locally?
|
||||
eprintln!("[INSTALL] hyperfine");
|
||||
Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
|
||||
Command::new("cargo")
|
||||
.arg("install")
|
||||
.arg("hyperfine")
|
||||
.env_remove("CARGO_TARGET_DIR")
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait()
|
||||
.unwrap();
|
||||
|
||||
ABI_CAFE.fetch();
|
||||
RAND.fetch();
|
||||
REGEX.fetch();
|
||||
PORTABLE_SIMD.fetch();
|
||||
SIMPLE_RAYTRACER.fetch();
|
||||
super::abi_cafe::ABI_CAFE_REPO.fetch(dirs);
|
||||
super::tests::RAND_REPO.fetch(dirs);
|
||||
super::tests::REGEX_REPO.fetch(dirs);
|
||||
super::tests::PORTABLE_SIMD_REPO.fetch(dirs);
|
||||
super::tests::SIMPLE_RAYTRACER_REPO.fetch(dirs);
|
||||
|
||||
eprintln!("[LLVM BUILD] simple-raytracer");
|
||||
let build_cmd = cargo_command("cargo", "build", None, &SIMPLE_RAYTRACER.source_dir());
|
||||
let host_compiler = Compiler::host();
|
||||
let build_cmd = super::tests::SIMPLE_RAYTRACER.build(&host_compiler, dirs);
|
||||
spawn_and_wait(build_cmd);
|
||||
fs::copy(
|
||||
SIMPLE_RAYTRACER
|
||||
.source_dir()
|
||||
.join("target")
|
||||
super::tests::SIMPLE_RAYTRACER
|
||||
.target_dir(dirs)
|
||||
.join(&host_compiler.triple)
|
||||
.join("debug")
|
||||
.join(get_file_name("main", "bin")),
|
||||
SIMPLE_RAYTRACER.source_dir().join(get_file_name("raytracer_cg_llvm", "bin")),
|
||||
RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn prepare_sysroot() {
|
||||
fn prepare_sysroot(dirs: &Dirs) {
|
||||
let rustc_path = get_rustc_path();
|
||||
let sysroot_src_orig = rustc_path.parent().unwrap().join("../lib/rustlib/src/rust");
|
||||
let sysroot_src = env::current_dir().unwrap().join("build_sysroot").join("sysroot_src");
|
||||
let sysroot_src = SYSROOT_SRC;
|
||||
|
||||
assert!(sysroot_src_orig.exists());
|
||||
|
||||
if sysroot_src.exists() {
|
||||
fs::remove_dir_all(&sysroot_src).unwrap();
|
||||
}
|
||||
fs::create_dir_all(sysroot_src.join("library")).unwrap();
|
||||
sysroot_src.ensure_fresh(dirs);
|
||||
fs::create_dir_all(sysroot_src.to_path(dirs).join("library")).unwrap();
|
||||
eprintln!("[COPY] sysroot src");
|
||||
copy_dir_recursively(&sysroot_src_orig.join("library"), &sysroot_src.join("library"));
|
||||
copy_dir_recursively(
|
||||
&sysroot_src_orig.join("library"),
|
||||
&sysroot_src.to_path(dirs).join("library"),
|
||||
);
|
||||
|
||||
let rustc_version = get_rustc_version();
|
||||
fs::write(Path::new("build_sysroot").join("rustc_version"), &rustc_version).unwrap();
|
||||
fs::write(SYSROOT_RUSTC_VERSION.to_path(dirs), &rustc_version).unwrap();
|
||||
|
||||
eprintln!("[GIT] init");
|
||||
let mut git_init_cmd = Command::new("git");
|
||||
git_init_cmd.arg("init").arg("-q").current_dir(&sysroot_src);
|
||||
spawn_and_wait(git_init_cmd);
|
||||
init_git_repo(&sysroot_src.to_path(dirs));
|
||||
|
||||
init_git_repo(&sysroot_src);
|
||||
|
||||
apply_patches("sysroot", &sysroot_src);
|
||||
apply_patches(dirs, "sysroot", &sysroot_src.to_path(dirs));
|
||||
}
|
||||
|
||||
pub(crate) struct GitRepo {
|
||||
|
|
@ -100,7 +83,7 @@ enum GitRepoUrl {
|
|||
}
|
||||
|
||||
impl GitRepo {
|
||||
const fn github(
|
||||
pub(crate) const fn github(
|
||||
user: &'static str,
|
||||
repo: &'static str,
|
||||
rev: &'static str,
|
||||
|
|
@ -109,21 +92,25 @@ impl GitRepo {
|
|||
GitRepo { url: GitRepoUrl::Github { user, repo }, rev, patch_name }
|
||||
}
|
||||
|
||||
pub(crate) fn source_dir(&self) -> PathBuf {
|
||||
pub(crate) const fn source_dir(&self) -> RelPath {
|
||||
match self.url {
|
||||
GitRepoUrl::Github { user: _, repo } => {
|
||||
std::env::current_dir().unwrap().join("download").join(repo)
|
||||
}
|
||||
GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo),
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch(&self) {
|
||||
fn fetch(&self, dirs: &Dirs) {
|
||||
match self.url {
|
||||
GitRepoUrl::Github { user, repo } => {
|
||||
clone_repo_shallow_github(&self.source_dir(), user, repo, self.rev);
|
||||
clone_repo_shallow_github(
|
||||
dirs,
|
||||
&self.source_dir().to_path(dirs),
|
||||
user,
|
||||
repo,
|
||||
self.rev,
|
||||
);
|
||||
}
|
||||
}
|
||||
apply_patches(self.patch_name, &self.source_dir());
|
||||
apply_patches(dirs, self.patch_name, &self.source_dir().to_path(dirs));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -142,18 +129,16 @@ fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
|
|||
spawn_and_wait(checkout_cmd);
|
||||
}
|
||||
|
||||
fn clone_repo_shallow_github(download_dir: &Path, user: &str, repo: &str, rev: &str) {
|
||||
fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo: &str, rev: &str) {
|
||||
if cfg!(windows) {
|
||||
// Older windows doesn't have tar or curl by default. Fall back to using git.
|
||||
clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev);
|
||||
return;
|
||||
}
|
||||
|
||||
let downloads_dir = std::env::current_dir().unwrap().join("download");
|
||||
|
||||
let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev);
|
||||
let archive_file = downloads_dir.join(format!("{}.tar.gz", rev));
|
||||
let archive_dir = downloads_dir.join(format!("{}-{}", repo, rev));
|
||||
let archive_file = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}.tar.gz", rev));
|
||||
let archive_dir = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}-{}", repo, rev));
|
||||
|
||||
eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url);
|
||||
|
||||
|
|
@ -169,7 +154,7 @@ fn clone_repo_shallow_github(download_dir: &Path, user: &str, repo: &str, rev: &
|
|||
|
||||
// Unpack tar archive
|
||||
let mut unpack_cmd = Command::new("tar");
|
||||
unpack_cmd.arg("xf").arg(&archive_file).current_dir(downloads_dir);
|
||||
unpack_cmd.arg("xf").arg(&archive_file).current_dir(RelPath::DOWNLOAD.to_path(dirs));
|
||||
spawn_and_wait(unpack_cmd);
|
||||
|
||||
// Rename unpacked dir to the expected name
|
||||
|
|
@ -191,12 +176,21 @@ fn init_git_repo(repo_dir: &Path) {
|
|||
spawn_and_wait(git_add_cmd);
|
||||
|
||||
let mut git_commit_cmd = Command::new("git");
|
||||
git_commit_cmd.arg("commit").arg("-m").arg("Initial commit").arg("-q").current_dir(repo_dir);
|
||||
git_commit_cmd
|
||||
.arg("-c")
|
||||
.arg("user.name=Dummy")
|
||||
.arg("-c")
|
||||
.arg("user.email=dummy@example.com")
|
||||
.arg("commit")
|
||||
.arg("-m")
|
||||
.arg("Initial commit")
|
||||
.arg("-q")
|
||||
.current_dir(repo_dir);
|
||||
spawn_and_wait(git_commit_cmd);
|
||||
}
|
||||
|
||||
fn get_patches(source_dir: &Path, crate_name: &str) -> Vec<PathBuf> {
|
||||
let mut patches: Vec<_> = fs::read_dir(source_dir.join("patches"))
|
||||
fn get_patches(dirs: &Dirs, crate_name: &str) -> Vec<PathBuf> {
|
||||
let mut patches: Vec<_> = fs::read_dir(RelPath::PATCHES.to_path(dirs))
|
||||
.unwrap()
|
||||
.map(|entry| entry.unwrap().path())
|
||||
.filter(|path| path.extension() == Some(OsStr::new("patch")))
|
||||
|
|
@ -215,19 +209,27 @@ fn get_patches(source_dir: &Path, crate_name: &str) -> Vec<PathBuf> {
|
|||
patches
|
||||
}
|
||||
|
||||
fn apply_patches(crate_name: &str, target_dir: &Path) {
|
||||
fn apply_patches(dirs: &Dirs, crate_name: &str, target_dir: &Path) {
|
||||
if crate_name == "<none>" {
|
||||
return;
|
||||
}
|
||||
|
||||
for patch in get_patches(&std::env::current_dir().unwrap(), crate_name) {
|
||||
for patch in get_patches(dirs, crate_name) {
|
||||
eprintln!(
|
||||
"[PATCH] {:?} <- {:?}",
|
||||
target_dir.file_name().unwrap(),
|
||||
patch.file_name().unwrap()
|
||||
);
|
||||
let mut apply_patch_cmd = Command::new("git");
|
||||
apply_patch_cmd.arg("am").arg(patch).arg("-q").current_dir(target_dir);
|
||||
apply_patch_cmd
|
||||
.arg("-c")
|
||||
.arg("user.name=Dummy")
|
||||
.arg("-c")
|
||||
.arg("user.email=dummy@example.com")
|
||||
.arg("am")
|
||||
.arg(patch)
|
||||
.arg("-q")
|
||||
.current_dir(target_dir);
|
||||
spawn_and_wait(apply_patch_cmd);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,16 @@ pub(crate) fn get_host_triple() -> String {
|
|||
.to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn get_cargo_path() -> PathBuf {
|
||||
let cargo_path = Command::new("rustup")
|
||||
.stderr(Stdio::inherit())
|
||||
.args(&["which", "cargo"])
|
||||
.output()
|
||||
.unwrap()
|
||||
.stdout;
|
||||
Path::new(String::from_utf8(cargo_path).unwrap().trim()).to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn get_rustc_path() -> PathBuf {
|
||||
let rustc_path = Command::new("rustup")
|
||||
.stderr(Stdio::inherit())
|
||||
|
|
@ -33,6 +43,16 @@ pub(crate) fn get_rustc_path() -> PathBuf {
|
|||
Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn get_rustdoc_path() -> PathBuf {
|
||||
let rustc_path = Command::new("rustup")
|
||||
.stderr(Stdio::inherit())
|
||||
.args(&["which", "rustdoc"])
|
||||
.output()
|
||||
.unwrap()
|
||||
.stdout;
|
||||
Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn get_default_sysroot() -> PathBuf {
|
||||
let default_sysroot = Command::new("rustc")
|
||||
.stderr(Stdio::inherit())
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
use super::build_sysroot;
|
||||
use super::config;
|
||||
use super::prepare;
|
||||
use super::rustc_info::get_wrapper_file_name;
|
||||
use super::utils::{cargo_command, hyperfine_command, spawn_and_wait, spawn_and_wait_with_input};
|
||||
use build_system::SysrootKind;
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::prepare::GitRepo;
|
||||
use super::rustc_info::{get_cargo_path, get_wrapper_file_name};
|
||||
use super::utils::{
|
||||
hyperfine_command, spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler,
|
||||
};
|
||||
use super::SysrootKind;
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
|
||||
|
||||
struct TestCase {
|
||||
config: &'static str,
|
||||
func: &'static dyn Fn(&TestRunner),
|
||||
|
|
@ -30,7 +35,7 @@ const NO_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--crate-type",
|
||||
"lib,dylib",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
}),
|
||||
TestCase::new("build.example", &|runner| {
|
||||
|
|
@ -39,7 +44,7 @@ const NO_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--crate-type",
|
||||
"lib",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
}),
|
||||
TestCase::new("jit.mini_core_hello_world", &|runner| {
|
||||
|
|
@ -51,7 +56,7 @@ const NO_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--cfg",
|
||||
"jit",
|
||||
"--target",
|
||||
&runner.host_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
|
||||
spawn_and_wait(jit_cmd);
|
||||
|
|
@ -65,7 +70,7 @@ const NO_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--cfg",
|
||||
"jit",
|
||||
"--target",
|
||||
&runner.host_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
|
||||
spawn_and_wait(jit_cmd);
|
||||
|
|
@ -79,7 +84,7 @@ const NO_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"bin",
|
||||
"-g",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]);
|
||||
}),
|
||||
|
|
@ -94,7 +99,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []);
|
||||
}),
|
||||
|
|
@ -106,7 +111,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("issue_91827_extern_types", []);
|
||||
}),
|
||||
|
|
@ -116,7 +121,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--crate-type",
|
||||
"lib",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
}),
|
||||
TestCase::new("aot.alloc_example", &|runner| {
|
||||
|
|
@ -125,7 +130,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("alloc_example", []);
|
||||
}),
|
||||
|
|
@ -136,7 +141,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"-Cprefer-dynamic",
|
||||
"example/std_example.rs",
|
||||
"--target",
|
||||
&runner.host_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
|
||||
eprintln!("[JIT-lazy] std_example");
|
||||
|
|
@ -146,7 +151,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"-Cprefer-dynamic",
|
||||
"example/std_example.rs",
|
||||
"--target",
|
||||
&runner.host_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
}),
|
||||
TestCase::new("aot.std_example", &|runner| {
|
||||
|
|
@ -155,7 +160,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("std_example", ["arg"]);
|
||||
}),
|
||||
|
|
@ -167,7 +172,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("dst_field_align", []);
|
||||
}),
|
||||
|
|
@ -178,7 +183,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"bin",
|
||||
"-Cpanic=abort",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("subslice-patterns-const-eval", []);
|
||||
}),
|
||||
|
|
@ -189,7 +194,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"bin",
|
||||
"-Cpanic=abort",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("track-caller-attribute", []);
|
||||
}),
|
||||
|
|
@ -200,7 +205,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"bin",
|
||||
"-Cpanic=abort",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("float-minmax-pass", []);
|
||||
}),
|
||||
|
|
@ -210,205 +215,252 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_triple,
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("mod_bench", []);
|
||||
}),
|
||||
TestCase::new("aot.issue-72793", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/issue-72793.rs",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("issue-72793", []);
|
||||
}),
|
||||
];
|
||||
|
||||
pub(crate) static RAND_REPO: GitRepo =
|
||||
GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
|
||||
|
||||
static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
|
||||
|
||||
pub(crate) static REGEX_REPO: GitRepo =
|
||||
GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
|
||||
|
||||
static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex");
|
||||
|
||||
pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
|
||||
"rust-lang",
|
||||
"portable-simd",
|
||||
"d5cd4a8112d958bd3a252327e0d069a6363249bd",
|
||||
"portable-simd",
|
||||
);
|
||||
|
||||
static PORTABLE_SIMD: CargoProject =
|
||||
CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable_simd");
|
||||
|
||||
pub(crate) static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
|
||||
"ebobby",
|
||||
"simple-raytracer",
|
||||
"804a7a21b9e673a482797aa289a18ed480e4d813",
|
||||
"<none>",
|
||||
);
|
||||
|
||||
pub(crate) static SIMPLE_RAYTRACER: CargoProject =
|
||||
CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer");
|
||||
|
||||
static LIBCORE_TESTS: CargoProject =
|
||||
CargoProject::new(&RelPath::BUILD_SYSROOT.join("sysroot_src/library/core/tests"), "core_tests");
|
||||
|
||||
const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
|
||||
TestCase::new("test.rust-random/rand", &|runner| {
|
||||
runner.in_dir(prepare::RAND.source_dir(), |runner| {
|
||||
runner.run_cargo("clean", []);
|
||||
spawn_and_wait(RAND.clean(&runner.target_compiler.cargo, &runner.dirs));
|
||||
|
||||
if runner.host_triple == runner.target_triple {
|
||||
eprintln!("[TEST] rust-random/rand");
|
||||
runner.run_cargo("test", ["--workspace"]);
|
||||
} else {
|
||||
eprintln!("[AOT] rust-random/rand");
|
||||
runner.run_cargo("build", ["--workspace", "--tests"]);
|
||||
}
|
||||
});
|
||||
if runner.is_native {
|
||||
eprintln!("[TEST] rust-random/rand");
|
||||
let mut test_cmd = RAND.test(&runner.target_compiler, &runner.dirs);
|
||||
test_cmd.arg("--workspace");
|
||||
spawn_and_wait(test_cmd);
|
||||
} else {
|
||||
eprintln!("[AOT] rust-random/rand");
|
||||
let mut build_cmd = RAND.build(&runner.target_compiler, &runner.dirs);
|
||||
build_cmd.arg("--workspace").arg("--tests");
|
||||
spawn_and_wait(build_cmd);
|
||||
}
|
||||
}),
|
||||
TestCase::new("bench.simple-raytracer", &|runner| {
|
||||
runner.in_dir(prepare::SIMPLE_RAYTRACER.source_dir(), |runner| {
|
||||
let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
|
||||
let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
|
||||
|
||||
if runner.host_triple == runner.target_triple {
|
||||
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
|
||||
let prepare = runner.cargo_command("clean", []);
|
||||
if runner.is_native {
|
||||
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
|
||||
let cargo_clif = RelPath::DIST
|
||||
.to_path(&runner.dirs)
|
||||
.join(get_wrapper_file_name("cargo-clif", "bin"));
|
||||
let manifest_path = SIMPLE_RAYTRACER.manifest_path(&runner.dirs);
|
||||
let target_dir = SIMPLE_RAYTRACER.target_dir(&runner.dirs);
|
||||
|
||||
let llvm_build_cmd = cargo_command("cargo", "build", None, Path::new("."));
|
||||
let clean_cmd = format!(
|
||||
"cargo clean --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
let llvm_build_cmd = format!(
|
||||
"cargo build --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
let clif_build_cmd = format!(
|
||||
"{cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
cargo_clif = cargo_clif.display(),
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
|
||||
let cargo_clif = runner
|
||||
.root_dir
|
||||
.clone()
|
||||
.join("build")
|
||||
.join(get_wrapper_file_name("cargo-clif", "bin"));
|
||||
let clif_build_cmd = cargo_command(cargo_clif, "build", None, Path::new("."));
|
||||
let bench_compile =
|
||||
hyperfine_command(1, run_runs, Some(&clean_cmd), &llvm_build_cmd, &clif_build_cmd);
|
||||
|
||||
let bench_compile =
|
||||
hyperfine_command(1, run_runs, Some(prepare), llvm_build_cmd, clif_build_cmd);
|
||||
spawn_and_wait(bench_compile);
|
||||
|
||||
spawn_and_wait(bench_compile);
|
||||
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
|
||||
fs::copy(
|
||||
target_dir.join("debug").join("main"),
|
||||
RelPath::BUILD.to_path(&runner.dirs).join("raytracer_cg_clif"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
|
||||
fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif"))
|
||||
.unwrap();
|
||||
|
||||
let bench_run = hyperfine_command(
|
||||
0,
|
||||
run_runs,
|
||||
None,
|
||||
Command::new("./raytracer_cg_llvm"),
|
||||
Command::new("./raytracer_cg_clif"),
|
||||
);
|
||||
spawn_and_wait(bench_run);
|
||||
} else {
|
||||
runner.run_cargo("clean", []);
|
||||
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
|
||||
eprintln!("[COMPILE] ebobby/simple-raytracer");
|
||||
runner.run_cargo("build", []);
|
||||
eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
|
||||
}
|
||||
});
|
||||
let mut bench_run =
|
||||
hyperfine_command(0, run_runs, None, "./raytracer_cg_llvm", "./raytracer_cg_clif");
|
||||
bench_run.current_dir(RelPath::BUILD.to_path(&runner.dirs));
|
||||
spawn_and_wait(bench_run);
|
||||
} else {
|
||||
spawn_and_wait(SIMPLE_RAYTRACER.clean(&runner.target_compiler.cargo, &runner.dirs));
|
||||
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
|
||||
eprintln!("[COMPILE] ebobby/simple-raytracer");
|
||||
spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs));
|
||||
eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
|
||||
}
|
||||
}),
|
||||
TestCase::new("test.libcore", &|runner| {
|
||||
runner.in_dir(
|
||||
std::env::current_dir()
|
||||
.unwrap()
|
||||
.join("build_sysroot")
|
||||
.join("sysroot_src")
|
||||
.join("library")
|
||||
.join("core")
|
||||
.join("tests"),
|
||||
|runner| {
|
||||
runner.run_cargo("clean", []);
|
||||
spawn_and_wait(LIBCORE_TESTS.clean(&runner.host_compiler.cargo, &runner.dirs));
|
||||
|
||||
if runner.host_triple == runner.target_triple {
|
||||
runner.run_cargo("test", []);
|
||||
} else {
|
||||
eprintln!("Cross-Compiling: Not running tests");
|
||||
runner.run_cargo("build", ["--tests"]);
|
||||
}
|
||||
},
|
||||
);
|
||||
if runner.is_native {
|
||||
spawn_and_wait(LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs));
|
||||
} else {
|
||||
eprintln!("Cross-Compiling: Not running tests");
|
||||
let mut build_cmd = LIBCORE_TESTS.build(&runner.target_compiler, &runner.dirs);
|
||||
build_cmd.arg("--tests");
|
||||
spawn_and_wait(build_cmd);
|
||||
}
|
||||
}),
|
||||
TestCase::new("test.regex-shootout-regex-dna", &|runner| {
|
||||
runner.in_dir(prepare::REGEX.source_dir(), |runner| {
|
||||
runner.run_cargo("clean", []);
|
||||
spawn_and_wait(REGEX.clean(&runner.target_compiler.cargo, &runner.dirs));
|
||||
|
||||
// newer aho_corasick versions throw a deprecation warning
|
||||
let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
|
||||
// newer aho_corasick versions throw a deprecation warning
|
||||
let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
|
||||
|
||||
let mut build_cmd = runner.cargo_command("build", ["--example", "shootout-regex-dna"]);
|
||||
build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
|
||||
spawn_and_wait(build_cmd);
|
||||
let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
|
||||
build_cmd.arg("--example").arg("shootout-regex-dna");
|
||||
build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
|
||||
spawn_and_wait(build_cmd);
|
||||
|
||||
if runner.host_triple == runner.target_triple {
|
||||
let mut run_cmd = runner.cargo_command("run", ["--example", "shootout-regex-dna"]);
|
||||
run_cmd.env("RUSTFLAGS", lint_rust_flags);
|
||||
if runner.is_native {
|
||||
let mut run_cmd = REGEX.run(&runner.target_compiler, &runner.dirs);
|
||||
run_cmd.arg("--example").arg("shootout-regex-dna");
|
||||
run_cmd.env("RUSTFLAGS", lint_rust_flags);
|
||||
|
||||
let input =
|
||||
fs::read_to_string(PathBuf::from("examples/regexdna-input.txt")).unwrap();
|
||||
let expected_path = PathBuf::from("examples/regexdna-output.txt");
|
||||
let expected = fs::read_to_string(&expected_path).unwrap();
|
||||
let input = fs::read_to_string(
|
||||
REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"),
|
||||
)
|
||||
.unwrap();
|
||||
let expected_path =
|
||||
REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt");
|
||||
let expected = fs::read_to_string(&expected_path).unwrap();
|
||||
|
||||
let output = spawn_and_wait_with_input(run_cmd, input);
|
||||
// Make sure `[codegen mono items] start` doesn't poison the diff
|
||||
let output = output
|
||||
.lines()
|
||||
.filter(|line| !line.contains("codegen mono items"))
|
||||
.chain(Some("")) // This just adds the trailing newline
|
||||
.collect::<Vec<&str>>()
|
||||
.join("\r\n");
|
||||
let output = spawn_and_wait_with_input(run_cmd, input);
|
||||
// Make sure `[codegen mono items] start` doesn't poison the diff
|
||||
let output = output
|
||||
.lines()
|
||||
.filter(|line| !line.contains("codegen mono items"))
|
||||
.chain(Some("")) // This just adds the trailing newline
|
||||
.collect::<Vec<&str>>()
|
||||
.join("\r\n");
|
||||
|
||||
let output_matches = expected.lines().eq(output.lines());
|
||||
if !output_matches {
|
||||
let res_path = PathBuf::from("res.txt");
|
||||
fs::write(&res_path, &output).unwrap();
|
||||
let output_matches = expected.lines().eq(output.lines());
|
||||
if !output_matches {
|
||||
let res_path = REGEX.source_dir(&runner.dirs).join("res.txt");
|
||||
fs::write(&res_path, &output).unwrap();
|
||||
|
||||
if cfg!(windows) {
|
||||
println!("Output files don't match!");
|
||||
println!("Expected Output:\n{}", expected);
|
||||
println!("Actual Output:\n{}", output);
|
||||
} else {
|
||||
let mut diff = Command::new("diff");
|
||||
diff.arg("-u");
|
||||
diff.arg(res_path);
|
||||
diff.arg(expected_path);
|
||||
spawn_and_wait(diff);
|
||||
}
|
||||
|
||||
std::process::exit(1);
|
||||
if cfg!(windows) {
|
||||
println!("Output files don't match!");
|
||||
println!("Expected Output:\n{}", expected);
|
||||
println!("Actual Output:\n{}", output);
|
||||
} else {
|
||||
let mut diff = Command::new("diff");
|
||||
diff.arg("-u");
|
||||
diff.arg(res_path);
|
||||
diff.arg(expected_path);
|
||||
spawn_and_wait(diff);
|
||||
}
|
||||
|
||||
std::process::exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}),
|
||||
TestCase::new("test.regex", &|runner| {
|
||||
runner.in_dir(prepare::REGEX.source_dir(), |runner| {
|
||||
runner.run_cargo("clean", []);
|
||||
spawn_and_wait(REGEX.clean(&runner.host_compiler.cargo, &runner.dirs));
|
||||
|
||||
// newer aho_corasick versions throw a deprecation warning
|
||||
let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
|
||||
// newer aho_corasick versions throw a deprecation warning
|
||||
let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
|
||||
|
||||
if runner.host_triple == runner.target_triple {
|
||||
let mut run_cmd = runner.cargo_command(
|
||||
"test",
|
||||
[
|
||||
"--tests",
|
||||
"--",
|
||||
"--exclude-should-panic",
|
||||
"--test-threads",
|
||||
"1",
|
||||
"-Zunstable-options",
|
||||
"-q",
|
||||
],
|
||||
);
|
||||
run_cmd.env("RUSTFLAGS", lint_rust_flags);
|
||||
spawn_and_wait(run_cmd);
|
||||
} else {
|
||||
eprintln!("Cross-Compiling: Not running tests");
|
||||
let mut build_cmd =
|
||||
runner.cargo_command("build", ["--tests", "--target", &runner.target_triple]);
|
||||
build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
|
||||
spawn_and_wait(build_cmd);
|
||||
}
|
||||
});
|
||||
if runner.is_native {
|
||||
let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
|
||||
run_cmd.args([
|
||||
"--tests",
|
||||
"--",
|
||||
"--exclude-should-panic",
|
||||
"--test-threads",
|
||||
"1",
|
||||
"-Zunstable-options",
|
||||
"-q",
|
||||
]);
|
||||
run_cmd.env("RUSTFLAGS", lint_rust_flags);
|
||||
spawn_and_wait(run_cmd);
|
||||
} else {
|
||||
eprintln!("Cross-Compiling: Not running tests");
|
||||
let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
|
||||
build_cmd.arg("--tests");
|
||||
build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
|
||||
spawn_and_wait(build_cmd);
|
||||
}
|
||||
}),
|
||||
TestCase::new("test.portable-simd", &|runner| {
|
||||
runner.in_dir(prepare::PORTABLE_SIMD.source_dir(), |runner| {
|
||||
runner.run_cargo("clean", []);
|
||||
runner.run_cargo("build", ["--all-targets", "--target", &runner.target_triple]);
|
||||
spawn_and_wait(PORTABLE_SIMD.clean(&runner.host_compiler.cargo, &runner.dirs));
|
||||
|
||||
if runner.host_triple == runner.target_triple {
|
||||
runner.run_cargo("test", ["-q"]);
|
||||
}
|
||||
});
|
||||
let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs);
|
||||
build_cmd.arg("--all-targets");
|
||||
spawn_and_wait(build_cmd);
|
||||
|
||||
if runner.is_native {
|
||||
let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs);
|
||||
test_cmd.arg("-q");
|
||||
spawn_and_wait(test_cmd);
|
||||
}
|
||||
}),
|
||||
];
|
||||
|
||||
pub(crate) fn run_tests(
|
||||
dirs: &Dirs,
|
||||
channel: &str,
|
||||
sysroot_kind: SysrootKind,
|
||||
target_dir: &Path,
|
||||
cg_clif_dylib: &Path,
|
||||
host_triple: &str,
|
||||
target_triple: &str,
|
||||
) {
|
||||
let runner = TestRunner::new(host_triple.to_string(), target_triple.to_string());
|
||||
let runner = TestRunner::new(dirs.clone(), host_triple.to_string(), target_triple.to_string());
|
||||
|
||||
if config::get_bool("testsuite.no_sysroot") {
|
||||
build_sysroot::build_sysroot(
|
||||
dirs,
|
||||
channel,
|
||||
SysrootKind::None,
|
||||
&target_dir,
|
||||
cg_clif_dylib,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
);
|
||||
|
||||
let _ = fs::remove_dir_all(Path::new("target").join("out"));
|
||||
BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
|
||||
runner.run_testsuite(NO_SYSROOT_SUITE);
|
||||
} else {
|
||||
eprintln!("[SKIP] no_sysroot tests");
|
||||
|
|
@ -419,9 +471,9 @@ pub(crate) fn run_tests(
|
|||
|
||||
if run_base_sysroot || run_extended_sysroot {
|
||||
build_sysroot::build_sysroot(
|
||||
dirs,
|
||||
channel,
|
||||
sysroot_kind,
|
||||
&target_dir,
|
||||
cg_clif_dylib,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
|
|
@ -442,40 +494,50 @@ pub(crate) fn run_tests(
|
|||
}
|
||||
|
||||
struct TestRunner {
|
||||
root_dir: PathBuf,
|
||||
out_dir: PathBuf,
|
||||
is_native: bool,
|
||||
jit_supported: bool,
|
||||
rust_flags: String,
|
||||
run_wrapper: Vec<String>,
|
||||
host_triple: String,
|
||||
target_triple: String,
|
||||
dirs: Dirs,
|
||||
host_compiler: Compiler,
|
||||
target_compiler: Compiler,
|
||||
}
|
||||
|
||||
impl TestRunner {
|
||||
pub fn new(host_triple: String, target_triple: String) -> Self {
|
||||
let root_dir = env::current_dir().unwrap();
|
||||
|
||||
let mut out_dir = root_dir.clone();
|
||||
out_dir.push("target");
|
||||
out_dir.push("out");
|
||||
|
||||
pub fn new(dirs: Dirs, host_triple: String, target_triple: String) -> Self {
|
||||
let is_native = host_triple == target_triple;
|
||||
let jit_supported =
|
||||
target_triple.contains("x86_64") && is_native && !host_triple.contains("windows");
|
||||
|
||||
let mut rust_flags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
|
||||
let mut run_wrapper = Vec::new();
|
||||
let rustc_clif =
|
||||
RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustc-clif", "bin"));
|
||||
let rustdoc_clif =
|
||||
RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustdoc-clif", "bin"));
|
||||
|
||||
let mut rustflags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
|
||||
let mut runner = vec![];
|
||||
|
||||
if !is_native {
|
||||
match target_triple.as_str() {
|
||||
"aarch64-unknown-linux-gnu" => {
|
||||
// We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
|
||||
rust_flags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rust_flags);
|
||||
run_wrapper = vec!["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"];
|
||||
rustflags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rustflags);
|
||||
runner = vec![
|
||||
"qemu-aarch64".to_owned(),
|
||||
"-L".to_owned(),
|
||||
"/usr/aarch64-linux-gnu".to_owned(),
|
||||
];
|
||||
}
|
||||
"s390x-unknown-linux-gnu" => {
|
||||
// We are cross-compiling for s390x. Use the correct linker and run tests in qemu.
|
||||
rustflags = format!("-Clinker=s390x-linux-gnu-gcc{}", rustflags);
|
||||
runner = vec![
|
||||
"qemu-s390x".to_owned(),
|
||||
"-L".to_owned(),
|
||||
"/usr/s390x-linux-gnu".to_owned(),
|
||||
];
|
||||
}
|
||||
"x86_64-pc-windows-gnu" => {
|
||||
// We are cross-compiling for Windows. Run tests in wine.
|
||||
run_wrapper = vec!["wine"];
|
||||
runner = vec!["wine".to_owned()];
|
||||
}
|
||||
_ => {
|
||||
println!("Unknown non-native platform");
|
||||
|
|
@ -484,19 +546,31 @@ impl TestRunner {
|
|||
}
|
||||
|
||||
// FIXME fix `#[linkage = "extern_weak"]` without this
|
||||
if host_triple.contains("darwin") {
|
||||
rust_flags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rust_flags);
|
||||
if target_triple.contains("darwin") {
|
||||
rustflags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rustflags);
|
||||
}
|
||||
|
||||
Self {
|
||||
root_dir,
|
||||
out_dir,
|
||||
jit_supported,
|
||||
rust_flags,
|
||||
run_wrapper: run_wrapper.iter().map(|s| s.to_string()).collect(),
|
||||
host_triple,
|
||||
target_triple,
|
||||
}
|
||||
let host_compiler = Compiler {
|
||||
cargo: get_cargo_path(),
|
||||
rustc: rustc_clif.clone(),
|
||||
rustdoc: rustdoc_clif.clone(),
|
||||
rustflags: String::new(),
|
||||
rustdocflags: String::new(),
|
||||
triple: host_triple,
|
||||
runner: vec![],
|
||||
};
|
||||
|
||||
let target_compiler = Compiler {
|
||||
cargo: get_cargo_path(),
|
||||
rustc: rustc_clif,
|
||||
rustdoc: rustdoc_clif,
|
||||
rustflags: rustflags.clone(),
|
||||
rustdocflags: rustflags,
|
||||
triple: target_triple,
|
||||
runner,
|
||||
};
|
||||
|
||||
Self { is_native, jit_supported, dirs, host_compiler, target_compiler }
|
||||
}
|
||||
|
||||
pub fn run_testsuite(&self, tests: &[TestCase]) {
|
||||
|
|
@ -516,29 +590,18 @@ impl TestRunner {
|
|||
}
|
||||
}
|
||||
|
||||
fn in_dir(&self, new: impl AsRef<Path>, callback: impl FnOnce(&TestRunner)) {
|
||||
let current = env::current_dir().unwrap();
|
||||
|
||||
env::set_current_dir(new).unwrap();
|
||||
callback(self);
|
||||
env::set_current_dir(current).unwrap();
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn rustc_command<I, S>(&self, args: I) -> Command
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: AsRef<OsStr>,
|
||||
{
|
||||
let mut rustc_clif = self.root_dir.clone();
|
||||
rustc_clif.push("build");
|
||||
rustc_clif.push(get_wrapper_file_name("rustc-clif", "bin"));
|
||||
|
||||
let mut cmd = Command::new(rustc_clif);
|
||||
cmd.args(self.rust_flags.split_whitespace());
|
||||
let mut cmd = Command::new(&self.target_compiler.rustc);
|
||||
cmd.args(self.target_compiler.rustflags.split_whitespace());
|
||||
cmd.arg("-L");
|
||||
cmd.arg(format!("crate={}", self.out_dir.display()));
|
||||
cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
|
||||
cmd.arg("--out-dir");
|
||||
cmd.arg(format!("{}", self.out_dir.display()));
|
||||
cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
|
||||
cmd.arg("-Cdebuginfo=2");
|
||||
cmd.args(args);
|
||||
cmd
|
||||
|
|
@ -559,15 +622,13 @@ impl TestRunner {
|
|||
let mut full_cmd = vec![];
|
||||
|
||||
// Prepend the RUN_WRAPPER's
|
||||
if !self.run_wrapper.is_empty() {
|
||||
full_cmd.extend(self.run_wrapper.iter().cloned());
|
||||
if !self.target_compiler.runner.is_empty() {
|
||||
full_cmd.extend(self.target_compiler.runner.iter().cloned());
|
||||
}
|
||||
|
||||
full_cmd.push({
|
||||
let mut out_path = self.out_dir.clone();
|
||||
out_path.push(name);
|
||||
out_path.to_str().unwrap().to_string()
|
||||
});
|
||||
full_cmd.push(
|
||||
BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(),
|
||||
);
|
||||
|
||||
for arg in args.into_iter() {
|
||||
full_cmd.push(arg.to_string());
|
||||
|
|
@ -581,30 +642,4 @@ impl TestRunner {
|
|||
|
||||
spawn_and_wait(cmd);
|
||||
}
|
||||
|
||||
fn cargo_command<'a, I>(&self, subcommand: &str, args: I) -> Command
|
||||
where
|
||||
I: IntoIterator<Item = &'a str>,
|
||||
{
|
||||
let mut cargo_clif = self.root_dir.clone();
|
||||
cargo_clif.push("build");
|
||||
cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin"));
|
||||
|
||||
let mut cmd = cargo_command(
|
||||
cargo_clif,
|
||||
subcommand,
|
||||
if subcommand == "clean" { None } else { Some(&self.target_triple) },
|
||||
Path::new("."),
|
||||
);
|
||||
cmd.args(args);
|
||||
cmd.env("RUSTFLAGS", &self.rust_flags);
|
||||
cmd
|
||||
}
|
||||
|
||||
fn run_cargo<'a, I>(&self, subcommand: &str, args: I)
|
||||
where
|
||||
I: IntoIterator<Item = &'a str>,
|
||||
{
|
||||
spawn_and_wait(self.cargo_command(subcommand, args));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,138 @@
|
|||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command, Stdio};
|
||||
|
||||
pub(crate) fn cargo_command(
|
||||
cargo: impl AsRef<Path>,
|
||||
subcommand: &str,
|
||||
triple: Option<&str>,
|
||||
source_dir: &Path,
|
||||
) -> Command {
|
||||
let mut cmd = Command::new(cargo.as_ref());
|
||||
cmd.arg(subcommand)
|
||||
.arg("--manifest-path")
|
||||
.arg(source_dir.join("Cargo.toml"))
|
||||
.arg("--target-dir")
|
||||
.arg(source_dir.join("target"));
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::rustc_info::{get_cargo_path, get_host_triple, get_rustc_path, get_rustdoc_path};
|
||||
|
||||
if let Some(triple) = triple {
|
||||
cmd.arg("--target").arg(triple);
|
||||
}
|
||||
|
||||
cmd
|
||||
pub(crate) struct Compiler {
|
||||
pub(crate) cargo: PathBuf,
|
||||
pub(crate) rustc: PathBuf,
|
||||
pub(crate) rustdoc: PathBuf,
|
||||
pub(crate) rustflags: String,
|
||||
pub(crate) rustdocflags: String,
|
||||
pub(crate) triple: String,
|
||||
pub(crate) runner: Vec<String>,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
pub(crate) fn host() -> Compiler {
|
||||
Compiler {
|
||||
cargo: get_cargo_path(),
|
||||
rustc: get_rustc_path(),
|
||||
rustdoc: get_rustdoc_path(),
|
||||
rustflags: String::new(),
|
||||
rustdocflags: String::new(),
|
||||
triple: get_host_triple(),
|
||||
runner: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn 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) struct CargoProject {
|
||||
source: &'static RelPath,
|
||||
target: &'static str,
|
||||
}
|
||||
|
||||
impl CargoProject {
|
||||
pub(crate) const fn new(path: &'static RelPath, target: &'static str) -> CargoProject {
|
||||
CargoProject { source: path, target }
|
||||
}
|
||||
|
||||
pub(crate) fn source_dir(&self, dirs: &Dirs) -> PathBuf {
|
||||
self.source.to_path(dirs)
|
||||
}
|
||||
|
||||
pub(crate) fn manifest_path(&self, dirs: &Dirs) -> PathBuf {
|
||||
self.source_dir(dirs).join("Cargo.toml")
|
||||
}
|
||||
|
||||
pub(crate) fn target_dir(&self, dirs: &Dirs) -> PathBuf {
|
||||
RelPath::BUILD.join(self.target).to_path(dirs)
|
||||
}
|
||||
|
||||
fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command {
|
||||
let mut cmd = Command::new(cargo);
|
||||
|
||||
cmd.arg(command)
|
||||
.arg("--manifest-path")
|
||||
.arg(self.manifest_path(dirs))
|
||||
.arg("--target-dir")
|
||||
.arg(self.target_dir(dirs));
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
fn build_cmd(&self, command: &str, compiler: &Compiler, dirs: &Dirs) -> Command {
|
||||
let mut cmd = self.base_cmd(command, &compiler.cargo, dirs);
|
||||
|
||||
cmd.arg("--target").arg(&compiler.triple);
|
||||
|
||||
cmd.env("RUSTC", &compiler.rustc);
|
||||
cmd.env("RUSTDOC", &compiler.rustdoc);
|
||||
cmd.env("RUSTFLAGS", &compiler.rustflags);
|
||||
cmd.env("RUSTDOCFLAGS", &compiler.rustdocflags);
|
||||
if !compiler.runner.is_empty() {
|
||||
cmd.env(
|
||||
format!("CARGO_TARGET_{}_RUNNER", compiler.triple.to_uppercase().replace('-', "_")),
|
||||
compiler.runner.join(" "),
|
||||
);
|
||||
}
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn fetch(&self, cargo: impl AsRef<Path>, dirs: &Dirs) -> Command {
|
||||
let mut cmd = Command::new(cargo.as_ref());
|
||||
|
||||
cmd.arg("fetch").arg("--manifest-path").arg(self.manifest_path(dirs));
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn clean(&self, cargo: &Path, dirs: &Dirs) -> Command {
|
||||
self.base_cmd("clean", cargo, dirs)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn build(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
|
||||
self.build_cmd("build", compiler, dirs)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn test(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
|
||||
self.build_cmd("test", compiler, dirs)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn run(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
|
||||
self.build_cmd("run", compiler, dirs)
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn hyperfine_command(
|
||||
warmup: u64,
|
||||
runs: u64,
|
||||
prepare: Option<Command>,
|
||||
a: Command,
|
||||
b: Command,
|
||||
prepare: Option<&str>,
|
||||
a: &str,
|
||||
b: &str,
|
||||
) -> Command {
|
||||
let mut bench = Command::new("hyperfine");
|
||||
|
||||
|
|
@ -42,10 +145,10 @@ pub(crate) fn hyperfine_command(
|
|||
}
|
||||
|
||||
if let Some(prepare) = prepare {
|
||||
bench.arg("--prepare").arg(format!("{:?}", prepare));
|
||||
bench.arg("--prepare").arg(prepare);
|
||||
}
|
||||
|
||||
bench.arg(format!("{:?}", a)).arg(format!("{:?}", b));
|
||||
bench.arg(a).arg(b);
|
||||
|
||||
bench
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
set -e
|
||||
|
||||
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
|
||||
rm -rf target/ build/ perf.data{,.old} y.bin
|
||||
rm -rf target/ build/ dist/ perf.data{,.old} y.bin
|
||||
rm -rf download/
|
||||
|
||||
# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ aot.subslice-patterns-const-eval
|
|||
aot.track-caller-attribute
|
||||
aot.float-minmax-pass
|
||||
aot.mod_bench
|
||||
aot.issue-72793
|
||||
|
||||
testsuite.extended_sysroot
|
||||
test.rust-random/rand
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo
|
|||
In the directory with your project (where you can do the usual `cargo build`), run:
|
||||
|
||||
```bash
|
||||
$ $cg_clif_dir/build/cargo-clif build
|
||||
$ $cg_clif_dir/dist/cargo-clif build
|
||||
```
|
||||
|
||||
This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
|
||||
|
|
@ -19,7 +19,7 @@ This will build your project with rustc_codegen_cranelift instead of the usual L
|
|||
> You should prefer using the Cargo method.
|
||||
|
||||
```bash
|
||||
$ $cg_clif_dir/build/rustc-clif my_crate.rs
|
||||
$ $cg_clif_dir/dist/rustc-clif my_crate.rs
|
||||
```
|
||||
|
||||
## Jit mode
|
||||
|
|
@ -32,20 +32,20 @@ In jit mode cg_clif will immediately execute your code without creating an execu
|
|||
> The jit mode will probably need cargo integration to make this possible.
|
||||
|
||||
```bash
|
||||
$ $cg_clif_dir/build/cargo-clif jit
|
||||
$ $cg_clif_dir/dist/cargo-clif jit
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
$ $cg_clif_dir/build/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
|
||||
$ $cg_clif_dir/dist/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
|
||||
```
|
||||
|
||||
There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
|
||||
first called.
|
||||
|
||||
```bash
|
||||
$ $cg_clif_dir/build/cargo-clif lazy-jit
|
||||
$ $cg_clif_dir/dist/cargo-clif lazy-jit
|
||||
```
|
||||
|
||||
## Shell
|
||||
|
|
@ -54,7 +54,7 @@ These are a few functions that allow you to easily run rust code from the shell
|
|||
|
||||
```bash
|
||||
function jit_naked() {
|
||||
echo "$@" | $cg_clif_dir/build/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
|
||||
echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
|
||||
}
|
||||
|
||||
function jit() {
|
||||
|
|
|
|||
24
compiler/rustc_codegen_cranelift/example/issue-72793.rs
Normal file
24
compiler/rustc_codegen_cranelift/example/issue-72793.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Adapted from rustc ui test suite (ui/type-alias-impl-trait/issue-72793.rs)
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
trait T { type Item; }
|
||||
|
||||
type Alias<'a> = impl T<Item = &'a ()>;
|
||||
|
||||
struct S;
|
||||
impl<'a> T for &'a S {
|
||||
type Item = &'a ();
|
||||
}
|
||||
|
||||
fn filter_positive<'a>() -> Alias<'a> {
|
||||
&S
|
||||
}
|
||||
|
||||
fn with_positive(fun: impl Fn(Alias<'_>)) {
|
||||
fun(filter_positive());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
with_positive(|_| ());
|
||||
}
|
||||
|
|
@ -19,6 +19,9 @@ pub trait Sized {}
|
|||
#[lang = "destruct"]
|
||||
pub trait Destruct {}
|
||||
|
||||
#[lang = "tuple_trait"]
|
||||
pub trait Tuple {}
|
||||
|
||||
#[lang = "unsize"]
|
||||
pub trait Unsize<T: ?Sized> {}
|
||||
|
||||
|
|
@ -443,7 +446,7 @@ pub struct PhantomData<T: ?Sized>;
|
|||
|
||||
#[lang = "fn_once"]
|
||||
#[rustc_paren_sugar]
|
||||
pub trait FnOnce<Args> {
|
||||
pub trait FnOnce<Args: Tuple> {
|
||||
#[lang = "fn_once_output"]
|
||||
type Output;
|
||||
|
||||
|
|
@ -452,7 +455,7 @@ pub trait FnOnce<Args> {
|
|||
|
||||
#[lang = "fn_mut"]
|
||||
#[rustc_paren_sugar]
|
||||
pub trait FnMut<Args>: FnOnce<Args> {
|
||||
pub trait FnMut<Args: Tuple>: FnOnce<Args> {
|
||||
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,8 +171,6 @@ fn main() {
|
|||
|
||||
assert_eq!(slice_ptr as usize % 4, 0);
|
||||
|
||||
//return;
|
||||
|
||||
unsafe {
|
||||
printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8);
|
||||
|
||||
|
|
|
|||
|
|
@ -164,6 +164,8 @@ unsafe fn test_simd() {
|
|||
let cmp_eq = _mm_cmpeq_epi8(y, y);
|
||||
let cmp_lt = _mm_cmplt_epi8(y, y);
|
||||
|
||||
let (zero0, zero1) = std::mem::transmute::<_, (u64, u64)>(x);
|
||||
assert_eq!((zero0, zero1), (0, 0));
|
||||
assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
|
||||
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
|
||||
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2022-10-23"
|
||||
channel = "nightly-2022-12-13"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
ignore = ["y.rs"]
|
||||
|
||||
# Matches rustfmt.toml of rustc
|
||||
version = "Two"
|
||||
use_small_heuristics = "Max"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#![forbid(unsafe_code)]/* This line is ignored by bash
|
||||
# This block is ignored by rustc
|
||||
pushd $(dirname "$0")/../
|
||||
RUSTC="$(pwd)/build/rustc-clif"
|
||||
RUSTC="$(pwd)/dist/rustc-clif"
|
||||
popd
|
||||
PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0
|
||||
#*/
|
||||
|
|
|
|||
36
compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
Normal file
36
compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
|
||||
|
||||
let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
|
||||
env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
|
||||
);
|
||||
|
||||
let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
|
||||
args.push(OsString::from("-Cpanic=abort"));
|
||||
args.push(OsString::from("-Zpanic-abort-tests"));
|
||||
let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
|
||||
codegen_backend_arg.push(cg_clif_dylib_path);
|
||||
args.push(codegen_backend_arg);
|
||||
if !args.contains(&OsString::from("--sysroot")) {
|
||||
args.push(OsString::from("--sysroot"));
|
||||
args.push(OsString::from(sysroot.to_str().unwrap()));
|
||||
}
|
||||
|
||||
// Ensure that the right toolchain is used
|
||||
env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
|
||||
|
||||
#[cfg(unix)]
|
||||
Command::new("rustdoc").args(args).exec();
|
||||
|
||||
#[cfg(not(unix))]
|
||||
std::process::exit(
|
||||
Command::new("rustdoc").args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1),
|
||||
);
|
||||
}
|
||||
|
|
@ -27,24 +27,6 @@ index d95b5b7f17f..00b6f0e3635 100644
|
|||
[dev-dependencies]
|
||||
rand = "0.7"
|
||||
rand_xorshift = "0.2"
|
||||
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
|
||||
index 8431aa7b818..a3ff7e68ce5 100644
|
||||
--- a/src/tools/compiletest/src/runtest.rs
|
||||
+++ b/src/tools/compiletest/src/runtest.rs
|
||||
@@ -3489,12 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
|
||||
let compiler_src_dir = base_dir.join("compiler");
|
||||
normalize_path(&compiler_src_dir, "$(echo '$COMPILER_DIR')");
|
||||
|
||||
- if let Some(virtual_rust_source_base_dir) =
|
||||
- option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
|
||||
- {
|
||||
- normalize_path(&virtual_rust_source_base_dir.join("library"), "$(echo '$SRC_DIR')");
|
||||
- normalize_path(&virtual_rust_source_base_dir.join("compiler"), "$(echo '$COMPILER_DIR')");
|
||||
- }
|
||||
+ normalize_path(&Path::new("$(cd ../build_sysroot/sysroot_src/library; pwd)"), "$(echo '$SRC_DIR')");
|
||||
|
||||
// Paths into the build directory
|
||||
let test_build_dir = &self.config.build_base;
|
||||
EOF
|
||||
|
||||
cat > config.toml <<EOF
|
||||
|
|
@ -54,7 +36,7 @@ changelog-seen = 2
|
|||
ninja = false
|
||||
|
||||
[build]
|
||||
rustc = "$(pwd)/../build/rustc-clif"
|
||||
rustc = "$(pwd)/../dist/rustc-clif"
|
||||
cargo = "$(rustup which cargo)"
|
||||
full-bootstrap = true
|
||||
local-rebuild = true
|
||||
|
|
@ -69,6 +51,8 @@ popd
|
|||
# FIXME remove once inline asm is fully supported
|
||||
export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc"
|
||||
|
||||
export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd build_sysroot/sysroot_src; pwd)"
|
||||
|
||||
# Allow the testsuite to use llvm tools
|
||||
host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
|
||||
export LLVM_BIN_DIR="$(rustc --print sysroot)/lib/rustlib/$host_triple/bin"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ for test in $(rg -i --files-with-matches "//(\[\w+\])?~[^\|]*\s*ERR|// error-pat
|
|||
done
|
||||
|
||||
git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
|
||||
git checkout -- src/test/ui/proc-macro/pretty-print-hack/
|
||||
|
||||
# missing features
|
||||
# ================
|
||||
|
|
@ -30,6 +31,7 @@ rm src/test/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abo
|
|||
|
||||
# requires compiling with -Cpanic=unwind
|
||||
rm -r src/test/ui/macros/rfc-2011-nicer-assert-messages/
|
||||
rm -r src/test/run-make/test-benches
|
||||
|
||||
# vendor intrinsics
|
||||
rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected
|
||||
|
|
@ -64,6 +66,8 @@ rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
|
|||
rm -r src/test/run-make/emit-named-files # requires full --emit support
|
||||
rm src/test/ui/abi/stack-probes.rs # stack probes not yet implemented
|
||||
rm src/test/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented
|
||||
rm -r src/test/run-make/repr128-dwarf # debuginfo test
|
||||
rm src/test/codegen-units/item-collection/asm-sym.rs # requires support for sym in asm!()
|
||||
|
||||
# optimization tests
|
||||
# ==================
|
||||
|
|
@ -82,20 +86,20 @@ rm src/test/ui/abi/stack-protector.rs # requires stack protector support
|
|||
rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
|
||||
rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
|
||||
rm src/test/ui/consts/issue-33537.rs # same
|
||||
rm src/test/ui/layout/valid_range_oob.rs # different ICE message
|
||||
|
||||
# doesn't work due to the way the rustc test suite is invoked.
|
||||
# should work when using ./x.py test the way it is intended
|
||||
# ============================================================
|
||||
rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
|
||||
rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in dist/bin/
|
||||
rm -r src/test/run-make/unstable-flag-required # same
|
||||
rm -r src/test/run-make/rustdoc-* # same
|
||||
rm -r src/test/run-make/issue-88756-default-output # same
|
||||
rm -r src/test/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
|
||||
rm -r src/test/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to be elsewhere
|
||||
|
||||
# genuine bugs
|
||||
# ============
|
||||
rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
|
||||
|
||||
rm src/test/incremental/spike-neg1.rs # errors out for some reason
|
||||
rm src/test/incremental/spike-neg2.rs # same
|
||||
rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
|
||||
|
|
@ -104,6 +108,8 @@ rm src/test/ui/type-alias-impl-trait/assoc-projection-ice.rs # produces ICE
|
|||
|
||||
rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
|
||||
|
||||
rm src/test/ui/runtime/out-of-stack.rs # SIGSEGV instead of SIGABRT for some reason (#1301)
|
||||
|
||||
# bugs in the test suite
|
||||
# ======================
|
||||
rm src/test/ui/backtrace.rs # TODO warning
|
||||
|
|
@ -111,6 +117,8 @@ rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support
|
|||
rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
|
||||
# not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason
|
||||
rm -r src/test/run-make/native-link-modifier-bundle
|
||||
rm src/test/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
|
||||
rm src/test/ui/dyn-star/dispatch-on-pin-mut.rs # TODO failed assertion in vtable::get_ptr_and_method_ref
|
||||
|
||||
rm src/test/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
|
||||
|
||||
|
|
|
|||
|
|
@ -56,13 +56,13 @@ pub(crate) fn conv_to_call_conv(c: Conv, default_call_conv: CallConv) -> CallCon
|
|||
|
||||
pub(crate) fn get_function_sig<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
triple: &target_lexicon::Triple,
|
||||
default_call_conv: CallConv,
|
||||
inst: Instance<'tcx>,
|
||||
) -> Signature {
|
||||
assert!(!inst.substs.needs_infer());
|
||||
clif_sig_from_fn_abi(
|
||||
tcx,
|
||||
CallConv::triple_default(triple),
|
||||
default_call_conv,
|
||||
&RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
|
||||
)
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ pub(crate) fn import_function<'tcx>(
|
|||
inst: Instance<'tcx>,
|
||||
) -> FuncId {
|
||||
let name = tcx.symbol_name(inst).name;
|
||||
let sig = get_function_sig(tcx, module.isa().triple(), inst);
|
||||
let sig = get_function_sig(tcx, module.target_config().default_call_conv, inst);
|
||||
match module.declare_function(name, Linkage::Import, &sig) {
|
||||
Ok(func_id) => func_id,
|
||||
Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
|
||||
|
|
@ -341,18 +341,16 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
destination: Place<'tcx>,
|
||||
target: Option<BasicBlock>,
|
||||
) {
|
||||
let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
|
||||
let fn_sig =
|
||||
fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
|
||||
let func = codegen_operand(fx, func);
|
||||
let fn_sig = func.layout().ty.fn_sig(fx.tcx);
|
||||
|
||||
let ret_place = codegen_place(fx, destination);
|
||||
|
||||
// Handle special calls like intrinsics and empty drop glue.
|
||||
let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
|
||||
let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.polymorphize(fx.tcx);
|
||||
let instance = if let ty::FnDef(def_id, substs) = *func.layout().ty.kind() {
|
||||
let instance =
|
||||
ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
|
||||
.polymorphize(fx.tcx);
|
||||
|
||||
if fx.tcx.symbol_name(instance).name.starts_with("llvm.") {
|
||||
crate::intrinsics::codegen_llvm_intrinsic_call(
|
||||
|
|
@ -391,17 +389,17 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
None
|
||||
};
|
||||
|
||||
let extra_args = &args[fn_sig.inputs().len()..];
|
||||
let extra_args = &args[fn_sig.inputs().skip_binder().len()..];
|
||||
let extra_args = fx
|
||||
.tcx
|
||||
.mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
|
||||
let fn_abi = if let Some(instance) = instance {
|
||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
|
||||
} else {
|
||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
|
||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
|
||||
};
|
||||
|
||||
let is_cold = if fn_sig.abi == Abi::RustCold {
|
||||
let is_cold = if fn_sig.abi() == Abi::RustCold {
|
||||
true
|
||||
} else {
|
||||
instance
|
||||
|
|
@ -418,7 +416,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
}
|
||||
|
||||
// Unpack arguments tuple for closures
|
||||
let mut args = if fn_sig.abi == Abi::RustCall {
|
||||
let mut args = if fn_sig.abi() == Abi::RustCall {
|
||||
assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
|
||||
let self_arg = codegen_call_argument_operand(fx, &args[0]);
|
||||
let pack_arg = codegen_call_argument_operand(fx, &args[1]);
|
||||
|
|
@ -486,7 +484,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
fx.add_comment(nop_inst, "indirect call");
|
||||
}
|
||||
|
||||
let func = codegen_operand(fx, func).load_scalar(fx);
|
||||
let func = func.load_scalar(fx);
|
||||
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
||||
let sig = fx.bcx.import_signature(sig);
|
||||
|
||||
|
|
@ -517,11 +515,11 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
};
|
||||
|
||||
// FIXME find a cleaner way to support varargs
|
||||
if fn_sig.c_variadic {
|
||||
if !matches!(fn_sig.abi, Abi::C { .. }) {
|
||||
if fn_sig.c_variadic() {
|
||||
if !matches!(fn_sig.abi(), Abi::C { .. }) {
|
||||
fx.tcx.sess.span_fatal(
|
||||
source_info.span,
|
||||
&format!("Variadic call for non-C abi {:?}", fn_sig.abi),
|
||||
&format!("Variadic call for non-C abi {:?}", fn_sig.abi()),
|
||||
);
|
||||
}
|
||||
let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ fn codegen_inner(
|
|||
};
|
||||
|
||||
let sig = Signature {
|
||||
call_conv: CallConv::triple_default(module.isa().triple()),
|
||||
call_conv: module.target_config().default_call_conv,
|
||||
params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
|
||||
returns: output.into_iter().map(AbiParam::new).collect(),
|
||||
};
|
||||
|
|
@ -104,7 +104,7 @@ fn codegen_inner(
|
|||
}
|
||||
|
||||
let sig = Signature {
|
||||
call_conv: CallConv::triple_default(module.isa().triple()),
|
||||
call_conv: module.target_config().default_call_conv,
|
||||
params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
|
||||
returns: vec![],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||
|
||||
// Declare function
|
||||
let symbol_name = tcx.symbol_name(instance).name.to_string();
|
||||
let sig = get_function_sig(tcx, module.isa().triple(), instance);
|
||||
let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance);
|
||||
let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap();
|
||||
|
||||
// Make the FunctionBuilder
|
||||
|
|
@ -390,11 +390,9 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
_ => unreachable!("{:?}", targets),
|
||||
};
|
||||
|
||||
let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
|
||||
let (discr, is_inverted) =
|
||||
crate::optimize::peephole::maybe_unwrap_bool_not(&mut fx.bcx, discr);
|
||||
let test_zero = if is_inverted { !test_zero } else { test_zero };
|
||||
let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
|
||||
if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
|
||||
&fx.bcx, discr, test_zero,
|
||||
) {
|
||||
|
|
@ -571,7 +569,7 @@ fn codegen_stmt<'tcx>(
|
|||
UnOp::Not => match layout.ty.kind() {
|
||||
ty::Bool => {
|
||||
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
|
||||
CValue::by_val(fx.bcx.ins().bint(types::I8, res), layout)
|
||||
CValue::by_val(res, layout)
|
||||
}
|
||||
ty::Uint(_) | ty::Int(_) => {
|
||||
CValue::by_val(fx.bcx.ins().bnot(val), layout)
|
||||
|
|
@ -579,12 +577,6 @@ fn codegen_stmt<'tcx>(
|
|||
_ => unreachable!("un op Not for {:?}", layout.ty),
|
||||
},
|
||||
UnOp::Neg => match layout.ty.kind() {
|
||||
ty::Int(IntTy::I128) => {
|
||||
// FIXME remove this case once ineg.i128 works
|
||||
let zero =
|
||||
CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
|
||||
crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand)
|
||||
}
|
||||
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
|
||||
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
|
||||
_ => unreachable!("un op Neg for {:?}", layout.ty),
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ pub(crate) fn clif_int_or_float_cast(
|
|||
}
|
||||
|
||||
let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from);
|
||||
let zero = fx.bcx.ins().iconst(to_ty, 0);
|
||||
let zero = type_zero_value(&mut fx.bcx, to_ty);
|
||||
fx.bcx.ins().select(is_not_nan, val, zero)
|
||||
} else if from_ty.is_float() && to_ty.is_float() {
|
||||
// float -> float
|
||||
|
|
|
|||
|
|
@ -162,11 +162,20 @@ pub(crate) fn codegen_icmp_imm(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let rhs = i64::try_from(rhs).expect("codegen_icmp_imm rhs out of range for <128bit int");
|
||||
let rhs = rhs as i64; // Truncates on purpose in case rhs is actually an unsigned value
|
||||
fx.bcx.ins().icmp_imm(intcc, lhs, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn type_zero_value(bcx: &mut FunctionBuilder<'_>, ty: Type) -> Value {
|
||||
if ty == types::I128 {
|
||||
let zero = bcx.ins().iconst(types::I64, 0);
|
||||
bcx.ins().iconcat(zero, zero)
|
||||
} else {
|
||||
bcx.ins().iconst(ty, 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn type_min_max_value(
|
||||
bcx: &mut FunctionBuilder<'_>,
|
||||
ty: Type,
|
||||
|
|
|
|||
|
|
@ -28,9 +28,7 @@ impl ConstantCx {
|
|||
}
|
||||
|
||||
pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) {
|
||||
//println!("todo {:?}", self.todo);
|
||||
define_all_allocs(tcx, module, &mut self);
|
||||
//println!("done {:?}", self.done);
|
||||
self.done.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -268,16 +266,7 @@ fn data_id_for_static(
|
|||
def_id: DefId,
|
||||
definition: bool,
|
||||
) -> DataId {
|
||||
let rlinkage = tcx.codegen_fn_attrs(def_id).linkage;
|
||||
let linkage = if definition {
|
||||
crate::linkage::get_static_linkage(tcx, def_id)
|
||||
} else if rlinkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak)
|
||||
|| rlinkage == Some(rustc_middle::mir::mono::Linkage::WeakAny)
|
||||
{
|
||||
Linkage::Preemptible
|
||||
} else {
|
||||
Linkage::Import
|
||||
};
|
||||
let attrs = tcx.codegen_fn_attrs(def_id);
|
||||
|
||||
let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
|
||||
let symbol_name = tcx.symbol_name(instance).name;
|
||||
|
|
@ -289,22 +278,30 @@ fn data_id_for_static(
|
|||
};
|
||||
let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
|
||||
|
||||
let attrs = tcx.codegen_fn_attrs(def_id);
|
||||
if let Some(import_linkage) = attrs.import_linkage {
|
||||
assert!(!definition);
|
||||
|
||||
let data_id = match module.declare_data(
|
||||
&*symbol_name,
|
||||
linkage,
|
||||
is_mutable,
|
||||
attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
|
||||
) {
|
||||
Ok(data_id) => data_id,
|
||||
Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
|
||||
"attempt to declare `{symbol_name}` as static, but it was already declared as function"
|
||||
)),
|
||||
Err(err) => Err::<_, _>(err).unwrap(),
|
||||
};
|
||||
let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak
|
||||
|| import_linkage == rustc_middle::mir::mono::Linkage::WeakAny
|
||||
{
|
||||
Linkage::Preemptible
|
||||
} else {
|
||||
Linkage::Import
|
||||
};
|
||||
|
||||
let data_id = match module.declare_data(
|
||||
&*symbol_name,
|
||||
linkage,
|
||||
is_mutable,
|
||||
attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
|
||||
) {
|
||||
Ok(data_id) => data_id,
|
||||
Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
|
||||
"attempt to declare `{symbol_name}` as static, but it was already declared as function"
|
||||
)),
|
||||
Err(err) => Err::<_, _>(err).unwrap(),
|
||||
};
|
||||
|
||||
if rlinkage.is_some() {
|
||||
// Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141
|
||||
// Declare an internal global `extern_with_linkage_foo` which
|
||||
// is initialized with the address of `foo`. If `foo` is
|
||||
|
|
@ -326,10 +323,34 @@ fn data_id_for_static(
|
|||
Err(ModuleError::DuplicateDefinition(_)) => {}
|
||||
res => res.unwrap(),
|
||||
}
|
||||
ref_data_id
|
||||
} else {
|
||||
data_id
|
||||
|
||||
return ref_data_id;
|
||||
}
|
||||
|
||||
let linkage = if definition {
|
||||
crate::linkage::get_static_linkage(tcx, def_id)
|
||||
} else if attrs.linkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak)
|
||||
|| attrs.linkage == Some(rustc_middle::mir::mono::Linkage::WeakAny)
|
||||
{
|
||||
Linkage::Preemptible
|
||||
} else {
|
||||
Linkage::Import
|
||||
};
|
||||
|
||||
let data_id = match module.declare_data(
|
||||
&*symbol_name,
|
||||
linkage,
|
||||
is_mutable,
|
||||
attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
|
||||
) {
|
||||
Ok(data_id) => data_id,
|
||||
Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
|
||||
"attempt to declare `{symbol_name}` as static, but it was already declared as function"
|
||||
)),
|
||||
Err(err) => Err::<_, _>(err).unwrap(),
|
||||
};
|
||||
|
||||
data_id
|
||||
}
|
||||
|
||||
fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut ConstantCx) {
|
||||
|
|
@ -348,8 +369,6 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
|||
(data_id, alloc, None)
|
||||
}
|
||||
TodoItem::Static(def_id) => {
|
||||
//println!("static {:?}", def_id);
|
||||
|
||||
let section_name = tcx.codegen_fn_attrs(def_id).link_section;
|
||||
|
||||
let alloc = tcx.eval_static_initializer(def_id).unwrap();
|
||||
|
|
@ -359,7 +378,6 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
|||
}
|
||||
};
|
||||
|
||||
//("data_id {}", data_id);
|
||||
if cx.done.contains(&data_id) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ impl UnwindContext {
|
|||
}
|
||||
|
||||
pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) {
|
||||
let unwind_info = if let Some(unwind_info) = context.create_unwind_info(isa).unwrap() {
|
||||
let unwind_info = if let Some(unwind_info) =
|
||||
context.compiled_code().unwrap().create_unwind_info(isa).unwrap()
|
||||
{
|
||||
unwind_info
|
||||
} else {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! Handling of enum discriminants
|
||||
//!
|
||||
//! Adapted from <https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs>
|
||||
//! Adapted from <https://github.com/rust-lang/rust/blob/31c0645b9d2539f47eecb096142474b29dc542f7/compiler/rustc_codegen_ssa/src/mir/place.rs>
|
||||
//! (<https://github.com/rust-lang/rust/pull/104535>)
|
||||
|
||||
use rustc_target::abi::{Int, TagEncoding, Variants};
|
||||
|
||||
|
|
@ -47,13 +48,19 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
|
|||
} => {
|
||||
if variant_index != untagged_variant {
|
||||
let niche = place.place_field(fx, mir::Field::new(tag_field));
|
||||
let niche_type = fx.clif_type(niche.layout().ty).unwrap();
|
||||
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
|
||||
let niche_value = ty::ScalarInt::try_from_uint(
|
||||
u128::from(niche_value).wrapping_add(niche_start),
|
||||
niche.layout().size,
|
||||
)
|
||||
.unwrap();
|
||||
let niche_llval = CValue::const_val(fx, niche.layout(), niche_value);
|
||||
let niche_value = (niche_value as u128).wrapping_add(niche_start);
|
||||
let niche_value = match niche_type {
|
||||
types::I128 => {
|
||||
let lsb = fx.bcx.ins().iconst(types::I64, niche_value as u64 as i64);
|
||||
let msb =
|
||||
fx.bcx.ins().iconst(types::I64, (niche_value >> 64) as u64 as i64);
|
||||
fx.bcx.ins().iconcat(lsb, msb)
|
||||
}
|
||||
ty => fx.bcx.ins().iconst(ty, niche_value as i64),
|
||||
};
|
||||
let niche_llval = CValue::by_val(niche_value, niche.layout());
|
||||
niche.write_cvalue(fx, niche_llval);
|
||||
}
|
||||
}
|
||||
|
|
@ -96,6 +103,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
|
|||
}
|
||||
};
|
||||
|
||||
let cast_to_size = dest_layout.layout.size();
|
||||
let cast_to = fx.clif_type(dest_layout.ty).unwrap();
|
||||
|
||||
// Read the tag/niche-encoded discriminant from memory.
|
||||
|
|
@ -114,21 +122,128 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
|
|||
dest.write_cvalue(fx, res);
|
||||
}
|
||||
TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
|
||||
// Rebase from niche values to discriminants, and check
|
||||
// whether the result is in range for the niche variants.
|
||||
let tag_size = tag_scalar.size(fx);
|
||||
let max_unsigned = tag_size.unsigned_int_max();
|
||||
let max_signed = tag_size.signed_int_max() as u128;
|
||||
let min_signed = max_signed + 1;
|
||||
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
|
||||
let niche_end = niche_start.wrapping_add(relative_max as u128) & max_unsigned;
|
||||
let range = tag_scalar.valid_range(fx);
|
||||
|
||||
// We first compute the "relative discriminant" (wrt `niche_variants`),
|
||||
// that is, if `n = niche_variants.end() - niche_variants.start()`,
|
||||
// we remap `niche_start..=niche_start + n` (which may wrap around)
|
||||
// to (non-wrap-around) `0..=n`, to be able to check whether the
|
||||
// discriminant corresponds to a niche variant with one comparison.
|
||||
// We also can't go directly to the (variant index) discriminant
|
||||
// and check that it is in the range `niche_variants`, because
|
||||
// that might not fit in the same type, on top of needing an extra
|
||||
// comparison (see also the comment on `let niche_discr`).
|
||||
let relative_discr = if niche_start == 0 {
|
||||
tag
|
||||
let sle = |lhs: u128, rhs: u128| -> bool {
|
||||
// Signed and unsigned comparisons give the same results,
|
||||
// except that in signed comparisons an integer with the
|
||||
// sign bit set is less than one with the sign bit clear.
|
||||
// Toggle the sign bit to do a signed comparison.
|
||||
(lhs ^ min_signed) <= (rhs ^ min_signed)
|
||||
};
|
||||
|
||||
// We have a subrange `niche_start..=niche_end` inside `range`.
|
||||
// If the value of the tag is inside this subrange, it's a
|
||||
// "niche value", an increment of the discriminant. Otherwise it
|
||||
// indicates the untagged variant.
|
||||
// A general algorithm to extract the discriminant from the tag
|
||||
// is:
|
||||
// relative_tag = tag - niche_start
|
||||
// is_niche = relative_tag <= (ule) relative_max
|
||||
// discr = if is_niche {
|
||||
// cast(relative_tag) + niche_variants.start()
|
||||
// } else {
|
||||
// untagged_variant
|
||||
// }
|
||||
// However, we will likely be able to emit simpler code.
|
||||
|
||||
// Find the least and greatest values in `range`, considered
|
||||
// both as signed and unsigned.
|
||||
let (low_unsigned, high_unsigned) =
|
||||
if range.start <= range.end { (range.start, range.end) } else { (0, max_unsigned) };
|
||||
let (low_signed, high_signed) = if sle(range.start, range.end) {
|
||||
(range.start, range.end)
|
||||
} else {
|
||||
(min_signed, max_signed)
|
||||
};
|
||||
|
||||
let niches_ule = niche_start <= niche_end;
|
||||
let niches_sle = sle(niche_start, niche_end);
|
||||
let cast_smaller = cast_to_size <= tag_size;
|
||||
|
||||
// In the algorithm above, we can change
|
||||
// cast(relative_tag) + niche_variants.start()
|
||||
// into
|
||||
// cast(tag + (niche_variants.start() - niche_start))
|
||||
// if either the casted type is no larger than the original
|
||||
// type, or if the niche values are contiguous (in either the
|
||||
// signed or unsigned sense).
|
||||
let can_incr = cast_smaller || niches_ule || niches_sle;
|
||||
|
||||
let data_for_boundary_niche = || -> Option<(IntCC, u128)> {
|
||||
if !can_incr {
|
||||
None
|
||||
} else if niche_start == low_unsigned {
|
||||
Some((IntCC::UnsignedLessThanOrEqual, niche_end))
|
||||
} else if niche_end == high_unsigned {
|
||||
Some((IntCC::UnsignedGreaterThanOrEqual, niche_start))
|
||||
} else if niche_start == low_signed {
|
||||
Some((IntCC::SignedLessThanOrEqual, niche_end))
|
||||
} else if niche_end == high_signed {
|
||||
Some((IntCC::SignedGreaterThanOrEqual, niche_start))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let (is_niche, tagged_discr, delta) = if relative_max == 0 {
|
||||
// Best case scenario: only one tagged variant. This will
|
||||
// likely become just a comparison and a jump.
|
||||
// The algorithm is:
|
||||
// is_niche = tag == niche_start
|
||||
// discr = if is_niche {
|
||||
// niche_start
|
||||
// } else {
|
||||
// untagged_variant
|
||||
// }
|
||||
let is_niche = codegen_icmp_imm(fx, IntCC::Equal, tag, niche_start as i128);
|
||||
let tagged_discr =
|
||||
fx.bcx.ins().iconst(cast_to, niche_variants.start().as_u32() as i64);
|
||||
(is_niche, tagged_discr, 0)
|
||||
} else if let Some((predicate, constant)) = data_for_boundary_niche() {
|
||||
// The niche values are either the lowest or the highest in
|
||||
// `range`. We can avoid the first subtraction in the
|
||||
// algorithm.
|
||||
// The algorithm is now this:
|
||||
// is_niche = tag <= niche_end
|
||||
// discr = if is_niche {
|
||||
// cast(tag + (niche_variants.start() - niche_start))
|
||||
// } else {
|
||||
// untagged_variant
|
||||
// }
|
||||
// (the first line may instead be tag >= niche_start,
|
||||
// and may be a signed or unsigned comparison)
|
||||
// The arithmetic must be done before the cast, so we can
|
||||
// have the correct wrapping behavior. See issue #104519 for
|
||||
// the consequences of getting this wrong.
|
||||
let is_niche = codegen_icmp_imm(fx, predicate, tag, constant as i128);
|
||||
let delta = (niche_variants.start().as_u32() as u128).wrapping_sub(niche_start);
|
||||
let incr_tag = if delta == 0 {
|
||||
tag
|
||||
} else {
|
||||
let delta = match fx.bcx.func.dfg.value_type(tag) {
|
||||
types::I128 => {
|
||||
let lsb = fx.bcx.ins().iconst(types::I64, delta as u64 as i64);
|
||||
let msb = fx.bcx.ins().iconst(types::I64, (delta >> 64) as u64 as i64);
|
||||
fx.bcx.ins().iconcat(lsb, msb)
|
||||
}
|
||||
ty => fx.bcx.ins().iconst(ty, delta as i64),
|
||||
};
|
||||
fx.bcx.ins().iadd(tag, delta)
|
||||
};
|
||||
|
||||
let cast_tag = clif_intcast(fx, incr_tag, cast_to, !niches_ule);
|
||||
|
||||
(is_niche, cast_tag, 0)
|
||||
} else {
|
||||
// The special cases don't apply, so we'll have to go with
|
||||
// the general algorithm.
|
||||
let niche_start = match fx.bcx.func.dfg.value_type(tag) {
|
||||
types::I128 => {
|
||||
let lsb = fx.bcx.ins().iconst(types::I64, niche_start as u64 as i64);
|
||||
|
|
@ -138,40 +253,40 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
|
|||
}
|
||||
ty => fx.bcx.ins().iconst(ty, niche_start as i64),
|
||||
};
|
||||
fx.bcx.ins().isub(tag, niche_start)
|
||||
};
|
||||
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
|
||||
let is_niche = {
|
||||
codegen_icmp_imm(
|
||||
let relative_discr = fx.bcx.ins().isub(tag, niche_start);
|
||||
let cast_tag = clif_intcast(fx, relative_discr, cast_to, false);
|
||||
let is_niche = crate::common::codegen_icmp_imm(
|
||||
fx,
|
||||
IntCC::UnsignedLessThanOrEqual,
|
||||
relative_discr,
|
||||
i128::from(relative_max),
|
||||
)
|
||||
);
|
||||
(is_niche, cast_tag, niche_variants.start().as_u32() as u128)
|
||||
};
|
||||
|
||||
// NOTE(eddyb) this addition needs to be performed on the final
|
||||
// type, in case the niche itself can't represent all variant
|
||||
// indices (e.g. `u8` niche with more than `256` variants,
|
||||
// but enough uninhabited variants so that the remaining variants
|
||||
// fit in the niche).
|
||||
// In other words, `niche_variants.end - niche_variants.start`
|
||||
// is representable in the niche, but `niche_variants.end`
|
||||
// might not be, in extreme cases.
|
||||
let niche_discr = {
|
||||
let relative_discr = if relative_max == 0 {
|
||||
// HACK(eddyb) since we have only one niche, we know which
|
||||
// one it is, and we can avoid having a dynamic value here.
|
||||
fx.bcx.ins().iconst(cast_to, 0)
|
||||
} else {
|
||||
clif_intcast(fx, relative_discr, cast_to, false)
|
||||
let tagged_discr = if delta == 0 {
|
||||
tagged_discr
|
||||
} else {
|
||||
let delta = match cast_to {
|
||||
types::I128 => {
|
||||
let lsb = fx.bcx.ins().iconst(types::I64, delta as u64 as i64);
|
||||
let msb = fx.bcx.ins().iconst(types::I64, (delta >> 64) as u64 as i64);
|
||||
fx.bcx.ins().iconcat(lsb, msb)
|
||||
}
|
||||
ty => fx.bcx.ins().iconst(ty, delta as i64),
|
||||
};
|
||||
fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
|
||||
fx.bcx.ins().iadd(tagged_discr, delta)
|
||||
};
|
||||
|
||||
let untagged_variant =
|
||||
fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32()));
|
||||
let discr = fx.bcx.ins().select(is_niche, niche_discr, untagged_variant);
|
||||
let untagged_variant = if cast_to == types::I128 {
|
||||
let zero = fx.bcx.ins().iconst(types::I64, 0);
|
||||
let untagged_variant =
|
||||
fx.bcx.ins().iconst(types::I64, i64::from(untagged_variant.as_u32()));
|
||||
fx.bcx.ins().iconcat(untagged_variant, zero)
|
||||
} else {
|
||||
fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32()))
|
||||
};
|
||||
let discr = fx.bcx.ins().select(is_niche, tagged_discr, untagged_variant);
|
||||
let res = CValue::by_val(discr, dest_layout);
|
||||
dest.write_cvalue(fx, res);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
|||
|
||||
tcx.sess.abort_if_errors();
|
||||
|
||||
jit_module.finalize_definitions();
|
||||
jit_module.finalize_definitions().unwrap();
|
||||
unsafe { cx.unwind_context.register_jit(&jit_module) };
|
||||
|
||||
println!(
|
||||
|
|
@ -245,7 +245,11 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
|
|||
let backend_config = lazy_jit_state.backend_config.clone();
|
||||
|
||||
let name = tcx.symbol_name(instance).name;
|
||||
let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
|
||||
let sig = crate::abi::get_function_sig(
|
||||
tcx,
|
||||
jit_module.target_config().default_call_conv,
|
||||
instance,
|
||||
);
|
||||
let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
|
||||
|
||||
let current_ptr = jit_module.read_got_entry(func_id);
|
||||
|
|
@ -278,7 +282,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
|
|||
});
|
||||
|
||||
assert!(cx.global_asm.is_empty());
|
||||
jit_module.finalize_definitions();
|
||||
jit_module.finalize_definitions().unwrap();
|
||||
unsafe { cx.unwind_context.register_jit(&jit_module) };
|
||||
jit_module.get_finalized_function(func_id)
|
||||
})
|
||||
|
|
@ -344,7 +348,7 @@ fn codegen_shim<'tcx>(
|
|||
let pointer_type = module.target_config().pointer_type();
|
||||
|
||||
let name = tcx.symbol_name(inst).name;
|
||||
let sig = crate::abi::get_function_sig(tcx, module.isa().triple(), inst);
|
||||
let sig = crate::abi::get_function_sig(tcx, module.target_config().default_call_conv, inst);
|
||||
let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap();
|
||||
|
||||
let instance_ptr = Box::into_raw(Box::new(inst));
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ fn predefine_mono_items<'tcx>(
|
|||
MonoItem::Fn(instance) => {
|
||||
let name = tcx.symbol_name(instance).name;
|
||||
let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name));
|
||||
let sig = get_function_sig(tcx, module.isa().triple(), instance);
|
||||
let sig =
|
||||
get_function_sig(tcx, module.target_config().default_call_conv, instance);
|
||||
let linkage = crate::linkage::get_clif_linkage(
|
||||
mono_item,
|
||||
linkage,
|
||||
|
|
|
|||
|
|
@ -8,135 +8,37 @@ use rustc_middle::ty::subst::SubstsRef;
|
|||
pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
intrinsic: &str,
|
||||
_substs: SubstsRef<'tcx>,
|
||||
substs: SubstsRef<'tcx>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
ret: CPlace<'tcx>,
|
||||
target: Option<BasicBlock>,
|
||||
) {
|
||||
match intrinsic {
|
||||
"llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
|
||||
// Spin loop hint
|
||||
}
|
||||
if intrinsic.starts_with("llvm.aarch64") {
|
||||
return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call(
|
||||
fx, intrinsic, substs, args, ret, target,
|
||||
);
|
||||
}
|
||||
if intrinsic.starts_with("llvm.x86") {
|
||||
return llvm_x86::codegen_x86_llvm_intrinsic_call(fx, intrinsic, substs, args, ret, target);
|
||||
}
|
||||
|
||||
// Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
|
||||
"llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
|
||||
match intrinsic {
|
||||
_ if intrinsic.starts_with("llvm.ctlz.v") => {
|
||||
intrinsic_args!(fx, args => (a); intrinsic);
|
||||
|
||||
let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let lane_ty = fx.clif_type(lane_ty).unwrap();
|
||||
assert!(lane_count <= 32);
|
||||
|
||||
let mut res = fx.bcx.ins().iconst(types::I32, 0);
|
||||
|
||||
for lane in (0..lane_count).rev() {
|
||||
let a_lane = a.value_lane(fx, lane).load_scalar(fx);
|
||||
|
||||
// cast float to int
|
||||
let a_lane = match lane_ty {
|
||||
types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane),
|
||||
types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane),
|
||||
_ => a_lane,
|
||||
};
|
||||
|
||||
// extract sign bit of an int
|
||||
let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1));
|
||||
|
||||
// shift sign bit into result
|
||||
let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false);
|
||||
res = fx.bcx.ins().ishl_imm(res, 1);
|
||||
res = fx.bcx.ins().bor(res, a_lane_sign);
|
||||
}
|
||||
|
||||
let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
|
||||
ret.write_cvalue(fx, res);
|
||||
}
|
||||
"llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
|
||||
let (x, y, kind) = match args {
|
||||
[x, y, kind] => (x, y, kind),
|
||||
_ => bug!("wrong number of args for intrinsic {intrinsic}"),
|
||||
};
|
||||
let x = codegen_operand(fx, x);
|
||||
let y = codegen_operand(fx, y);
|
||||
let kind = crate::constant::mir_operand_get_const_val(fx, kind)
|
||||
.expect("llvm.x86.sse2.cmp.* kind not const");
|
||||
|
||||
let flt_cc = match kind
|
||||
.try_to_bits(Size::from_bytes(1))
|
||||
.unwrap_or_else(|| panic!("kind not scalar: {:?}", kind))
|
||||
{
|
||||
0 => FloatCC::Equal,
|
||||
1 => FloatCC::LessThan,
|
||||
2 => FloatCC::LessThanOrEqual,
|
||||
7 => FloatCC::Ordered,
|
||||
3 => FloatCC::Unordered,
|
||||
4 => FloatCC::NotEqual,
|
||||
5 => FloatCC::UnorderedOrGreaterThanOrEqual,
|
||||
6 => FloatCC::UnorderedOrGreaterThan,
|
||||
kind => unreachable!("kind {:?}", kind),
|
||||
};
|
||||
|
||||
simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
|
||||
let res_lane = match lane_ty.kind() {
|
||||
ty::Float(_) => fx.bcx.ins().fcmp(flt_cc, x_lane, y_lane),
|
||||
_ => unreachable!("{:?}", lane_ty),
|
||||
};
|
||||
bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
|
||||
fx.bcx.ins().clz(lane)
|
||||
});
|
||||
}
|
||||
"llvm.x86.sse2.psrli.d" => {
|
||||
let (a, imm8) = match args {
|
||||
[a, imm8] => (a, imm8),
|
||||
_ => bug!("wrong number of args for intrinsic {intrinsic}"),
|
||||
};
|
||||
let a = codegen_operand(fx, a);
|
||||
let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
|
||||
.expect("llvm.x86.sse2.psrli.d imm8 not const");
|
||||
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
|
||||
.try_to_bits(Size::from_bytes(4))
|
||||
.unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
|
||||
{
|
||||
imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
|
||||
_ => fx.bcx.ins().iconst(types::I32, 0),
|
||||
_ if intrinsic.starts_with("llvm.ctpop.v") => {
|
||||
intrinsic_args!(fx, args => (a); intrinsic);
|
||||
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
|
||||
fx.bcx.ins().popcnt(lane)
|
||||
});
|
||||
}
|
||||
"llvm.x86.sse2.pslli.d" => {
|
||||
let (a, imm8) = match args {
|
||||
[a, imm8] => (a, imm8),
|
||||
_ => bug!("wrong number of args for intrinsic {intrinsic}"),
|
||||
};
|
||||
let a = codegen_operand(fx, a);
|
||||
let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
|
||||
.expect("llvm.x86.sse2.psrli.d imm8 not const");
|
||||
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
|
||||
.try_to_bits(Size::from_bytes(4))
|
||||
.unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
|
||||
{
|
||||
imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
|
||||
_ => fx.bcx.ins().iconst(types::I32, 0),
|
||||
});
|
||||
}
|
||||
"llvm.x86.sse2.storeu.dq" => {
|
||||
intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
|
||||
let mem_addr = mem_addr.load_scalar(fx);
|
||||
|
||||
// FIXME correctly handle the unalignment
|
||||
let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
|
||||
dest.write_cvalue(fx, a);
|
||||
}
|
||||
"llvm.x86.addcarry.64" => {
|
||||
intrinsic_args!(fx, args => (c_in, a, b); intrinsic);
|
||||
let c_in = c_in.load_scalar(fx);
|
||||
|
||||
llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b);
|
||||
}
|
||||
"llvm.x86.subborrow.64" => {
|
||||
intrinsic_args!(fx, args => (b_in, a, b); intrinsic);
|
||||
let b_in = b_in.load_scalar(fx);
|
||||
|
||||
llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
|
||||
}
|
||||
_ => {
|
||||
fx.tcx
|
||||
.sess
|
||||
|
|
@ -150,47 +52,3 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
|
|||
let ret_block = fx.get_block(dest);
|
||||
fx.bcx.ins().jump(ret_block, &[]);
|
||||
}
|
||||
|
||||
// llvm.x86.avx2.vperm2i128
|
||||
// llvm.x86.ssse3.pshuf.b.128
|
||||
// llvm.x86.avx2.pshuf.b
|
||||
// llvm.x86.avx2.psrli.w
|
||||
// llvm.x86.sse2.psrli.w
|
||||
|
||||
fn llvm_add_sub<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
bin_op: BinOp,
|
||||
ret: CPlace<'tcx>,
|
||||
cb_in: Value,
|
||||
a: CValue<'tcx>,
|
||||
b: CValue<'tcx>,
|
||||
) {
|
||||
assert_eq!(
|
||||
a.layout().ty,
|
||||
fx.tcx.types.u64,
|
||||
"llvm.x86.addcarry.64/llvm.x86.subborrow.64 second operand must be u64"
|
||||
);
|
||||
assert_eq!(
|
||||
b.layout().ty,
|
||||
fx.tcx.types.u64,
|
||||
"llvm.x86.addcarry.64/llvm.x86.subborrow.64 third operand must be u64"
|
||||
);
|
||||
|
||||
// c + carry -> c + first intermediate carry or borrow respectively
|
||||
let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
|
||||
let c = int0.value_field(fx, mir::Field::new(0));
|
||||
let cb0 = int0.value_field(fx, mir::Field::new(1)).load_scalar(fx);
|
||||
|
||||
// c + carry -> c + second intermediate carry or borrow respectively
|
||||
let cb_in_as_u64 = fx.bcx.ins().uextend(types::I64, cb_in);
|
||||
let cb_in_as_u64 = CValue::by_val(cb_in_as_u64, fx.layout_of(fx.tcx.types.u64));
|
||||
let int1 = crate::num::codegen_checked_int_binop(fx, bin_op, c, cb_in_as_u64);
|
||||
let (c, cb1) = int1.load_scalar_pair(fx);
|
||||
|
||||
// carry0 | carry1 -> carry or borrow respectively
|
||||
let cb_out = fx.bcx.ins().bor(cb0, cb1);
|
||||
|
||||
let layout = fx.layout_of(fx.tcx.mk_tup([fx.tcx.types.u8, fx.tcx.types.u64].iter()));
|
||||
let val = CValue::by_val_pair(cb_out, c, layout);
|
||||
ret.write_cvalue(fx, val);
|
||||
}
|
||||
|
|
|
|||
222
compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
Normal file
222
compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
//! Emulate AArch64 LLVM intrinsics
|
||||
|
||||
use crate::intrinsics::*;
|
||||
use crate::prelude::*;
|
||||
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
|
||||
pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
intrinsic: &str,
|
||||
_substs: SubstsRef<'tcx>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
ret: CPlace<'tcx>,
|
||||
target: Option<BasicBlock>,
|
||||
) {
|
||||
// llvm.aarch64.neon.sqshl.v*i*
|
||||
|
||||
match intrinsic {
|
||||
"llvm.aarch64.isb" => {
|
||||
fx.bcx.ins().fence();
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.abs.v") => {
|
||||
intrinsic_args!(fx, args => (a); intrinsic);
|
||||
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
|
||||
fx.bcx.ins().iabs(lane)
|
||||
});
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.cls.v") => {
|
||||
intrinsic_args!(fx, args => (a); intrinsic);
|
||||
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
|
||||
fx.bcx.ins().cls(lane)
|
||||
});
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.rbit.v") => {
|
||||
intrinsic_args!(fx, args => (a); intrinsic);
|
||||
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
|
||||
fx.bcx.ins().bitrev(lane)
|
||||
});
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.sqadd.v") => {
|
||||
intrinsic_args!(fx, args => (x, y); intrinsic);
|
||||
|
||||
simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| {
|
||||
crate::num::codegen_saturating_int_binop(fx, BinOp::Add, x_lane, y_lane)
|
||||
});
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.sqsub.v") => {
|
||||
intrinsic_args!(fx, args => (x, y); intrinsic);
|
||||
|
||||
simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| {
|
||||
crate::num::codegen_saturating_int_binop(fx, BinOp::Sub, x_lane, y_lane)
|
||||
});
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.smax.v") => {
|
||||
intrinsic_args!(fx, args => (x, y); intrinsic);
|
||||
|
||||
simd_pair_for_each_lane(
|
||||
fx,
|
||||
x,
|
||||
y,
|
||||
ret,
|
||||
&|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
|
||||
let gt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, x_lane, y_lane);
|
||||
fx.bcx.ins().select(gt, x_lane, y_lane)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.umax.v") => {
|
||||
intrinsic_args!(fx, args => (x, y); intrinsic);
|
||||
|
||||
simd_pair_for_each_lane(
|
||||
fx,
|
||||
x,
|
||||
y,
|
||||
ret,
|
||||
&|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
|
||||
let gt = fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, x_lane, y_lane);
|
||||
fx.bcx.ins().select(gt, x_lane, y_lane)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.smaxv.i") => {
|
||||
intrinsic_args!(fx, args => (v); intrinsic);
|
||||
|
||||
simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
|
||||
let gt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, a, b);
|
||||
fx.bcx.ins().select(gt, a, b)
|
||||
});
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.umaxv.i") => {
|
||||
intrinsic_args!(fx, args => (v); intrinsic);
|
||||
|
||||
simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
|
||||
let gt = fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, a, b);
|
||||
fx.bcx.ins().select(gt, a, b)
|
||||
});
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.smin.v") => {
|
||||
intrinsic_args!(fx, args => (x, y); intrinsic);
|
||||
|
||||
simd_pair_for_each_lane(
|
||||
fx,
|
||||
x,
|
||||
y,
|
||||
ret,
|
||||
&|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
|
||||
let gt = fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane);
|
||||
fx.bcx.ins().select(gt, x_lane, y_lane)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.umin.v") => {
|
||||
intrinsic_args!(fx, args => (x, y); intrinsic);
|
||||
|
||||
simd_pair_for_each_lane(
|
||||
fx,
|
||||
x,
|
||||
y,
|
||||
ret,
|
||||
&|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
|
||||
let gt = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, x_lane, y_lane);
|
||||
fx.bcx.ins().select(gt, x_lane, y_lane)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.sminv.i") => {
|
||||
intrinsic_args!(fx, args => (v); intrinsic);
|
||||
|
||||
simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
|
||||
let gt = fx.bcx.ins().icmp(IntCC::SignedLessThan, a, b);
|
||||
fx.bcx.ins().select(gt, a, b)
|
||||
});
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.uminv.i") => {
|
||||
intrinsic_args!(fx, args => (v); intrinsic);
|
||||
|
||||
simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
|
||||
let gt = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, a, b);
|
||||
fx.bcx.ins().select(gt, a, b)
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.sshl.v")
|
||||
|| intrinsic.starts_with("llvm.aarch64.neon.sqshl.v")
|
||||
// FIXME split this one out once saturating is implemented
|
||||
|| intrinsic.starts_with("llvm.aarch64.neon.sqshlu.v") =>
|
||||
{
|
||||
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||
|
||||
simd_pair_for_each_lane(fx, a, b, ret, &|fx, _lane_ty, _res_lane_ty, a, b| {
|
||||
// FIXME saturate?
|
||||
fx.bcx.ins().ishl(a, b)
|
||||
});
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.sqshrn.v") => {
|
||||
let (a, imm32) = match args {
|
||||
[a, imm32] => (a, imm32),
|
||||
_ => bug!("wrong number of args for intrinsic {intrinsic}"),
|
||||
};
|
||||
let a = codegen_operand(fx, a);
|
||||
let imm32 = crate::constant::mir_operand_get_const_val(fx, imm32)
|
||||
.expect("llvm.aarch64.neon.sqshrn.v* imm32 not const");
|
||||
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm32
|
||||
.try_to_bits(Size::from_bytes(4))
|
||||
.unwrap_or_else(|| panic!("imm32 not scalar: {:?}", imm32))
|
||||
{
|
||||
imm32 if imm32 < 32 => fx.bcx.ins().sshr_imm(lane, i64::from(imm32 as u8)),
|
||||
_ => fx.bcx.ins().iconst(types::I32, 0),
|
||||
});
|
||||
}
|
||||
|
||||
_ if intrinsic.starts_with("llvm.aarch64.neon.sqshrun.v") => {
|
||||
let (a, imm32) = match args {
|
||||
[a, imm32] => (a, imm32),
|
||||
_ => bug!("wrong number of args for intrinsic {intrinsic}"),
|
||||
};
|
||||
let a = codegen_operand(fx, a);
|
||||
let imm32 = crate::constant::mir_operand_get_const_val(fx, imm32)
|
||||
.expect("llvm.aarch64.neon.sqshrn.v* imm32 not const");
|
||||
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm32
|
||||
.try_to_bits(Size::from_bytes(4))
|
||||
.unwrap_or_else(|| panic!("imm32 not scalar: {:?}", imm32))
|
||||
{
|
||||
imm32 if imm32 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm32 as u8)),
|
||||
_ => fx.bcx.ins().iconst(types::I32, 0),
|
||||
});
|
||||
}
|
||||
*/
|
||||
_ => {
|
||||
fx.tcx.sess.warn(&format!(
|
||||
"unsupported AArch64 llvm intrinsic {}; replacing with trap",
|
||||
intrinsic
|
||||
));
|
||||
crate::trap::trap_unimplemented(fx, intrinsic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let dest = target.expect("all llvm intrinsics used by stdlib should return");
|
||||
let ret_block = fx.get_block(dest);
|
||||
fx.bcx.ins().jump(ret_block, &[]);
|
||||
}
|
||||
197
compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
Normal file
197
compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
//! Emulate x86 LLVM intrinsics
|
||||
|
||||
use crate::intrinsics::*;
|
||||
use crate::prelude::*;
|
||||
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
|
||||
pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
intrinsic: &str,
|
||||
_substs: SubstsRef<'tcx>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
ret: CPlace<'tcx>,
|
||||
target: Option<BasicBlock>,
|
||||
) {
|
||||
match intrinsic {
|
||||
"llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
|
||||
// Spin loop hint
|
||||
}
|
||||
|
||||
// Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
|
||||
"llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
|
||||
intrinsic_args!(fx, args => (a); intrinsic);
|
||||
|
||||
let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let lane_ty = fx.clif_type(lane_ty).unwrap();
|
||||
assert!(lane_count <= 32);
|
||||
|
||||
let mut res = fx.bcx.ins().iconst(types::I32, 0);
|
||||
|
||||
for lane in (0..lane_count).rev() {
|
||||
let a_lane = a.value_lane(fx, lane).load_scalar(fx);
|
||||
|
||||
// cast float to int
|
||||
let a_lane = match lane_ty {
|
||||
types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane),
|
||||
types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane),
|
||||
_ => a_lane,
|
||||
};
|
||||
|
||||
// extract sign bit of an int
|
||||
let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1));
|
||||
|
||||
// shift sign bit into result
|
||||
let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false);
|
||||
res = fx.bcx.ins().ishl_imm(res, 1);
|
||||
res = fx.bcx.ins().bor(res, a_lane_sign);
|
||||
}
|
||||
|
||||
let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
|
||||
ret.write_cvalue(fx, res);
|
||||
}
|
||||
"llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
|
||||
let (x, y, kind) = match args {
|
||||
[x, y, kind] => (x, y, kind),
|
||||
_ => bug!("wrong number of args for intrinsic {intrinsic}"),
|
||||
};
|
||||
let x = codegen_operand(fx, x);
|
||||
let y = codegen_operand(fx, y);
|
||||
let kind = crate::constant::mir_operand_get_const_val(fx, kind)
|
||||
.expect("llvm.x86.sse2.cmp.* kind not const");
|
||||
|
||||
let flt_cc = match kind
|
||||
.try_to_bits(Size::from_bytes(1))
|
||||
.unwrap_or_else(|| panic!("kind not scalar: {:?}", kind))
|
||||
{
|
||||
0 => FloatCC::Equal,
|
||||
1 => FloatCC::LessThan,
|
||||
2 => FloatCC::LessThanOrEqual,
|
||||
7 => FloatCC::Ordered,
|
||||
3 => FloatCC::Unordered,
|
||||
4 => FloatCC::NotEqual,
|
||||
5 => FloatCC::UnorderedOrGreaterThanOrEqual,
|
||||
6 => FloatCC::UnorderedOrGreaterThan,
|
||||
kind => unreachable!("kind {:?}", kind),
|
||||
};
|
||||
|
||||
simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
|
||||
let res_lane = match lane_ty.kind() {
|
||||
ty::Float(_) => fx.bcx.ins().fcmp(flt_cc, x_lane, y_lane),
|
||||
_ => unreachable!("{:?}", lane_ty),
|
||||
};
|
||||
bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
|
||||
});
|
||||
}
|
||||
"llvm.x86.sse2.psrli.d" => {
|
||||
let (a, imm8) = match args {
|
||||
[a, imm8] => (a, imm8),
|
||||
_ => bug!("wrong number of args for intrinsic {intrinsic}"),
|
||||
};
|
||||
let a = codegen_operand(fx, a);
|
||||
let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
|
||||
.expect("llvm.x86.sse2.psrli.d imm8 not const");
|
||||
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
|
||||
.try_to_bits(Size::from_bytes(4))
|
||||
.unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
|
||||
{
|
||||
imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
|
||||
_ => fx.bcx.ins().iconst(types::I32, 0),
|
||||
});
|
||||
}
|
||||
"llvm.x86.sse2.pslli.d" => {
|
||||
let (a, imm8) = match args {
|
||||
[a, imm8] => (a, imm8),
|
||||
_ => bug!("wrong number of args for intrinsic {intrinsic}"),
|
||||
};
|
||||
let a = codegen_operand(fx, a);
|
||||
let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
|
||||
.expect("llvm.x86.sse2.psrli.d imm8 not const");
|
||||
|
||||
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
|
||||
.try_to_bits(Size::from_bytes(4))
|
||||
.unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
|
||||
{
|
||||
imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
|
||||
_ => fx.bcx.ins().iconst(types::I32, 0),
|
||||
});
|
||||
}
|
||||
"llvm.x86.sse2.storeu.dq" => {
|
||||
intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
|
||||
let mem_addr = mem_addr.load_scalar(fx);
|
||||
|
||||
// FIXME correctly handle the unalignment
|
||||
let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
|
||||
dest.write_cvalue(fx, a);
|
||||
}
|
||||
"llvm.x86.addcarry.64" => {
|
||||
intrinsic_args!(fx, args => (c_in, a, b); intrinsic);
|
||||
let c_in = c_in.load_scalar(fx);
|
||||
|
||||
llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b);
|
||||
}
|
||||
"llvm.x86.subborrow.64" => {
|
||||
intrinsic_args!(fx, args => (b_in, a, b); intrinsic);
|
||||
let b_in = b_in.load_scalar(fx);
|
||||
|
||||
llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
|
||||
}
|
||||
_ => {
|
||||
fx.tcx.sess.warn(&format!(
|
||||
"unsupported x86 llvm intrinsic {}; replacing with trap",
|
||||
intrinsic
|
||||
));
|
||||
crate::trap::trap_unimplemented(fx, intrinsic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let dest = target.expect("all llvm intrinsics used by stdlib should return");
|
||||
let ret_block = fx.get_block(dest);
|
||||
fx.bcx.ins().jump(ret_block, &[]);
|
||||
}
|
||||
|
||||
// llvm.x86.avx2.vperm2i128
|
||||
// llvm.x86.ssse3.pshuf.b.128
|
||||
// llvm.x86.avx2.pshuf.b
|
||||
// llvm.x86.avx2.psrli.w
|
||||
// llvm.x86.sse2.psrli.w
|
||||
|
||||
fn llvm_add_sub<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
bin_op: BinOp,
|
||||
ret: CPlace<'tcx>,
|
||||
cb_in: Value,
|
||||
a: CValue<'tcx>,
|
||||
b: CValue<'tcx>,
|
||||
) {
|
||||
assert_eq!(
|
||||
a.layout().ty,
|
||||
fx.tcx.types.u64,
|
||||
"llvm.x86.addcarry.64/llvm.x86.subborrow.64 second operand must be u64"
|
||||
);
|
||||
assert_eq!(
|
||||
b.layout().ty,
|
||||
fx.tcx.types.u64,
|
||||
"llvm.x86.addcarry.64/llvm.x86.subborrow.64 third operand must be u64"
|
||||
);
|
||||
|
||||
// c + carry -> c + first intermediate carry or borrow respectively
|
||||
let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
|
||||
let c = int0.value_field(fx, mir::Field::new(0));
|
||||
let cb0 = int0.value_field(fx, mir::Field::new(1)).load_scalar(fx);
|
||||
|
||||
// c + carry -> c + second intermediate carry or borrow respectively
|
||||
let cb_in_as_u64 = fx.bcx.ins().uextend(types::I64, cb_in);
|
||||
let cb_in_as_u64 = CValue::by_val(cb_in_as_u64, fx.layout_of(fx.tcx.types.u64));
|
||||
let int1 = crate::num::codegen_checked_int_binop(fx, bin_op, c, cb_in_as_u64);
|
||||
let (c, cb1) = int1.load_scalar_pair(fx);
|
||||
|
||||
// carry0 | carry1 -> carry or borrow respectively
|
||||
let cb_out = fx.bcx.ins().bor(cb0, cb1);
|
||||
|
||||
let layout = fx.layout_of(fx.tcx.mk_tup([fx.tcx.types.u8, fx.tcx.types.u64].iter()));
|
||||
let val = CValue::by_val_pair(cb_out, c, layout);
|
||||
ret.write_cvalue(fx, val);
|
||||
}
|
||||
|
|
@ -14,6 +14,8 @@ macro_rules! intrinsic_args {
|
|||
|
||||
mod cpuid;
|
||||
mod llvm;
|
||||
mod llvm_aarch64;
|
||||
mod llvm_x86;
|
||||
mod simd;
|
||||
|
||||
pub(crate) use cpuid::codegen_cpuid_call;
|
||||
|
|
@ -195,8 +197,7 @@ fn bool_to_zero_or_max_uint<'tcx>(
|
|||
ty => ty,
|
||||
};
|
||||
|
||||
let val = fx.bcx.ins().bint(int_ty, val);
|
||||
let mut res = fx.bcx.ins().ineg(val);
|
||||
let mut res = fx.bcx.ins().bmask(int_ty, val);
|
||||
|
||||
if ty.is_float() {
|
||||
res = fx.bcx.ins().bitcast(ty, res);
|
||||
|
|
@ -632,85 +633,15 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
ret.write_cvalue(fx, res);
|
||||
}
|
||||
sym::bswap => {
|
||||
// FIXME(CraneStation/cranelift#794) add bswap instruction to cranelift
|
||||
fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
|
||||
match bcx.func.dfg.value_type(v) {
|
||||
types::I8 => v,
|
||||
|
||||
// https://code.woboq.org/gcc/include/bits/byteswap.h.html
|
||||
types::I16 => {
|
||||
let tmp1 = bcx.ins().ishl_imm(v, 8);
|
||||
let n1 = bcx.ins().band_imm(tmp1, 0xFF00);
|
||||
|
||||
let tmp2 = bcx.ins().ushr_imm(v, 8);
|
||||
let n2 = bcx.ins().band_imm(tmp2, 0x00FF);
|
||||
|
||||
bcx.ins().bor(n1, n2)
|
||||
}
|
||||
types::I32 => {
|
||||
let tmp1 = bcx.ins().ishl_imm(v, 24);
|
||||
let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000);
|
||||
|
||||
let tmp2 = bcx.ins().ishl_imm(v, 8);
|
||||
let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000);
|
||||
|
||||
let tmp3 = bcx.ins().ushr_imm(v, 8);
|
||||
let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00);
|
||||
|
||||
let tmp4 = bcx.ins().ushr_imm(v, 24);
|
||||
let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF);
|
||||
|
||||
let or_tmp1 = bcx.ins().bor(n1, n2);
|
||||
let or_tmp2 = bcx.ins().bor(n3, n4);
|
||||
bcx.ins().bor(or_tmp1, or_tmp2)
|
||||
}
|
||||
types::I64 => {
|
||||
let tmp1 = bcx.ins().ishl_imm(v, 56);
|
||||
let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000_0000_0000u64 as i64);
|
||||
|
||||
let tmp2 = bcx.ins().ishl_imm(v, 40);
|
||||
let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000_0000_0000u64 as i64);
|
||||
|
||||
let tmp3 = bcx.ins().ishl_imm(v, 24);
|
||||
let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00_0000_0000u64 as i64);
|
||||
|
||||
let tmp4 = bcx.ins().ishl_imm(v, 8);
|
||||
let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF_0000_0000u64 as i64);
|
||||
|
||||
let tmp5 = bcx.ins().ushr_imm(v, 8);
|
||||
let n5 = bcx.ins().band_imm(tmp5, 0x0000_0000_FF00_0000u64 as i64);
|
||||
|
||||
let tmp6 = bcx.ins().ushr_imm(v, 24);
|
||||
let n6 = bcx.ins().band_imm(tmp6, 0x0000_0000_00FF_0000u64 as i64);
|
||||
|
||||
let tmp7 = bcx.ins().ushr_imm(v, 40);
|
||||
let n7 = bcx.ins().band_imm(tmp7, 0x0000_0000_0000_FF00u64 as i64);
|
||||
|
||||
let tmp8 = bcx.ins().ushr_imm(v, 56);
|
||||
let n8 = bcx.ins().band_imm(tmp8, 0x0000_0000_0000_00FFu64 as i64);
|
||||
|
||||
let or_tmp1 = bcx.ins().bor(n1, n2);
|
||||
let or_tmp2 = bcx.ins().bor(n3, n4);
|
||||
let or_tmp3 = bcx.ins().bor(n5, n6);
|
||||
let or_tmp4 = bcx.ins().bor(n7, n8);
|
||||
|
||||
let or_tmp5 = bcx.ins().bor(or_tmp1, or_tmp2);
|
||||
let or_tmp6 = bcx.ins().bor(or_tmp3, or_tmp4);
|
||||
bcx.ins().bor(or_tmp5, or_tmp6)
|
||||
}
|
||||
types::I128 => {
|
||||
let (lo, hi) = bcx.ins().isplit(v);
|
||||
let lo = swap(bcx, lo);
|
||||
let hi = swap(bcx, hi);
|
||||
bcx.ins().iconcat(hi, lo)
|
||||
}
|
||||
ty => unreachable!("bswap {}", ty),
|
||||
}
|
||||
}
|
||||
intrinsic_args!(fx, args => (arg); intrinsic);
|
||||
let val = arg.load_scalar(fx);
|
||||
|
||||
let res = CValue::by_val(swap(&mut fx.bcx, val), arg.layout());
|
||||
let res = if fx.bcx.func.dfg.value_type(val) == types::I8 {
|
||||
val
|
||||
} else {
|
||||
fx.bcx.ins().bswap(val)
|
||||
};
|
||||
let res = CValue::by_val(res, arg.layout());
|
||||
ret.write_cvalue(fx, res);
|
||||
}
|
||||
sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
|
||||
|
|
@ -936,8 +867,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
let old = fx.bcx.ins().atomic_cas(MemFlags::trusted(), ptr, test_old, new);
|
||||
let is_eq = fx.bcx.ins().icmp(IntCC::Equal, old, test_old);
|
||||
|
||||
let ret_val =
|
||||
CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout());
|
||||
let ret_val = CValue::by_val_pair(old, is_eq, ret.layout());
|
||||
ret.write_cvalue(fx, ret_val)
|
||||
}
|
||||
|
||||
|
|
@ -1259,8 +1189,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
flags.set_notrap();
|
||||
let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
|
||||
let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
|
||||
let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
|
||||
fx.bcx.ins().bint(types::I8, eq)
|
||||
fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val)
|
||||
} else {
|
||||
// Just call `memcmp` (like slices do in core) when the
|
||||
// size is too large or it's not a power-of-two.
|
||||
|
|
@ -1270,8 +1199,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
let returns = vec![AbiParam::new(types::I32)];
|
||||
let args = &[lhs_ref, rhs_ref, bytes_val];
|
||||
let cmp = fx.lib_call("memcmp", params, returns, args)[0];
|
||||
let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
|
||||
fx.bcx.ins().bint(types::I8, eq)
|
||||
fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0)
|
||||
};
|
||||
ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,10 +112,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let ty = fx.clif_type(res_lane_ty).unwrap();
|
||||
|
||||
let res_lane = fx.bcx.ins().bint(ty, res_lane);
|
||||
fx.bcx.ins().ineg(res_lane)
|
||||
bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -716,7 +713,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
|
||||
let res_type =
|
||||
Type::int_with_byte_size(u16::try_from(expected_bytes).unwrap()).unwrap();
|
||||
let mut res = fx.bcx.ins().iconst(res_type, 0);
|
||||
let mut res = type_zero_value(&mut fx.bcx, res_type);
|
||||
|
||||
let lanes = match fx.tcx.sess.target.endian {
|
||||
Endian::Big => Box::new(0..lane_count) as Box<dyn Iterator<Item = u64>>,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)],
|
||||
call_conv: crate::conv_to_call_conv(
|
||||
tcx.sess.target.options.entry_abi,
|
||||
CallConv::triple_default(m.isa().triple()),
|
||||
m.target_config().default_call_conv,
|
||||
),
|
||||
};
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
|
||||
|
||||
let main_name = tcx.symbol_name(instance).name;
|
||||
let main_sig = get_function_sig(tcx, m.isa().triple(), instance);
|
||||
let main_sig = get_function_sig(tcx, m.target_config().default_call_conv, instance);
|
||||
let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap();
|
||||
|
||||
let mut ctx = Context::new();
|
||||
|
|
@ -119,7 +119,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
.polymorphize(tcx);
|
||||
|
||||
let report_name = tcx.symbol_name(report).name;
|
||||
let report_sig = get_function_sig(tcx, m.isa().triple(), report);
|
||||
let report_sig = get_function_sig(tcx, m.target_config().default_call_conv, report);
|
||||
let report_func_id =
|
||||
m.declare_function(report_name, Linkage::Import, &report_sig).unwrap();
|
||||
let report_func_ref = m.declare_func_in_func(report_func_id, &mut bcx.func);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ fn codegen_compare_bin_op<'tcx>(
|
|||
) -> CValue<'tcx> {
|
||||
let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
|
||||
let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
|
||||
let val = fx.bcx.ins().bint(types::I8, val);
|
||||
CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
|
||||
}
|
||||
|
||||
|
|
@ -290,8 +289,6 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
|
|||
_ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, in_lhs, in_rhs),
|
||||
};
|
||||
|
||||
let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
|
||||
|
||||
let out_layout = fx.layout_of(fx.tcx.mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter()));
|
||||
CValue::by_val_pair(res, has_overflow, out_layout)
|
||||
}
|
||||
|
|
@ -368,7 +365,6 @@ pub(crate) fn codegen_float_binop<'tcx>(
|
|||
_ => unreachable!(),
|
||||
};
|
||||
let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs);
|
||||
let val = fx.bcx.ins().bint(types::I8, val);
|
||||
return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool));
|
||||
}
|
||||
_ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
|
||||
|
|
@ -440,7 +436,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>(
|
|||
_ => panic!("bin_op {:?} on ptr", bin_op),
|
||||
};
|
||||
|
||||
CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool))
|
||||
CValue::by_val(res, fx.layout_of(fx.tcx.types.bool))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,19 +3,6 @@
|
|||
use cranelift_codegen::ir::{condcodes::IntCC, InstructionData, Opcode, Value, ValueDef};
|
||||
use cranelift_frontend::FunctionBuilder;
|
||||
|
||||
/// If the given value was produced by a `bint` instruction, return it's input, otherwise return the
|
||||
/// given value.
|
||||
pub(crate) fn maybe_unwrap_bint(bcx: &mut FunctionBuilder<'_>, arg: Value) -> Value {
|
||||
if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
|
||||
match bcx.func.dfg[arg_inst] {
|
||||
InstructionData::Unary { opcode: Opcode::Bint, arg } => arg,
|
||||
_ => arg,
|
||||
}
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
}
|
||||
|
||||
/// If the given value was produced by the lowering of `Rvalue::Not` return the input and true,
|
||||
/// otherwise return the given value and false.
|
||||
pub(crate) fn maybe_unwrap_bool_not(bcx: &mut FunctionBuilder<'_>, arg: Value) -> (Value, bool) {
|
||||
|
|
@ -48,13 +35,6 @@ pub(crate) fn maybe_known_branch_taken(
|
|||
};
|
||||
|
||||
match bcx.func.dfg[arg_inst] {
|
||||
InstructionData::UnaryBool { opcode: Opcode::Bconst, imm } => {
|
||||
if test_zero {
|
||||
Some(!imm)
|
||||
} else {
|
||||
Some(imm)
|
||||
}
|
||||
}
|
||||
InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => {
|
||||
if test_zero {
|
||||
Some(imm.bits() == 0)
|
||||
|
|
|
|||
|
|
@ -392,7 +392,7 @@ impl<'tcx> CPlace<'tcx> {
|
|||
local: Local,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
) -> CPlace<'tcx> {
|
||||
let var = Variable::with_u32(fx.next_ssa_var);
|
||||
let var = Variable::from_u32(fx.next_ssa_var);
|
||||
fx.next_ssa_var += 1;
|
||||
fx.bcx.declare_var(var, fx.clif_type(layout.ty).unwrap());
|
||||
CPlace { inner: CPlaceInner::Var(local, var), layout }
|
||||
|
|
@ -403,9 +403,9 @@ impl<'tcx> CPlace<'tcx> {
|
|||
local: Local,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
) -> CPlace<'tcx> {
|
||||
let var1 = Variable::with_u32(fx.next_ssa_var);
|
||||
let var1 = Variable::from_u32(fx.next_ssa_var);
|
||||
fx.next_ssa_var += 1;
|
||||
let var2 = Variable::with_u32(fx.next_ssa_var);
|
||||
let var2 = Variable::from_u32(fx.next_ssa_var);
|
||||
fx.next_ssa_var += 1;
|
||||
|
||||
let (ty1, ty2) = fx.clif_pair_type(layout.ty).unwrap();
|
||||
|
|
@ -515,9 +515,7 @@ impl<'tcx> CPlace<'tcx> {
|
|||
| (types::F32, types::I32)
|
||||
| (types::I64, types::F64)
|
||||
| (types::F64, types::I64) => fx.bcx.ins().bitcast(dst_ty, data),
|
||||
_ if src_ty.is_vector() && dst_ty.is_vector() => {
|
||||
fx.bcx.ins().raw_bitcast(dst_ty, data)
|
||||
}
|
||||
_ if src_ty.is_vector() && dst_ty.is_vector() => fx.bcx.ins().bitcast(dst_ty, data),
|
||||
_ if src_ty.is_vector() || dst_ty.is_vector() => {
|
||||
// FIXME do something more efficient for transmutes between vectors and integers.
|
||||
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
|
||||
|
|
@ -590,7 +588,10 @@ impl<'tcx> CPlace<'tcx> {
|
|||
return;
|
||||
}
|
||||
CPlaceInner::VarPair(_local, var1, var2) => {
|
||||
let (data1, data2) = CValue(from.0, dst_layout).load_scalar_pair(fx);
|
||||
let (ptr, meta) = from.force_stack(fx);
|
||||
assert!(meta.is_none());
|
||||
let (data1, data2) =
|
||||
CValue(CValueInner::ByRef(ptr, None), dst_layout).load_scalar_pair(fx);
|
||||
let (dst_ty1, dst_ty2) = fx.clif_pair_type(self.layout().ty).unwrap();
|
||||
transmute_value(fx, var1, data1, dst_ty1);
|
||||
transmute_value(fx, var2, data2, dst_ty2);
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
exec ./y.rs test
|
||||
exec ./y.rs test "$@"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# This block is ignored by rustc
|
||||
set -e
|
||||
echo "[BUILD] y.rs" 1>&2
|
||||
rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1
|
||||
rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021
|
||||
exec ${0/.rs/.bin} $@
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1119,18 +1119,18 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
// TODO(antoyo)
|
||||
}
|
||||
|
||||
fn cleanup_landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let field1 = self.context.new_field(None, self.u8_type.make_pointer(), "landing_pad_field_1");
|
||||
let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1");
|
||||
let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]);
|
||||
self.current_func().new_local(None, struct_type.as_type(), "landing_pad")
|
||||
.to_rvalue()
|
||||
fn cleanup_landing_pad(&mut self, _pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
|
||||
(
|
||||
self.current_func().new_local(None, self.u8_type.make_pointer(), "landing_pad0")
|
||||
.to_rvalue(),
|
||||
self.current_func().new_local(None, self.i32_type, "landing_pad1").to_rvalue(),
|
||||
)
|
||||
// TODO(antoyo): Properly implement unwinding.
|
||||
// the above is just to make the compilation work as it seems
|
||||
// rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort.
|
||||
}
|
||||
|
||||
fn resume(&mut self, _exn: RValue<'gcc>) {
|
||||
fn resume(&mut self, _exn0: RValue<'gcc>, _exn1: RValue<'gcc>) {
|
||||
// TODO(bjorn3): Properly implement unwinding.
|
||||
self.unreachable();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ use crate::errors::{
|
|||
use crate::llvm::archive_ro::{ArchiveRO, Child};
|
||||
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
|
||||
use rustc_codegen_ssa::back::archive::{
|
||||
get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder,
|
||||
ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind,
|
||||
get_native_object_symbols, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
|
||||
ArchiveBuilderBuilder, UnknownArchiveKind,
|
||||
};
|
||||
|
||||
use rustc_session::cstore::DllImport;
|
||||
|
|
@ -66,13 +66,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
|
|||
archive: &Path,
|
||||
skip: Box<dyn FnMut(&str) -> bool + 'static>,
|
||||
) -> io::Result<()> {
|
||||
let mut archive = archive.to_path_buf();
|
||||
if self.sess.target.llvm_target.contains("-apple-macosx") {
|
||||
if let Some(new_archive) = try_extract_macho_fat_archive(&self.sess, &archive)? {
|
||||
archive = new_archive
|
||||
}
|
||||
}
|
||||
let archive_ro = match ArchiveRO::open(&archive) {
|
||||
let archive_ro = match ArchiveRO::open(archive) {
|
||||
Ok(ar) => ar,
|
||||
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
|
||||
};
|
||||
|
|
@ -80,7 +74,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
|
|||
return Ok(());
|
||||
}
|
||||
self.additions.push(Addition::Archive {
|
||||
path: archive,
|
||||
path: archive.to_path_buf(),
|
||||
archive: archive_ro,
|
||||
skip: Box::new(skip),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -133,6 +133,10 @@ fn prepare_lto(
|
|||
}
|
||||
}
|
||||
|
||||
// __llvm_profile_counter_bias is pulled in at link time by an undefined reference to
|
||||
// __llvm_profile_runtime, therefore we won't know until link time if this symbol
|
||||
// should have default visibility.
|
||||
symbols_below_threshold.push(CString::new("__llvm_profile_counter_bias").unwrap());
|
||||
Ok((symbols_below_threshold, upstream_modules))
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +210,7 @@ pub(crate) fn run_thin(
|
|||
}
|
||||
|
||||
pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBuffer) {
|
||||
let name = module.name.clone();
|
||||
let name = module.name;
|
||||
let buffer = ThinBuffer::new(module.module_llvm.llmod(), true);
|
||||
(name, buffer)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -979,15 +979,20 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn cleanup_landing_pad(&mut self, ty: &'ll Type, pers_fn: &'ll Value) -> &'ll Value {
|
||||
fn cleanup_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) {
|
||||
let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
|
||||
let landing_pad = self.landing_pad(ty, pers_fn, 1 /* FIXME should this be 0? */);
|
||||
unsafe {
|
||||
llvm::LLVMSetCleanup(landing_pad, llvm::True);
|
||||
}
|
||||
landing_pad
|
||||
(self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1))
|
||||
}
|
||||
|
||||
fn resume(&mut self, exn: &'ll Value) {
|
||||
fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) {
|
||||
let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
|
||||
let mut exn = self.const_undef(ty);
|
||||
exn = self.insert_value(exn, exn0, 0);
|
||||
exn = self.insert_value(exn, exn1, 1);
|
||||
unsafe {
|
||||
llvm::LLVMBuildResume(self.llbuilder, exn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -424,7 +424,9 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
typeid: &'ll Value,
|
||||
) -> Self::Value {
|
||||
let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32);
|
||||
self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid])
|
||||
let type_checked_load =
|
||||
self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]);
|
||||
self.extract_value(type_checked_load, 0)
|
||||
}
|
||||
|
||||
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use tempfile::Builder as TempFileBuilder;
|
|||
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
// Re-exporting for rustc_codegen_llvm::back::archive
|
||||
|
|
@ -116,12 +116,11 @@ impl<'a> ArArchiveBuilder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn try_filter_fat_archs(
|
||||
fn try_filter_fat_archs<'a>(
|
||||
archs: object::read::Result<&[impl FatArch]>,
|
||||
target_arch: object::Architecture,
|
||||
archive_path: &Path,
|
||||
archive_map_data: &[u8],
|
||||
) -> io::Result<Option<PathBuf>> {
|
||||
archive_map_data: &'a [u8],
|
||||
) -> io::Result<Option<(&'a [u8], u64)>> {
|
||||
let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||
|
||||
let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() {
|
||||
|
|
@ -129,38 +128,30 @@ fn try_filter_fat_archs(
|
|||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let (mut new_f, extracted_path) = tempfile::Builder::new()
|
||||
.suffix(archive_path.file_name().unwrap())
|
||||
.tempfile()?
|
||||
.keep()
|
||||
.unwrap();
|
||||
|
||||
new_f.write_all(
|
||||
Ok(Some((
|
||||
desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
|
||||
)?;
|
||||
|
||||
Ok(Some(extracted_path))
|
||||
desired.offset().into(),
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn try_extract_macho_fat_archive(
|
||||
pub fn try_extract_macho_fat_archive<'a>(
|
||||
sess: &Session,
|
||||
archive_path: &Path,
|
||||
) -> io::Result<Option<PathBuf>> {
|
||||
let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
|
||||
archive_bytes: &'a [u8],
|
||||
) -> io::Result<Option<(&'a [u8], u64)>> {
|
||||
let target_arch = match sess.target.arch.as_ref() {
|
||||
"aarch64" => object::Architecture::Aarch64,
|
||||
"x86_64" => object::Architecture::X86_64,
|
||||
_ => return Ok(None),
|
||||
};
|
||||
|
||||
match object::macho::FatHeader::parse(&*archive_map) {
|
||||
match object::macho::FatHeader::parse(archive_bytes) {
|
||||
Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => {
|
||||
let archs = object::macho::FatHeader::parse_arch32(&*archive_map);
|
||||
try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
|
||||
let archs = object::macho::FatHeader::parse_arch32(archive_bytes);
|
||||
try_filter_fat_archs(archs, target_arch, archive_bytes)
|
||||
}
|
||||
Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => {
|
||||
let archs = object::macho::FatHeader::parse_arch64(&*archive_map);
|
||||
try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
|
||||
let archs = object::macho::FatHeader::parse_arch64(archive_bytes);
|
||||
try_filter_fat_archs(archs, target_arch, archive_bytes)
|
||||
}
|
||||
// Not a FatHeader at all, just return None.
|
||||
_ => Ok(None),
|
||||
|
|
@ -173,21 +164,24 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
|
|||
archive_path: &Path,
|
||||
mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
|
||||
) -> io::Result<()> {
|
||||
let mut archive_path = archive_path.to_path_buf();
|
||||
if self.sess.target.llvm_target.contains("-apple-macosx") {
|
||||
if let Some(new_archive_path) =
|
||||
try_extract_macho_fat_archive(&self.sess, &archive_path)?
|
||||
{
|
||||
archive_path = new_archive_path
|
||||
}
|
||||
}
|
||||
|
||||
let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
|
||||
if self.src_archives.iter().any(|archive| archive.0 == archive_path) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
|
||||
let archive = ArchiveFile::parse(&*archive_map)
|
||||
let (archive_bytes, offset) = if self.sess.target.llvm_target.contains("-apple-macosx") {
|
||||
if let Some((sub_archive, archive_offset)) =
|
||||
try_extract_macho_fat_archive(&self.sess, &*archive_map)?
|
||||
{
|
||||
(sub_archive, Some(archive_offset))
|
||||
} else {
|
||||
(&*archive_map, None)
|
||||
}
|
||||
} else {
|
||||
(&*archive_map, None)
|
||||
};
|
||||
|
||||
let archive = ArchiveFile::parse(&*archive_bytes)
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
|
||||
let archive_index = self.src_archives.len();
|
||||
|
||||
|
|
@ -196,9 +190,13 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
|
|||
let file_name = String::from_utf8(entry.name().to_vec())
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
|
||||
if !skip(&file_name) {
|
||||
let mut range = entry.file_range();
|
||||
if let Some(offset) = offset {
|
||||
range.0 += offset;
|
||||
}
|
||||
self.entries.push((
|
||||
file_name.into_bytes(),
|
||||
ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
|
||||
ArchiveEntry::FromArchive { archive_index, file_range: range },
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
|||
use rustc_target::abi::{Align, Size, VariantIdx};
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::convert::TryFrom;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
|
|
|||
688
compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Normal file
688
compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
use rustc_ast::{ast, MetaItemKind, NestedMetaItem};
|
||||
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::mir::mono::Linkage;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self as ty, DefIdTree, TyCtxt};
|
||||
use rustc_session::{lint, parse::feature_err};
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_target::spec::{abi, SanitizerSet};
|
||||
|
||||
use crate::target_features::from_target_feature;
|
||||
use crate::{errors::ExpectedUsedSymbol, target_features::check_target_feature_trait_unsafe};
|
||||
|
||||
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
|
||||
use rustc_middle::mir::mono::Linkage::*;
|
||||
|
||||
// Use the names from src/llvm/docs/LangRef.rst here. Most types are only
|
||||
// applicable to variable declarations and may not really make sense for
|
||||
// Rust code in the first place but allow them anyway and trust that the
|
||||
// user knows what they're doing. Who knows, unanticipated use cases may pop
|
||||
// up in the future.
|
||||
//
|
||||
// ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
|
||||
// and don't have to be, LLVM treats them as no-ops.
|
||||
match name {
|
||||
"appending" => Appending,
|
||||
"available_externally" => AvailableExternally,
|
||||
"common" => Common,
|
||||
"extern_weak" => ExternalWeak,
|
||||
"external" => External,
|
||||
"internal" => Internal,
|
||||
"linkonce" => LinkOnceAny,
|
||||
"linkonce_odr" => LinkOnceODR,
|
||||
"private" => Private,
|
||||
"weak" => WeakAny,
|
||||
"weak_odr" => WeakODR,
|
||||
_ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
|
||||
}
|
||||
}
|
||||
|
||||
fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
|
||||
if cfg!(debug_assertions) {
|
||||
let def_kind = tcx.def_kind(did);
|
||||
assert!(
|
||||
def_kind.has_codegen_attrs(),
|
||||
"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
|
||||
);
|
||||
}
|
||||
|
||||
let did = did.expect_local();
|
||||
let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
|
||||
let mut codegen_fn_attrs = CodegenFnAttrs::new();
|
||||
if tcx.should_inherit_track_caller(did) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
|
||||
}
|
||||
|
||||
let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
|
||||
|
||||
let mut inline_span = None;
|
||||
let mut link_ordinal_span = None;
|
||||
let mut no_sanitize_span = None;
|
||||
for attr in attrs.iter() {
|
||||
if attr.has_name(sym::cold) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
|
||||
} else if attr.has_name(sym::rustc_allocator) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
|
||||
} else if attr.has_name(sym::ffi_returns_twice) {
|
||||
if tcx.is_foreign_item(did) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
|
||||
} else {
|
||||
// `#[ffi_returns_twice]` is only allowed `extern fn`s.
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
attr.span,
|
||||
E0724,
|
||||
"`#[ffi_returns_twice]` may only be used on foreign functions"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
} else if attr.has_name(sym::ffi_pure) {
|
||||
if tcx.is_foreign_item(did) {
|
||||
if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
|
||||
// `#[ffi_const]` functions cannot be `#[ffi_pure]`
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
attr.span,
|
||||
E0757,
|
||||
"`#[ffi_const]` function cannot be `#[ffi_pure]`"
|
||||
)
|
||||
.emit();
|
||||
} else {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
|
||||
}
|
||||
} else {
|
||||
// `#[ffi_pure]` is only allowed on foreign functions
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
attr.span,
|
||||
E0755,
|
||||
"`#[ffi_pure]` may only be used on foreign functions"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
} else if attr.has_name(sym::ffi_const) {
|
||||
if tcx.is_foreign_item(did) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
|
||||
} else {
|
||||
// `#[ffi_const]` is only allowed on foreign functions
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
attr.span,
|
||||
E0756,
|
||||
"`#[ffi_const]` may only be used on foreign functions"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
} else if attr.has_name(sym::rustc_nounwind) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
|
||||
} else if attr.has_name(sym::rustc_reallocator) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
|
||||
} else if attr.has_name(sym::rustc_deallocator) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
|
||||
} else if attr.has_name(sym::rustc_allocator_zeroed) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
|
||||
} else if attr.has_name(sym::naked) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
|
||||
} else if attr.has_name(sym::no_mangle) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
||||
} else if attr.has_name(sym::no_coverage) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
|
||||
} else if attr.has_name(sym::rustc_std_internal_symbol) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
|
||||
} else if attr.has_name(sym::used) {
|
||||
let inner = attr.meta_item_list();
|
||||
match inner.as_deref() {
|
||||
Some([item]) if item.has_name(sym::linker) => {
|
||||
if !tcx.features().used_with_arg {
|
||||
feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::used_with_arg,
|
||||
attr.span,
|
||||
"`#[used(linker)]` is currently unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
|
||||
}
|
||||
Some([item]) if item.has_name(sym::compiler) => {
|
||||
if !tcx.features().used_with_arg {
|
||||
feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::used_with_arg,
|
||||
attr.span,
|
||||
"`#[used(compiler)]` is currently unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
|
||||
}
|
||||
Some(_) => {
|
||||
tcx.sess.emit_err(ExpectedUsedSymbol { span: attr.span });
|
||||
}
|
||||
None => {
|
||||
// Unfortunately, unconditionally using `llvm.used` causes
|
||||
// issues in handling `.init_array` with the gold linker,
|
||||
// but using `llvm.compiler.used` caused a nontrival amount
|
||||
// of unintentional ecosystem breakage -- particularly on
|
||||
// Mach-O targets.
|
||||
//
|
||||
// As a result, we emit `llvm.compiler.used` only on ELF
|
||||
// targets. This is somewhat ad-hoc, but actually follows
|
||||
// our pre-LLVM 13 behavior (prior to the ecosystem
|
||||
// breakage), and seems to match `clang`'s behavior as well
|
||||
// (both before and after LLVM 13), possibly because they
|
||||
// have similar compatibility concerns to us. See
|
||||
// https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
|
||||
// and following comments for some discussion of this, as
|
||||
// well as the comments in `rustc_codegen_llvm` where these
|
||||
// flags are handled.
|
||||
//
|
||||
// Anyway, to be clear: this is still up in the air
|
||||
// somewhat, and is subject to change in the future (which
|
||||
// is a good thing, because this would ideally be a bit
|
||||
// more firmed up).
|
||||
let is_like_elf = !(tcx.sess.target.is_like_osx
|
||||
|| tcx.sess.target.is_like_windows
|
||||
|| tcx.sess.target.is_like_wasm);
|
||||
codegen_fn_attrs.flags |= if is_like_elf {
|
||||
CodegenFnAttrFlags::USED
|
||||
} else {
|
||||
CodegenFnAttrFlags::USED_LINKER
|
||||
};
|
||||
}
|
||||
}
|
||||
} else if attr.has_name(sym::cmse_nonsecure_entry) {
|
||||
if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
attr.span,
|
||||
E0776,
|
||||
"`#[cmse_nonsecure_entry]` requires C ABI"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
if !tcx.sess.target.llvm_target.contains("thumbv8m") {
|
||||
struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
|
||||
.emit();
|
||||
}
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
|
||||
} else if attr.has_name(sym::thread_local) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
|
||||
} else if attr.has_name(sym::track_caller) {
|
||||
if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).abi() != abi::Abi::Rust {
|
||||
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
|
||||
.emit();
|
||||
}
|
||||
if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
|
||||
feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::closure_track_caller,
|
||||
attr.span,
|
||||
"`#[track_caller]` on closures is currently unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
|
||||
} else if attr.has_name(sym::export_name) {
|
||||
if let Some(s) = attr.value_str() {
|
||||
if s.as_str().contains('\0') {
|
||||
// `#[export_name = ...]` will be converted to a null-terminated string,
|
||||
// so it may not contain any null characters.
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
attr.span,
|
||||
E0648,
|
||||
"`export_name` may not contain null characters"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
codegen_fn_attrs.export_name = Some(s);
|
||||
}
|
||||
} else if attr.has_name(sym::target_feature) {
|
||||
if !tcx.is_closure(did.to_def_id())
|
||||
&& tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
|
||||
{
|
||||
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
|
||||
// The `#[target_feature]` attribute is allowed on
|
||||
// WebAssembly targets on all functions, including safe
|
||||
// ones. Other targets require that `#[target_feature]` is
|
||||
// only applied to unsafe functions (pending the
|
||||
// `target_feature_11` feature) because on most targets
|
||||
// execution of instructions that are not supported is
|
||||
// considered undefined behavior. For WebAssembly which is a
|
||||
// 100% safe target at execution time it's not possible to
|
||||
// execute undefined instructions, and even if a future
|
||||
// feature was added in some form for this it would be a
|
||||
// deterministic trap. There is no undefined behavior when
|
||||
// executing WebAssembly so `#[target_feature]` is allowed
|
||||
// on safe functions (but again, only for WebAssembly)
|
||||
//
|
||||
// Note that this is also allowed if `actually_rustdoc` so
|
||||
// if a target is documenting some wasm-specific code then
|
||||
// it's not spuriously denied.
|
||||
} else if !tcx.features().target_feature_11 {
|
||||
let mut err = feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::target_feature_11,
|
||||
attr.span,
|
||||
"`#[target_feature(..)]` can only be applied to `unsafe` functions",
|
||||
);
|
||||
err.span_label(tcx.def_span(did), "not an `unsafe` function");
|
||||
err.emit();
|
||||
} else {
|
||||
check_target_feature_trait_unsafe(tcx, did, attr.span);
|
||||
}
|
||||
}
|
||||
from_target_feature(
|
||||
tcx,
|
||||
attr,
|
||||
supported_target_features,
|
||||
&mut codegen_fn_attrs.target_features,
|
||||
);
|
||||
} else if attr.has_name(sym::linkage) {
|
||||
if let Some(val) = attr.value_str() {
|
||||
let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
|
||||
if tcx.is_foreign_item(did) {
|
||||
codegen_fn_attrs.import_linkage = linkage;
|
||||
} else {
|
||||
codegen_fn_attrs.linkage = linkage;
|
||||
}
|
||||
}
|
||||
} else if attr.has_name(sym::link_section) {
|
||||
if let Some(val) = attr.value_str() {
|
||||
if val.as_str().bytes().any(|b| b == 0) {
|
||||
let msg = format!(
|
||||
"illegal null byte in link_section \
|
||||
value: `{}`",
|
||||
&val
|
||||
);
|
||||
tcx.sess.span_err(attr.span, &msg);
|
||||
} else {
|
||||
codegen_fn_attrs.link_section = Some(val);
|
||||
}
|
||||
}
|
||||
} else if attr.has_name(sym::link_name) {
|
||||
codegen_fn_attrs.link_name = attr.value_str();
|
||||
} else if attr.has_name(sym::link_ordinal) {
|
||||
link_ordinal_span = Some(attr.span);
|
||||
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
|
||||
codegen_fn_attrs.link_ordinal = ordinal;
|
||||
}
|
||||
} else if attr.has_name(sym::no_sanitize) {
|
||||
no_sanitize_span = Some(attr.span);
|
||||
if let Some(list) = attr.meta_item_list() {
|
||||
for item in list.iter() {
|
||||
if item.has_name(sym::address) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
|
||||
} else if item.has_name(sym::cfi) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
|
||||
} else if item.has_name(sym::kcfi) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
|
||||
} else if item.has_name(sym::memory) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
|
||||
} else if item.has_name(sym::memtag) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
|
||||
} else if item.has_name(sym::shadow_call_stack) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
|
||||
} else if item.has_name(sym::thread) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
|
||||
} else if item.has_name(sym::hwaddress) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
|
||||
} else {
|
||||
tcx.sess
|
||||
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
|
||||
.note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if attr.has_name(sym::instruction_set) {
|
||||
codegen_fn_attrs.instruction_set = match attr.meta_kind() {
|
||||
Some(MetaItemKind::List(ref items)) => match items.as_slice() {
|
||||
[NestedMetaItem::MetaItem(set)] => {
|
||||
let segments =
|
||||
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
|
||||
match segments.as_slice() {
|
||||
[sym::arm, sym::a32] | [sym::arm, sym::t32] => {
|
||||
if !tcx.sess.target.has_thumb_interworking {
|
||||
struct_span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
attr.span,
|
||||
E0779,
|
||||
"target does not support `#[instruction_set]`"
|
||||
)
|
||||
.emit();
|
||||
None
|
||||
} else if segments[1] == sym::a32 {
|
||||
Some(InstructionSetAttr::ArmA32)
|
||||
} else if segments[1] == sym::t32 {
|
||||
Some(InstructionSetAttr::ArmT32)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
attr.span,
|
||||
E0779,
|
||||
"invalid instruction set specified",
|
||||
)
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
[] => {
|
||||
struct_span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
attr.span,
|
||||
E0778,
|
||||
"`#[instruction_set]` requires an argument"
|
||||
)
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
attr.span,
|
||||
E0779,
|
||||
"cannot specify more than one instruction set"
|
||||
)
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
attr.span,
|
||||
E0778,
|
||||
"must specify an instruction set"
|
||||
)
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
};
|
||||
} else if attr.has_name(sym::repr) {
|
||||
codegen_fn_attrs.alignment = match attr.meta_item_list() {
|
||||
Some(items) => match items.as_slice() {
|
||||
[item] => match item.name_value_literal() {
|
||||
Some((sym::align, literal)) => {
|
||||
let alignment = rustc_attr::parse_alignment(&literal.kind);
|
||||
|
||||
match alignment {
|
||||
Ok(align) => Some(align),
|
||||
Err(msg) => {
|
||||
struct_span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
attr.span,
|
||||
E0589,
|
||||
"invalid `repr(align)` attribute: {}",
|
||||
msg
|
||||
)
|
||||
.emit();
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
[] => None,
|
||||
_ => None,
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
|
||||
if !attr.has_name(sym::inline) {
|
||||
return ia;
|
||||
}
|
||||
match attr.meta_kind() {
|
||||
Some(MetaItemKind::Word) => InlineAttr::Hint,
|
||||
Some(MetaItemKind::List(ref items)) => {
|
||||
inline_span = Some(attr.span);
|
||||
if items.len() != 1 {
|
||||
struct_span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
attr.span,
|
||||
E0534,
|
||||
"expected one argument"
|
||||
)
|
||||
.emit();
|
||||
InlineAttr::None
|
||||
} else if list_contains_name(&items, sym::always) {
|
||||
InlineAttr::Always
|
||||
} else if list_contains_name(&items, sym::never) {
|
||||
InlineAttr::Never
|
||||
} else {
|
||||
struct_span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
items[0].span(),
|
||||
E0535,
|
||||
"invalid argument"
|
||||
)
|
||||
.help("valid inline arguments are `always` and `never`")
|
||||
.emit();
|
||||
|
||||
InlineAttr::None
|
||||
}
|
||||
}
|
||||
Some(MetaItemKind::NameValue(_)) => ia,
|
||||
None => ia,
|
||||
}
|
||||
});
|
||||
|
||||
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
|
||||
if !attr.has_name(sym::optimize) {
|
||||
return ia;
|
||||
}
|
||||
let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit();
|
||||
match attr.meta_kind() {
|
||||
Some(MetaItemKind::Word) => {
|
||||
err(attr.span, "expected one argument");
|
||||
ia
|
||||
}
|
||||
Some(MetaItemKind::List(ref items)) => {
|
||||
inline_span = Some(attr.span);
|
||||
if items.len() != 1 {
|
||||
err(attr.span, "expected one argument");
|
||||
OptimizeAttr::None
|
||||
} else if list_contains_name(&items, sym::size) {
|
||||
OptimizeAttr::Size
|
||||
} else if list_contains_name(&items, sym::speed) {
|
||||
OptimizeAttr::Speed
|
||||
} else {
|
||||
err(items[0].span(), "invalid argument");
|
||||
OptimizeAttr::None
|
||||
}
|
||||
}
|
||||
Some(MetaItemKind::NameValue(_)) => ia,
|
||||
None => ia,
|
||||
}
|
||||
});
|
||||
|
||||
// #73631: closures inherit `#[target_feature]` annotations
|
||||
if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
|
||||
let owner_id = tcx.parent(did.to_def_id());
|
||||
if tcx.def_kind(owner_id).has_codegen_attrs() {
|
||||
codegen_fn_attrs
|
||||
.target_features
|
||||
.extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied());
|
||||
}
|
||||
}
|
||||
|
||||
// If a function uses #[target_feature] it can't be inlined into general
|
||||
// purpose functions as they wouldn't have the right target features
|
||||
// enabled. For that reason we also forbid #[inline(always)] as it can't be
|
||||
// respected.
|
||||
if !codegen_fn_attrs.target_features.is_empty() {
|
||||
if codegen_fn_attrs.inline == InlineAttr::Always {
|
||||
if let Some(span) = inline_span {
|
||||
tcx.sess.span_err(
|
||||
span,
|
||||
"cannot use `#[inline(always)]` with \
|
||||
`#[target_feature]`",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !codegen_fn_attrs.no_sanitize.is_empty() {
|
||||
if codegen_fn_attrs.inline == InlineAttr::Always {
|
||||
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
|
||||
tcx.struct_span_lint_hir(
|
||||
lint::builtin::INLINE_NO_SANITIZE,
|
||||
hir_id,
|
||||
no_sanitize_span,
|
||||
"`no_sanitize` will have no effect after inlining",
|
||||
|lint| lint.span_note(inline_span, "inlining requested here"),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
|
||||
codegen_fn_attrs.inline = InlineAttr::Never;
|
||||
}
|
||||
|
||||
// Weak lang items have the same semantics as "std internal" symbols in the
|
||||
// sense that they're preserved through all our LTO passes and only
|
||||
// strippable by the linker.
|
||||
//
|
||||
// Additionally weak lang items have predetermined symbol names.
|
||||
if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
|
||||
}
|
||||
if let Some((name, _)) = lang_items::extract(attrs)
|
||||
&& let Some(lang_item) = LangItem::from_name(name)
|
||||
&& let Some(link_name) = lang_item.link_name()
|
||||
{
|
||||
codegen_fn_attrs.export_name = Some(link_name);
|
||||
codegen_fn_attrs.link_name = Some(link_name);
|
||||
}
|
||||
check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
|
||||
|
||||
// Internal symbols to the standard library all have no_mangle semantics in
|
||||
// that they have defined symbol names present in the function name. This
|
||||
// also applies to weak symbols where they all have known symbol names.
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
||||
}
|
||||
|
||||
// Any linkage to LLVM intrinsics for now forcibly marks them all as never
|
||||
// unwinds since LLVM sometimes can't handle codegen which `invoke`s
|
||||
// intrinsic functions.
|
||||
if let Some(name) = &codegen_fn_attrs.link_name {
|
||||
if name.as_str().starts_with("llvm.") {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
|
||||
}
|
||||
}
|
||||
|
||||
codegen_fn_attrs
|
||||
}
|
||||
|
||||
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
|
||||
/// applied to the method prototype.
|
||||
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
if let Some(impl_item) = tcx.opt_associated_item(def_id)
|
||||
&& let ty::AssocItemContainer::ImplContainer = impl_item.container
|
||||
&& let Some(trait_item) = impl_item.trait_item_def_id
|
||||
{
|
||||
return tcx
|
||||
.codegen_fn_attrs(trait_item)
|
||||
.flags
|
||||
.intersects(CodegenFnAttrFlags::TRACK_CALLER);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
|
||||
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
|
||||
if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
|
||||
feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::raw_dylib,
|
||||
attr.span,
|
||||
"`#[link_ordinal]` is unstable on x86",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
let meta_item_list = attr.meta_item_list();
|
||||
let meta_item_list = meta_item_list.as_deref();
|
||||
let sole_meta_list = match meta_item_list {
|
||||
Some([item]) => item.lit(),
|
||||
Some(_) => {
|
||||
tcx.sess
|
||||
.struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
|
||||
.note("the attribute requires exactly one argument")
|
||||
.emit();
|
||||
return None;
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
|
||||
sole_meta_list
|
||||
{
|
||||
// According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
|
||||
// the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
|
||||
// in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
|
||||
// to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
|
||||
//
|
||||
// FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this:
|
||||
// both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
|
||||
// a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
|
||||
// for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
|
||||
// library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet
|
||||
// if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
|
||||
// about LINK.EXE failing.)
|
||||
if *ordinal <= u16::MAX as u128 {
|
||||
Some(*ordinal as u16)
|
||||
} else {
|
||||
let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
|
||||
tcx.sess
|
||||
.struct_span_err(attr.span, &msg)
|
||||
.note("the value may not exceed `u16::MAX`")
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
} else {
|
||||
tcx.sess
|
||||
.struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
|
||||
.note("an unsuffixed integer value, e.g., `1`, is expected")
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn check_link_name_xor_ordinal(
|
||||
tcx: TyCtxt<'_>,
|
||||
codegen_fn_attrs: &CodegenFnAttrs,
|
||||
inline_span: Option<Span>,
|
||||
) {
|
||||
if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
|
||||
return;
|
||||
}
|
||||
let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
|
||||
if let Some(span) = inline_span {
|
||||
tcx.sess.span_err(span, msg);
|
||||
} else {
|
||||
tcx.sess.err(msg);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
|
||||
}
|
||||
|
|
@ -235,7 +235,7 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
let projection_bounds: SmallVec<[_; 4]> = trait_data
|
||||
.projection_bounds()
|
||||
.map(|bound| {
|
||||
let ExistentialProjection { item_def_id, term, .. } =
|
||||
let ExistentialProjection { def_id: item_def_id, term, .. } =
|
||||
tcx.erase_late_bound_regions(bound);
|
||||
// FIXME(associated_const_equality): allow for consts here
|
||||
(item_def_id, term.ty().unwrap())
|
||||
|
|
@ -411,9 +411,8 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
ty::Error(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Projection(..)
|
||||
| ty::Alias(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Opaque(..)
|
||||
| ty::GeneratorWitness(..) => {
|
||||
bug!(
|
||||
"debuginfo: Trying to create type name for \
|
||||
|
|
|
|||
|
|
@ -548,3 +548,10 @@ pub struct ArchiveBuildFailure {
|
|||
pub struct UnknownArchiveKind<'a> {
|
||||
pub kind: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_expected_used_symbol)]
|
||||
pub struct ExpectedUsedSymbol {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
pub mod back;
|
||||
pub mod base;
|
||||
pub mod codegen_attrs;
|
||||
pub mod common;
|
||||
pub mod coverageinfo;
|
||||
pub mod debuginfo;
|
||||
|
|
@ -180,6 +181,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
crate::back::symbol_export::provide(providers);
|
||||
crate::base::provide(providers);
|
||||
crate::target_features::provide(providers);
|
||||
crate::codegen_attrs::provide(providers);
|
||||
}
|
||||
|
||||
pub fn provide_extern(providers: &mut ExternProviders) {
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ impl<'a, 'tcx> VirtualIndex {
|
|||
let typeid =
|
||||
bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty)));
|
||||
let vtable_byte_offset = self.0 * bx.data_layout().pointer_size.bytes();
|
||||
let type_checked_load = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
|
||||
let func = bx.extract_value(type_checked_load, 0);
|
||||
let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
|
||||
bx.pointercast(func, llty)
|
||||
} else {
|
||||
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
|
||||
|
|
|
|||
|
|
@ -289,16 +289,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.cleanup_ret(funclet, None);
|
||||
} else {
|
||||
let slot = self.get_personality_slot(bx);
|
||||
let lp0 = slot.project_field(bx, 0);
|
||||
let lp0 = bx.load_operand(lp0).immediate();
|
||||
let lp1 = slot.project_field(bx, 1);
|
||||
let lp1 = bx.load_operand(lp1).immediate();
|
||||
let exn0 = slot.project_field(bx, 0);
|
||||
let exn0 = bx.load_operand(exn0).immediate();
|
||||
let exn1 = slot.project_field(bx, 1);
|
||||
let exn1 = bx.load_operand(exn1).immediate();
|
||||
slot.storage_dead(bx);
|
||||
|
||||
let mut lp = bx.const_undef(self.landing_pad_type());
|
||||
lp = bx.insert_value(lp, lp0, 0);
|
||||
lp = bx.insert_value(lp, lp1, 1);
|
||||
bx.resume(lp);
|
||||
bx.resume(exn0, exn1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -751,10 +748,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let (instance, mut llfn) = match *callee.layout.ty.kind() {
|
||||
ty::FnDef(def_id, substs) => (
|
||||
Some(
|
||||
ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.polymorphize(bx.tcx()),
|
||||
ty::Instance::expect_resolve(
|
||||
bx.tcx(),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
def_id,
|
||||
substs,
|
||||
)
|
||||
.polymorphize(bx.tcx()),
|
||||
),
|
||||
None,
|
||||
),
|
||||
|
|
@ -1633,24 +1633,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
|
||||
|
||||
let llpersonality = self.cx.eh_personality();
|
||||
let llretty = self.landing_pad_type();
|
||||
let lp = cleanup_bx.cleanup_landing_pad(llretty, llpersonality);
|
||||
let (exn0, exn1) = cleanup_bx.cleanup_landing_pad(llpersonality);
|
||||
|
||||
let slot = self.get_personality_slot(&mut cleanup_bx);
|
||||
slot.storage_live(&mut cleanup_bx);
|
||||
Pair(cleanup_bx.extract_value(lp, 0), cleanup_bx.extract_value(lp, 1))
|
||||
.store(&mut cleanup_bx, slot);
|
||||
Pair(exn0, exn1).store(&mut cleanup_bx, slot);
|
||||
|
||||
cleanup_bx.br(llbb);
|
||||
cleanup_llbb
|
||||
}
|
||||
}
|
||||
|
||||
fn landing_pad_type(&self) -> Bx::Type {
|
||||
let cx = self.cx;
|
||||
cx.type_struct(&[cx.type_i8p(), cx.type_i32()], false)
|
||||
}
|
||||
|
||||
fn unreachable_block(&mut self) -> Bx::BasicBlock {
|
||||
self.unreachable_block.unwrap_or_else(|| {
|
||||
let llbb = Bx::append_block(self.cx, self.llfn, "unreachable");
|
||||
|
|
@ -1670,8 +1663,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
|
||||
|
||||
let llpersonality = self.cx.eh_personality();
|
||||
let llretty = self.landing_pad_type();
|
||||
bx.cleanup_landing_pad(llretty, llpersonality);
|
||||
bx.cleanup_landing_pad(llpersonality);
|
||||
|
||||
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicNoUnwind);
|
||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||
|
|
@ -1810,15 +1802,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
match (src.layout.abi, dst.layout.abi) {
|
||||
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
|
||||
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
|
||||
if (src_scalar.primitive() == abi::Pointer)
|
||||
== (dst_scalar.primitive() == abi::Pointer)
|
||||
{
|
||||
let src_is_ptr = src_scalar.primitive() == abi::Pointer;
|
||||
let dst_is_ptr = dst_scalar.primitive() == abi::Pointer;
|
||||
if src_is_ptr == dst_is_ptr {
|
||||
assert_eq!(src.layout.size, dst.layout.size);
|
||||
|
||||
// NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
|
||||
// conversions allow handling `bool`s the same as `u8`s.
|
||||
let src = bx.from_immediate(src.immediate());
|
||||
let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout));
|
||||
// LLVM also doesn't like `bitcast`s between pointers in different address spaces.
|
||||
let src_as_dst = if src_is_ptr {
|
||||
bx.pointercast(src, bx.backend_type(dst.layout))
|
||||
} else {
|
||||
bx.bitcast(src, bx.backend_type(dst.layout))
|
||||
};
|
||||
Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
assert!(bx.cx().tcx().is_static(def_id));
|
||||
let static_ = bx.get_static(def_id);
|
||||
let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id));
|
||||
OperandRef::from_immediate_or_packed_pair(bx, static_, layout)
|
||||
OperandRef { val: OperandValue::Immediate(static_), layout }
|
||||
}
|
||||
mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand),
|
||||
mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,19 @@
|
|||
use rustc_ast::ast;
|
||||
use rustc_attr::InstructionSetAttr;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
|
||||
/// Features that control behaviour of rustc, rather than the codegen.
|
||||
pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
|
||||
|
|
@ -322,15 +333,148 @@ pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
providers.supported_target_features = |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
if tcx.sess.opts.actually_rustdoc {
|
||||
// rustdoc needs to be able to document functions that use all the features, so
|
||||
// whitelist them all
|
||||
all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
|
||||
} else {
|
||||
supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
|
||||
}
|
||||
pub fn from_target_feature(
|
||||
tcx: TyCtxt<'_>,
|
||||
attr: &ast::Attribute,
|
||||
supported_target_features: &FxHashMap<String, Option<Symbol>>,
|
||||
target_features: &mut Vec<Symbol>,
|
||||
) {
|
||||
let Some(list) = attr.meta_item_list() else { return };
|
||||
let bad_item = |span| {
|
||||
let msg = "malformed `target_feature` attribute input";
|
||||
let code = "enable = \"..\"";
|
||||
tcx.sess
|
||||
.struct_span_err(span, msg)
|
||||
.span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
|
||||
.emit();
|
||||
};
|
||||
let rust_features = tcx.features();
|
||||
for item in list {
|
||||
// Only `enable = ...` is accepted in the meta-item list.
|
||||
if !item.has_name(sym::enable) {
|
||||
bad_item(item.span());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Must be of the form `enable = "..."` (a string).
|
||||
let Some(value) = item.value_str() else {
|
||||
bad_item(item.span());
|
||||
continue;
|
||||
};
|
||||
|
||||
// We allow comma separation to enable multiple features.
|
||||
target_features.extend(value.as_str().split(',').filter_map(|feature| {
|
||||
let Some(feature_gate) = supported_target_features.get(feature) else {
|
||||
let msg =
|
||||
format!("the feature named `{}` is not valid for this target", feature);
|
||||
let mut err = tcx.sess.struct_span_err(item.span(), &msg);
|
||||
err.span_label(
|
||||
item.span(),
|
||||
format!("`{}` is not valid for this target", feature),
|
||||
);
|
||||
if let Some(stripped) = feature.strip_prefix('+') {
|
||||
let valid = supported_target_features.contains_key(stripped);
|
||||
if valid {
|
||||
err.help("consider removing the leading `+` in the feature name");
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
return None;
|
||||
};
|
||||
|
||||
// Only allow features whose feature gates have been enabled.
|
||||
let allowed = match feature_gate.as_ref().copied() {
|
||||
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
|
||||
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
|
||||
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
|
||||
Some(sym::mips_target_feature) => rust_features.mips_target_feature,
|
||||
Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
|
||||
Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
|
||||
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
|
||||
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
|
||||
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
|
||||
Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
|
||||
Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
|
||||
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
|
||||
Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
|
||||
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
|
||||
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
|
||||
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
|
||||
Some(name) => bug!("unknown target feature gate {}", name),
|
||||
None => true,
|
||||
};
|
||||
if !allowed {
|
||||
feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
feature_gate.unwrap(),
|
||||
item.span(),
|
||||
&format!("the target feature `{}` is currently unstable", feature),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
Some(Symbol::intern(feature))
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the set of target features used in a function for the purposes of
|
||||
/// inline assembly.
|
||||
fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
|
||||
let mut target_features = tcx.sess.unstable_target_features.clone();
|
||||
if tcx.def_kind(did).has_codegen_attrs() {
|
||||
let attrs = tcx.codegen_fn_attrs(did);
|
||||
target_features.extend(&attrs.target_features);
|
||||
match attrs.instruction_set {
|
||||
None => {}
|
||||
Some(InstructionSetAttr::ArmA32) => {
|
||||
target_features.remove(&sym::thumb_mode);
|
||||
}
|
||||
Some(InstructionSetAttr::ArmT32) => {
|
||||
target_features.insert(sym::thumb_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tcx.arena.alloc(target_features)
|
||||
}
|
||||
|
||||
/// Checks the function annotated with `#[target_feature]` is not a safe
|
||||
/// trait method implementation, reporting an error if it is.
|
||||
pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
|
||||
let node = tcx.hir().get(hir_id);
|
||||
if let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
let parent_item = tcx.hir().expect_item(parent_id.def_id);
|
||||
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
|
||||
tcx.sess
|
||||
.struct_span_err(
|
||||
attr_span,
|
||||
"`#[target_feature(..)]` cannot be applied to safe trait method",
|
||||
)
|
||||
.span_label(attr_span, "cannot be applied to safe trait method")
|
||||
.span_label(tcx.def_span(id), "not an `unsafe` function")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
supported_target_features: |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
if tcx.sess.opts.actually_rustdoc {
|
||||
// rustdoc needs to be able to document functions that use all the features, so
|
||||
// whitelist them all
|
||||
all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
|
||||
} else {
|
||||
supported_target_features(tcx.sess)
|
||||
.iter()
|
||||
.map(|&(a, b)| (a.to_string(), b))
|
||||
.collect()
|
||||
}
|
||||
},
|
||||
asm_target_features,
|
||||
..*providers
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,8 +271,8 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
fn set_personality_fn(&mut self, personality: Self::Value);
|
||||
|
||||
// These are used by everyone except msvc
|
||||
fn cleanup_landing_pad(&mut self, ty: Self::Type, pers_fn: Self::Value) -> Self::Value;
|
||||
fn resume(&mut self, exn: Self::Value);
|
||||
fn cleanup_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value);
|
||||
fn resume(&mut self, exn0: Self::Value, exn1: Self::Value);
|
||||
|
||||
// These are used only by msvc
|
||||
fn cleanup_pad(&mut self, parent: Option<Self::Value>, args: &[Self::Value]) -> Self::Funclet;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,59 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
|||
self.report_decorated(tcx, message, |_| {})
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, decorate))]
|
||||
pub(super) fn decorate(&self, err: &mut Diagnostic, decorate: impl FnOnce(&mut Diagnostic)) {
|
||||
trace!("reporting const eval failure at {:?}", self.span);
|
||||
// Add some more context for select error types.
|
||||
match self.error {
|
||||
InterpError::Unsupported(
|
||||
UnsupportedOpInfo::ReadPointerAsBytes
|
||||
| UnsupportedOpInfo::PartialPointerOverwrite(_)
|
||||
| UnsupportedOpInfo::PartialPointerCopy(_),
|
||||
) => {
|
||||
err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
|
||||
err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// Add spans for the stacktrace. Don't print a single-line backtrace though.
|
||||
if self.stacktrace.len() > 1 {
|
||||
// Helper closure to print duplicated lines.
|
||||
let mut flush_last_line = |last_frame, times| {
|
||||
if let Some((line, span)) = last_frame {
|
||||
err.span_note(span, &line);
|
||||
// Don't print [... additional calls ...] if the number of lines is small
|
||||
if times < 3 {
|
||||
for _ in 0..times {
|
||||
err.span_note(span, &line);
|
||||
}
|
||||
} else {
|
||||
err.span_note(
|
||||
span,
|
||||
format!("[... {} additional calls {} ...]", times, &line),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut last_frame = None;
|
||||
let mut times = 0;
|
||||
for frame_info in &self.stacktrace {
|
||||
let frame = (frame_info.to_string(), frame_info.span);
|
||||
if last_frame.as_ref() == Some(&frame) {
|
||||
times += 1;
|
||||
} else {
|
||||
flush_last_line(last_frame, times);
|
||||
last_frame = Some(frame);
|
||||
times = 0;
|
||||
}
|
||||
}
|
||||
flush_last_line(last_frame, times);
|
||||
}
|
||||
// Let the caller attach any additional information it wants.
|
||||
decorate(err);
|
||||
}
|
||||
|
||||
/// Create a diagnostic for this const eval error.
|
||||
///
|
||||
/// Sets the message passed in via `message` and adds span labels with detailed error
|
||||
|
|
@ -101,88 +154,30 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
|||
message: &str,
|
||||
decorate: impl FnOnce(&mut Diagnostic),
|
||||
) -> ErrorHandled {
|
||||
let finish = |err: &mut Diagnostic, span_msg: Option<String>| {
|
||||
trace!("reporting const eval failure at {:?}", self.span);
|
||||
if let Some(span_msg) = span_msg {
|
||||
err.span_label(self.span, span_msg);
|
||||
}
|
||||
// Add some more context for select error types.
|
||||
match self.error {
|
||||
InterpError::Unsupported(
|
||||
UnsupportedOpInfo::ReadPointerAsBytes
|
||||
| UnsupportedOpInfo::PartialPointerOverwrite(_)
|
||||
| UnsupportedOpInfo::PartialPointerCopy(_),
|
||||
) => {
|
||||
err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
|
||||
err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// Add spans for the stacktrace. Don't print a single-line backtrace though.
|
||||
if self.stacktrace.len() > 1 {
|
||||
// Helper closure to print duplicated lines.
|
||||
let mut flush_last_line = |last_frame, times| {
|
||||
if let Some((line, span)) = last_frame {
|
||||
err.span_note(span, &line);
|
||||
// Don't print [... additional calls ...] if the number of lines is small
|
||||
if times < 3 {
|
||||
for _ in 0..times {
|
||||
err.span_note(span, &line);
|
||||
}
|
||||
} else {
|
||||
err.span_note(
|
||||
span,
|
||||
format!("[... {} additional calls {} ...]", times, &line),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut last_frame = None;
|
||||
let mut times = 0;
|
||||
for frame_info in &self.stacktrace {
|
||||
let frame = (frame_info.to_string(), frame_info.span);
|
||||
if last_frame.as_ref() == Some(&frame) {
|
||||
times += 1;
|
||||
} else {
|
||||
flush_last_line(last_frame, times);
|
||||
last_frame = Some(frame);
|
||||
times = 0;
|
||||
}
|
||||
}
|
||||
flush_last_line(last_frame, times);
|
||||
}
|
||||
// Let the caller attach any additional information it wants.
|
||||
decorate(err);
|
||||
};
|
||||
|
||||
debug!("self.error: {:?}", self.error);
|
||||
// Special handling for certain errors
|
||||
match &self.error {
|
||||
// Don't emit a new diagnostic for these errors
|
||||
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
|
||||
return ErrorHandled::TooGeneric;
|
||||
}
|
||||
err_inval!(AlreadyReported(error_reported)) => {
|
||||
return ErrorHandled::Reported(*error_reported);
|
||||
ErrorHandled::TooGeneric
|
||||
}
|
||||
err_inval!(AlreadyReported(error_reported)) => ErrorHandled::Reported(*error_reported),
|
||||
err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
|
||||
// We must *always* hard error on these, even if the caller wants just a lint.
|
||||
// The `message` makes little sense here, this is a more serious error than the
|
||||
// caller thinks anyway.
|
||||
// See <https://github.com/rust-lang/rust/pull/63152>.
|
||||
let mut err = struct_error(tcx, &self.error.to_string());
|
||||
finish(&mut err, None);
|
||||
return ErrorHandled::Reported(err.emit());
|
||||
self.decorate(&mut err, decorate);
|
||||
ErrorHandled::Reported(err.emit())
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
let err_msg = self.error.to_string();
|
||||
|
||||
// Report as hard error.
|
||||
let mut err = struct_error(tcx, message);
|
||||
finish(&mut err, Some(err_msg));
|
||||
ErrorHandled::Reported(err.emit())
|
||||
_ => {
|
||||
// Report as hard error.
|
||||
let mut err = struct_error(tcx, message);
|
||||
err.span_label(self.span, self.error.to_string());
|
||||
self.decorate(&mut err, decorate);
|
||||
ErrorHandled::Reported(err.emit())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::const_eval::CheckAlignment;
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use either::{Left, Right};
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|
|||
None => InternKind::Constant,
|
||||
}
|
||||
};
|
||||
ecx.machine.check_alignment = false; // interning doesn't need to respect alignment
|
||||
ecx.machine.check_alignment = CheckAlignment::No; // interning doesn't need to respect alignment
|
||||
intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
|
||||
// we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway
|
||||
|
||||
|
|
@ -103,11 +103,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
|
|||
tcx,
|
||||
root_span,
|
||||
param_env,
|
||||
CompileTimeInterpreter::new(
|
||||
tcx.const_eval_limit(),
|
||||
can_access_statics,
|
||||
/*check_alignment:*/ false,
|
||||
),
|
||||
CompileTimeInterpreter::new(tcx.const_eval_limit(), can_access_statics, CheckAlignment::No),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -312,7 +308,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||
CompileTimeInterpreter::new(
|
||||
tcx.const_eval_limit(),
|
||||
/*can_access_statics:*/ is_static,
|
||||
/*check_alignment:*/ tcx.sess.opts.unstable_opts.extra_const_ub_checks,
|
||||
if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
|
||||
CheckAlignment::Error
|
||||
} else {
|
||||
CheckAlignment::FutureIncompat
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_hir::{LangItem, CRATE_HIR_ID};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::PointerArithmetic;
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_session::lint::builtin::INVALID_ALIGNMENT;
|
||||
use std::borrow::Borrow;
|
||||
use std::hash::Hash;
|
||||
use std::ops::ControlFlow;
|
||||
|
|
@ -47,14 +48,34 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
|
|||
pub(super) can_access_statics: bool,
|
||||
|
||||
/// Whether to check alignment during evaluation.
|
||||
pub(super) check_alignment: bool,
|
||||
pub(super) check_alignment: CheckAlignment,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum CheckAlignment {
|
||||
/// Ignore alignment when following relocations.
|
||||
/// This is mainly used in interning.
|
||||
No,
|
||||
/// Hard error when dereferencing a misaligned pointer.
|
||||
Error,
|
||||
/// Emit a future incompat lint when dereferencing a misaligned pointer.
|
||||
FutureIncompat,
|
||||
}
|
||||
|
||||
impl CheckAlignment {
|
||||
pub fn should_check(&self) -> bool {
|
||||
match self {
|
||||
CheckAlignment::No => false,
|
||||
CheckAlignment::Error | CheckAlignment::FutureIncompat => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
|
||||
pub(crate) fn new(
|
||||
const_eval_limit: Limit,
|
||||
can_access_statics: bool,
|
||||
check_alignment: bool,
|
||||
check_alignment: CheckAlignment,
|
||||
) -> Self {
|
||||
CompileTimeInterpreter {
|
||||
steps_remaining: const_eval_limit.0,
|
||||
|
|
@ -309,7 +330,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
|
||||
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
|
||||
ecx.machine.check_alignment
|
||||
}
|
||||
|
||||
|
|
@ -318,6 +339,36 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
|
||||
}
|
||||
|
||||
fn alignment_check_failed(
|
||||
ecx: &InterpCx<'mir, 'tcx, Self>,
|
||||
has: Align,
|
||||
required: Align,
|
||||
check: CheckAlignment,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
let err = err_ub!(AlignmentCheckFailed { has, required }).into();
|
||||
match check {
|
||||
CheckAlignment::Error => Err(err),
|
||||
CheckAlignment::No => span_bug!(
|
||||
ecx.cur_span(),
|
||||
"`alignment_check_failed` called when no alignment check requested"
|
||||
),
|
||||
CheckAlignment::FutureIncompat => {
|
||||
let err = ConstEvalErr::new(ecx, err, None);
|
||||
ecx.tcx.struct_span_lint_hir(
|
||||
INVALID_ALIGNMENT,
|
||||
ecx.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
|
||||
err.span,
|
||||
err.error.to_string(),
|
||||
|db| {
|
||||
err.decorate(db, |_| {});
|
||||
db
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn load_mir(
|
||||
ecx: &InterpCx<'mir, 'tcx, Self>,
|
||||
instance: ty::InstanceDef<'tcx>,
|
||||
|
|
|
|||
|
|
@ -142,12 +142,11 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
|||
| ty::Foreign(..)
|
||||
| ty::Infer(ty::FreshIntTy(_))
|
||||
| ty::Infer(ty::FreshFloatTy(_))
|
||||
| ty::Projection(..)
|
||||
// FIXME(oli-obk): we could look behind opaque types
|
||||
| ty::Alias(..)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(..)
|
||||
// FIXME(oli-obk): we could look behind opaque types
|
||||
| ty::Opaque(..)
|
||||
| ty::Infer(_)
|
||||
// FIXME(oli-obk): we can probably encode closures just like structs
|
||||
| ty::Closure(..)
|
||||
|
|
@ -307,11 +306,10 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
| ty::Foreign(..)
|
||||
| ty::Infer(ty::FreshIntTy(_))
|
||||
| ty::Infer(ty::FreshFloatTy(_))
|
||||
| ty::Projection(..)
|
||||
| ty::Alias(..)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Opaque(..)
|
||||
| ty::Infer(_)
|
||||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue