mirror of
https://github.com/rust-lang/rust.git
synced 2026-06-01 05:57:03 +03:00
Merge ref '69d4d5fc0e4d' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh.
Upstream ref: 69d4d5fc0e
Filtered ref: 55f7a9f34e7b6dccf3ed08a163109a5e83c36b85
Upstream diff: https://github.com/rust-lang/rust/compare/8401398e1f14a24670ee1a3203713dc2f0f8b3a8...69d4d5fc0e4db60272aac85ef27ecccef5764f3a
This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
@@ -6,7 +6,7 @@ name: Post merge analysis
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ no_llvm_build
|
||||
/llvm/
|
||||
/mingw-build/
|
||||
/build
|
||||
/build-rust-analyzer/
|
||||
/build-rust-analyzer
|
||||
/dist/
|
||||
/unicode-downloads
|
||||
/target
|
||||
|
||||
+34
-34
@@ -80,9 +80,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "annotate-snippets"
|
||||
version = "0.12.8"
|
||||
version = "0.12.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "025c7edcdffa4ccc5c0905f472a0ae3759378cfbef88ef518a3575e19ae3aebd"
|
||||
checksum = "a44baf24dd94e781f74dfe67ffee75a09a57971ddf0f615a178b4f6d404b48ff"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"unicode-width 0.2.2",
|
||||
@@ -1288,7 +1288,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2154,7 +2154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets 0.53.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3766,7 +3766,7 @@ dependencies = [
|
||||
name = "rustc_errors"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.12.8",
|
||||
"annotate-snippets 0.12.9",
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"derive_setters",
|
||||
@@ -4905,7 +4905,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5273,9 +5273,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "stringdex"
|
||||
version = "0.0.2"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18b3bd4f10d15ef859c40291769f0d85209de6b0f1c30713ff9cdf45ac43ea36"
|
||||
checksum = "556a6126952cb2f5150057c98a77cc6c771027dea2825bf7fa03d3d638b0a4f8"
|
||||
dependencies = [
|
||||
"stacker",
|
||||
]
|
||||
@@ -6070,9 +6070,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasi-preview1-component-adapter-provider"
|
||||
version = "37.0.2"
|
||||
version = "38.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d0fcd636ad2b29a7c0490799a23ad61d1c8dedfafdb970447fddd0549502b60"
|
||||
checksum = "7ec3ef3783e18f2457796ed91b1e6c2adc46f2905f740d1527ab3053fe8e5682"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
@@ -6134,9 +6134,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-component-ld"
|
||||
version = "0.5.18"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11f565dfcfd9aabb10d865b608a92ce1f93051aeb56f4c89550ed9cd97d8ce0e"
|
||||
checksum = "4bfc50dd0b883d841bc1dba5ff7020ca52fa7b2c3bb1266d8bf6a09dd032e115"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -6144,7 +6144,7 @@ dependencies = [
|
||||
"libc",
|
||||
"tempfile",
|
||||
"wasi-preview1-component-adapter-provider",
|
||||
"wasmparser 0.240.0",
|
||||
"wasmparser 0.241.2",
|
||||
"wat",
|
||||
"windows-sys 0.61.2",
|
||||
"winsplit",
|
||||
@@ -6171,24 +6171,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.240.0"
|
||||
version = "0.241.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06d642d8c5ecc083aafe9ceb32809276a304547a3a6eeecceb5d8152598bc71f"
|
||||
checksum = "e01164c9dda68301e34fdae536c23ed6fe90ce6d97213ccc171eebbd3d02d6b8"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser 0.240.0",
|
||||
"wasmparser 0.241.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.240.0"
|
||||
version = "0.241.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee093e1e1ccffa005b9b778f7a10ccfd58e25a20eccad294a1a93168d076befb"
|
||||
checksum = "876fe286f2fa416386deedebe8407e6f19e0b5aeaef3d03161e77a15fa80f167"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"wasm-encoder 0.240.0",
|
||||
"wasmparser 0.240.0",
|
||||
"wasm-encoder 0.241.2",
|
||||
"wasmparser 0.241.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6213,9 +6213,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.240.0"
|
||||
version = "0.241.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b722dcf61e0ea47440b53ff83ccb5df8efec57a69d150e4f24882e4eba7e24a4"
|
||||
checksum = "46d90019b1afd4b808c263e428de644f3003691f243387d30d673211ee0cb8e8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"hashbrown",
|
||||
@@ -6226,22 +6226,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "240.0.0"
|
||||
version = "241.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0efe1c93db4ac562b9733e3dca19ed7fc878dba29aef22245acf84f13da4a19"
|
||||
checksum = "63f66e07e2ddf531fef6344dbf94d112df7c2f23ed6ffb10962e711500b8d816"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"leb128fmt",
|
||||
"memchr",
|
||||
"unicode-width 0.2.2",
|
||||
"wasm-encoder 0.240.0",
|
||||
"wasm-encoder 0.241.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.240.0"
|
||||
version = "1.241.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec9b6eab7ecd4d639d78515e9ea491c9bacf494aa5eda10823bd35992cf8c1e"
|
||||
checksum = "45f923705c40830af909c5dec2352ec2821202e4a66008194585e1917458a26d"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
@@ -6679,9 +6679,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.240.0"
|
||||
version = "0.241.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dc5474b078addc5fe8a72736de8da3acfb3ff324c2491133f8b59594afa1a20"
|
||||
checksum = "1fd0c57df25e7ee612d946d3b7646c1ddb2310f8280aa2c17e543b66e0812241"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
@@ -6690,17 +6690,17 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder 0.240.0",
|
||||
"wasm-encoder 0.241.2",
|
||||
"wasm-metadata",
|
||||
"wasmparser 0.240.0",
|
||||
"wasmparser 0.241.2",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.240.0"
|
||||
version = "0.241.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9875ea3fa272f57cc1fc50f225a7b94021a7878c484b33792bccad0d93223439"
|
||||
checksum = "09ef1c6ad67f35c831abd4039c02894de97034100899614d1c44e2268ad01c91"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
@@ -6711,7 +6711,7 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser 0.240.0",
|
||||
"wasmparser 0.241.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -59,7 +59,10 @@
|
||||
# toolchain or changing LLVM locally, you probably want to leave this enabled.
|
||||
#
|
||||
# Set this to `true` to download if CI llvm available otherwise it builds
|
||||
# from `src/llvm-project`.
|
||||
# from `src/llvm-project`. If you set it to `true`, it's safe and time-saving to run
|
||||
# `git submodule deinit src/llvm-project` to avoid git updating the llvm-project submodule
|
||||
# when building compiler locally.
|
||||
#
|
||||
#
|
||||
# Set this to `"if-unchanged"` to download only if the llvm-project has not
|
||||
# been modified. You can also use this if you are unsure whether you're on a
|
||||
@@ -320,7 +323,7 @@
|
||||
#build.npm = "npm"
|
||||
|
||||
# Python interpreter to use for various tasks throughout the build, notably
|
||||
# rustdoc tests, the lldb python interpreter, and some dist bits and pieces.
|
||||
# rustdoc tests, and some dist bits and pieces.
|
||||
#
|
||||
# Defaults to the Python interpreter used to execute x.py.
|
||||
#build.python = "python"
|
||||
|
||||
@@ -269,13 +269,56 @@ pub fn supports_c_variadic(self) -> CVariadicStatus {
|
||||
| Self::Aapcs { .. }
|
||||
| Self::Win64 { .. }
|
||||
| Self::SysV64 { .. }
|
||||
| Self::EfiApi => CVariadicStatus::Stable,
|
||||
Self::System { .. } => {
|
||||
CVariadicStatus::Unstable { feature: rustc_span::sym::extern_system_varargs }
|
||||
}
|
||||
| Self::EfiApi
|
||||
| Self::System { .. } => CVariadicStatus::Stable,
|
||||
_ => CVariadicStatus::NotSupported,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the ABI supports guaranteed tail calls.
|
||||
#[cfg(feature = "nightly")]
|
||||
pub fn supports_guaranteed_tail_call(self) -> bool {
|
||||
match self {
|
||||
Self::CmseNonSecureCall | Self::CmseNonSecureEntry => {
|
||||
// See https://godbolt.org/z/9jhdeqErv. The CMSE calling conventions clear registers
|
||||
// before returning, and hence cannot guarantee a tail call.
|
||||
false
|
||||
}
|
||||
Self::AvrInterrupt
|
||||
| Self::AvrNonBlockingInterrupt
|
||||
| Self::Msp430Interrupt
|
||||
| Self::RiscvInterruptM
|
||||
| Self::RiscvInterruptS
|
||||
| Self::X86Interrupt => {
|
||||
// See https://godbolt.org/z/Edfjnxxcq. Interrupts cannot be called directly.
|
||||
false
|
||||
}
|
||||
Self::GpuKernel | Self::PtxKernel => {
|
||||
// See https://godbolt.org/z/jq5TE5jK1.
|
||||
false
|
||||
}
|
||||
Self::Custom => {
|
||||
// This ABI does not support calls at all (except via assembly).
|
||||
false
|
||||
}
|
||||
Self::C { .. }
|
||||
| Self::System { .. }
|
||||
| Self::Rust
|
||||
| Self::RustCall
|
||||
| Self::RustCold
|
||||
| Self::RustInvalid
|
||||
| Self::Unadjusted
|
||||
| Self::EfiApi
|
||||
| Self::Aapcs { .. }
|
||||
| Self::Cdecl { .. }
|
||||
| Self::Stdcall { .. }
|
||||
| Self::Fastcall { .. }
|
||||
| Self::Thiscall { .. }
|
||||
| Self::Vectorcall { .. }
|
||||
| Self::SysV64 { .. }
|
||||
| Self::Win64 { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_names() -> Vec<&'static str> {
|
||||
|
||||
@@ -648,9 +648,10 @@ pub fn to_ty(&self) -> Option<Box<Ty>> {
|
||||
PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
|
||||
PatKind::MacCall(mac) => TyKind::MacCall(mac.clone()),
|
||||
// `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type.
|
||||
PatKind::Ref(pat, mutbl) => {
|
||||
pat.to_ty().map(|ty| TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }))?
|
||||
}
|
||||
PatKind::Ref(pat, pinned, mutbl) => pat.to_ty().map(|ty| match pinned {
|
||||
Pinnedness::Not => TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }),
|
||||
Pinnedness::Pinned => TyKind::PinnedRef(None, MutTy { ty, mutbl: *mutbl }),
|
||||
})?,
|
||||
// A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
|
||||
// when `P` can be reparsed as a type `T`.
|
||||
PatKind::Slice(pats) if let [pat] = pats.as_slice() => {
|
||||
@@ -696,7 +697,7 @@ pub fn walk<'ast>(&'ast self, it: &mut impl FnMut(&'ast Pat) -> bool) {
|
||||
// Trivial wrappers over inner patterns.
|
||||
PatKind::Box(s)
|
||||
| PatKind::Deref(s)
|
||||
| PatKind::Ref(s, _)
|
||||
| PatKind::Ref(s, _, _)
|
||||
| PatKind::Paren(s)
|
||||
| PatKind::Guard(s, _) => s.walk(it),
|
||||
|
||||
@@ -717,7 +718,7 @@ pub fn walk<'ast>(&'ast self, it: &mut impl FnMut(&'ast Pat) -> bool) {
|
||||
/// Strip off all reference patterns (`&`, `&mut`) and return the inner pattern.
|
||||
pub fn peel_refs(&self) -> &Pat {
|
||||
let mut current = self;
|
||||
while let PatKind::Ref(inner, _) = ¤t.kind {
|
||||
while let PatKind::Ref(inner, _, _) = ¤t.kind {
|
||||
current = inner;
|
||||
}
|
||||
current
|
||||
@@ -765,7 +766,9 @@ pub fn descr(&self) -> Option<String> {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => Some("_".to_string()),
|
||||
PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")),
|
||||
PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())),
|
||||
PatKind::Ref(pat, pinned, mutbl) => {
|
||||
pat.descr().map(|d| format!("&{}{d}", pinned.prefix_str(*mutbl)))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -913,7 +916,7 @@ pub enum PatKind {
|
||||
Deref(Box<Pat>),
|
||||
|
||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(Box<Pat>, Mutability),
|
||||
Ref(Box<Pat>, Pinnedness, Mutability),
|
||||
|
||||
/// A literal, const block or path.
|
||||
Expr(Box<Expr>),
|
||||
|
||||
@@ -645,8 +645,9 @@ fn visit_assoc_item(&mut self, item: &$($lt)? $($mut)? AssocItem, ctxt: AssocCtx
|
||||
fn visit_fn(
|
||||
&mut self,
|
||||
fk: FnKind<$($lt)? $(${ignore($mut)} '_)?>,
|
||||
_: &AttrVec,
|
||||
_: Span,
|
||||
_: NodeId
|
||||
_: NodeId,
|
||||
) -> Self::Result {
|
||||
walk_fn(self, fk)
|
||||
}
|
||||
@@ -740,6 +741,7 @@ pub trait WalkItemKind {
|
||||
type Ctxt;
|
||||
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
&$($lt)? $($mut)? self,
|
||||
attrs: &AttrVec,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
visibility: &$($lt)? $($mut)? Visibility,
|
||||
@@ -773,7 +775,7 @@ fn walk_item_inner<$($lt,)? K: WalkItemKind, V: $Visitor$(<$lt>)?>(
|
||||
) -> V::Result {
|
||||
let Item { attrs, id, kind, vis, span, tokens: _ } = item;
|
||||
visit_visitable!($($mut)? visitor, id, attrs, vis);
|
||||
try_visit!(kind.walk(*span, *id, vis, ctxt, visitor));
|
||||
try_visit!(kind.walk(attrs, *span, *id, vis, ctxt, visitor));
|
||||
visit_visitable!($($mut)? visitor, span);
|
||||
V::Result::output()
|
||||
}
|
||||
@@ -799,6 +801,7 @@ impl WalkItemKind for ItemKind {
|
||||
type Ctxt = ();
|
||||
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
&$($lt)? $($mut)? self,
|
||||
attrs: &AttrVec,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
visibility: &$($lt)? $($mut)? Visibility,
|
||||
@@ -808,7 +811,7 @@ fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
match self {
|
||||
ItemKind::Fn(func) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Free, visibility, &$($mut)? *func);
|
||||
try_visit!(vis.visit_fn(kind, span, id));
|
||||
try_visit!(vis.visit_fn(kind, attrs, span, id));
|
||||
}
|
||||
ItemKind::ExternCrate(orig_name, ident) =>
|
||||
visit_visitable!($($mut)? vis, orig_name, ident),
|
||||
@@ -856,6 +859,7 @@ impl WalkItemKind for AssocItemKind {
|
||||
type Ctxt = AssocCtxt;
|
||||
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
&$($lt)? $($mut)? self,
|
||||
attrs: &AttrVec,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
visibility: &$($lt)? $($mut)? Visibility,
|
||||
@@ -867,7 +871,7 @@ fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
AssocItemKind::Fn(func) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), visibility, &$($mut)? *func);
|
||||
try_visit!(vis.visit_fn(kind, span, id))
|
||||
try_visit!(vis.visit_fn(kind, attrs, span, id))
|
||||
}
|
||||
AssocItemKind::Type(alias) =>
|
||||
visit_visitable!($($mut)? vis, alias),
|
||||
@@ -886,6 +890,7 @@ impl WalkItemKind for ForeignItemKind {
|
||||
type Ctxt = ();
|
||||
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
&$($lt)? $($mut)? self,
|
||||
attrs: &AttrVec,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
visibility: &$($lt)? $($mut)? Visibility,
|
||||
@@ -897,7 +902,7 @@ fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
ForeignItemKind::Fn(func) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Foreign, visibility, &$($mut)?*func);
|
||||
try_visit!(vis.visit_fn(kind, span, id))
|
||||
try_visit!(vis.visit_fn(kind, attrs, span, id))
|
||||
}
|
||||
ForeignItemKind::TyAlias(alias) =>
|
||||
visit_visitable!($($mut)? vis, alias),
|
||||
@@ -999,7 +1004,7 @@ pub fn walk_fn<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, kind: FnKind<$($lt)?
|
||||
}) => {
|
||||
visit_visitable!($($mut)? vis, constness, movability, capture_clause);
|
||||
let kind = FnKind::Closure(binder, coroutine_kind, fn_decl, body);
|
||||
try_visit!(vis.visit_fn(kind, *span, *id));
|
||||
try_visit!(vis.visit_fn(kind, attrs, *span, *id));
|
||||
visit_visitable!($($mut)? vis, fn_decl_span, fn_arg_span);
|
||||
}
|
||||
ExprKind::Block(block, opt_label) =>
|
||||
|
||||
@@ -317,4 +317,15 @@ impl Pinnedness {
|
||||
pub fn is_pinned(self) -> bool {
|
||||
matches!(self, Self::Pinned)
|
||||
}
|
||||
|
||||
/// Returns `""` (empty string), "mut", `"pin mut "` or `"pin const "` depending
|
||||
/// on the pinnedness and mutability.
|
||||
pub fn prefix_str(self, mutbl: Mutability) -> &'static str {
|
||||
match (self, mutbl) {
|
||||
(Pinnedness::Pinned, Mutability::Mut) => "pin mut ",
|
||||
(Pinnedness::Pinned, Mutability::Not) => "pin const ",
|
||||
(Pinnedness::Not, Mutability::Mut) => "mut ",
|
||||
(Pinnedness::Not, Mutability::Not) => "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::source_map::{Spanned, respan};
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
|
||||
use rustc_span::{ByteSymbol, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
use visit::{Visitor, walk_expr};
|
||||
|
||||
@@ -924,7 +924,7 @@ fn make_lowered_await(
|
||||
arena_vec![self; new_unchecked, get_context],
|
||||
),
|
||||
};
|
||||
self.arena.alloc(self.expr_unsafe(call))
|
||||
self.arena.alloc(self.expr_unsafe(span, call))
|
||||
};
|
||||
|
||||
// `::std::task::Poll::Ready(result) => break result`
|
||||
@@ -1771,8 +1771,14 @@ fn lower_expr_for(
|
||||
let pat = self.lower_pat(pat);
|
||||
let for_span =
|
||||
self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);
|
||||
let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
|
||||
let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
|
||||
let for_ctxt = for_span.ctxt();
|
||||
|
||||
// Try to point both the head and pat spans to their position in the for loop
|
||||
// rather than inside a macro.
|
||||
let head_span =
|
||||
head.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(head.span).with_ctxt(for_ctxt);
|
||||
let pat_span =
|
||||
pat.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(pat.span).with_ctxt(for_ctxt);
|
||||
|
||||
let loop_hir_id = self.lower_node_id(e.id);
|
||||
let label = self.lower_label(opt_label, e.id, loop_hir_id);
|
||||
@@ -1826,7 +1832,7 @@ fn lower_expr_for(
|
||||
arena_vec![self; iter],
|
||||
));
|
||||
// `unsafe { ... }`
|
||||
let iter = self.arena.alloc(self.expr_unsafe(iter));
|
||||
let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));
|
||||
let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator);
|
||||
self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span })
|
||||
}
|
||||
@@ -1881,7 +1887,7 @@ fn lower_expr_for(
|
||||
arena_vec![self; iter],
|
||||
));
|
||||
// `unsafe { ... }`
|
||||
let iter = self.arena.alloc(self.expr_unsafe(iter));
|
||||
let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));
|
||||
let inner_match_expr = self.arena.alloc(self.expr_match(
|
||||
for_span,
|
||||
iter,
|
||||
@@ -1923,7 +1929,7 @@ fn lower_expr_for(
|
||||
/// ControlFlow::Break(residual) =>
|
||||
/// #[allow(unreachable_code)]
|
||||
/// // If there is an enclosing `try {...}`:
|
||||
/// break 'catch_target Try::from_residual(residual),
|
||||
/// break 'catch_target Residual::into_try_type(residual),
|
||||
/// // Otherwise:
|
||||
/// return Try::from_residual(residual),
|
||||
/// }
|
||||
@@ -1973,7 +1979,11 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir>
|
||||
let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);
|
||||
let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);
|
||||
let from_residual_expr = self.wrap_in_try_constructor(
|
||||
hir::LangItem::TryTraitFromResidual,
|
||||
if self.catch_scope.is_some() {
|
||||
hir::LangItem::ResidualIntoTryType
|
||||
} else {
|
||||
hir::LangItem::TryTraitFromResidual
|
||||
},
|
||||
try_span,
|
||||
self.arena.alloc(residual_expr),
|
||||
unstable_span,
|
||||
@@ -2097,26 +2107,6 @@ pub(super) fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
|
||||
self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[])))
|
||||
}
|
||||
|
||||
fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> {
|
||||
let lit = hir::Lit {
|
||||
span: self.lower_span(sp),
|
||||
node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)),
|
||||
};
|
||||
self.expr(sp, hir::ExprKind::Lit(lit))
|
||||
}
|
||||
|
||||
pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
|
||||
self.expr_uint(sp, ast::UintTy::Usize, value as u128)
|
||||
}
|
||||
|
||||
pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> {
|
||||
self.expr_uint(sp, ast::UintTy::U32, value as u128)
|
||||
}
|
||||
|
||||
pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> {
|
||||
self.expr_uint(sp, ast::UintTy::U16, value as u128)
|
||||
}
|
||||
|
||||
pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
|
||||
let lit = hir::Lit {
|
||||
span: self.lower_span(sp),
|
||||
@@ -2125,6 +2115,14 @@ pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
|
||||
self.expr(sp, hir::ExprKind::Lit(lit))
|
||||
}
|
||||
|
||||
pub(super) fn expr_byte_str(&mut self, sp: Span, value: ByteSymbol) -> hir::Expr<'hir> {
|
||||
let lit = hir::Lit {
|
||||
span: self.lower_span(sp),
|
||||
node: ast::LitKind::ByteStr(value, ast::StrStyle::Cooked),
|
||||
};
|
||||
self.expr(sp, hir::ExprKind::Lit(lit))
|
||||
}
|
||||
|
||||
pub(super) fn expr_call_mut(
|
||||
&mut self,
|
||||
span: Span,
|
||||
@@ -2256,9 +2254,12 @@ pub(super) fn expr_ident_mut(
|
||||
self.expr(span, expr_path)
|
||||
}
|
||||
|
||||
fn expr_unsafe(&mut self, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
|
||||
pub(super) fn expr_unsafe(
|
||||
&mut self,
|
||||
span: Span,
|
||||
expr: &'hir hir::Expr<'hir>,
|
||||
) -> hir::Expr<'hir> {
|
||||
let hir_id = self.next_id();
|
||||
let span = expr.span;
|
||||
self.expr(
|
||||
span,
|
||||
hir::ExprKind::Block(
|
||||
@@ -2296,15 +2297,6 @@ pub(super) fn block_expr_block(
|
||||
self.arena.alloc(self.expr_block(b))
|
||||
}
|
||||
|
||||
pub(super) fn expr_array_ref(
|
||||
&mut self,
|
||||
span: Span,
|
||||
elements: &'hir [hir::Expr<'hir>],
|
||||
) -> hir::Expr<'hir> {
|
||||
let array = self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements)));
|
||||
self.expr_ref(span, array)
|
||||
}
|
||||
|
||||
pub(super) fn expr_ref(&mut self, span: Span, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
|
||||
self.expr(span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr))
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_session::config::FmtDebug;
|
||||
use rustc_span::{DesugaringKind, Ident, Span, Symbol, sym};
|
||||
use rustc_span::{ByteSymbol, DesugaringKind, Ident, Span, Symbol, sym};
|
||||
|
||||
use super::LoweringContext;
|
||||
|
||||
@@ -90,20 +90,14 @@ fn inline_literals<'fmt>(&self, mut fmt: Cow<'fmt, FormatArgs>) -> Cow<'fmt, For
|
||||
let mut inlined_anything = false;
|
||||
|
||||
for i in 0..fmt.template.len() {
|
||||
let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i] else { continue };
|
||||
let Ok(arg_index) = placeholder.argument.index else { continue };
|
||||
|
||||
let mut literal = None;
|
||||
|
||||
if let FormatTrait::Display = placeholder.format_trait
|
||||
if let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i]
|
||||
&& let Ok(arg_index) = placeholder.argument.index
|
||||
&& let FormatTrait::Display = placeholder.format_trait
|
||||
&& placeholder.format_options == Default::default()
|
||||
&& let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs()
|
||||
&& let ExprKind::Lit(lit) = arg.kind
|
||||
&& let Some(literal) = self.try_inline_lit(lit)
|
||||
{
|
||||
literal = self.try_inline_lit(lit);
|
||||
}
|
||||
|
||||
if let Some(literal) = literal {
|
||||
// Now we need to mutate the outer FormatArgs.
|
||||
// If this is the first time, this clones the outer FormatArgs.
|
||||
let fmt = fmt.to_mut();
|
||||
@@ -265,136 +259,21 @@ fn make_argument<'hir>(
|
||||
ctx.expr_call_mut(sp, new_fn, std::slice::from_ref(arg))
|
||||
}
|
||||
|
||||
/// Generate a hir expression for a format_args Count.
|
||||
/// Get the value for a `width` or `precision` field.
|
||||
///
|
||||
/// Generates:
|
||||
///
|
||||
/// ```text
|
||||
/// <core::fmt::rt::Count>::Is(…)
|
||||
/// ```
|
||||
///
|
||||
/// or
|
||||
///
|
||||
/// ```text
|
||||
/// <core::fmt::rt::Count>::Param(…)
|
||||
/// ```
|
||||
///
|
||||
/// or
|
||||
///
|
||||
/// ```text
|
||||
/// <core::fmt::rt::Count>::Implied
|
||||
/// ```
|
||||
fn make_count<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
sp: Span,
|
||||
count: &Option<FormatCount>,
|
||||
/// Returns the value and whether it is indirect (an indexed argument) or not.
|
||||
fn make_count(
|
||||
count: &FormatCount,
|
||||
argmap: &mut FxIndexMap<(usize, ArgumentType), Option<Span>>,
|
||||
) -> hir::Expr<'hir> {
|
||||
) -> (bool, u16) {
|
||||
match count {
|
||||
Some(FormatCount::Literal(n)) => {
|
||||
let count_is = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
sp,
|
||||
hir::LangItem::FormatCount,
|
||||
sym::Is,
|
||||
));
|
||||
let value = ctx.arena.alloc_from_iter([ctx.expr_u16(sp, *n)]);
|
||||
ctx.expr_call_mut(sp, count_is, value)
|
||||
}
|
||||
Some(FormatCount::Argument(arg)) => {
|
||||
if let Ok(arg_index) = arg.index {
|
||||
let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize), arg.span);
|
||||
let count_param = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
sp,
|
||||
hir::LangItem::FormatCount,
|
||||
sym::Param,
|
||||
));
|
||||
let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, i)]);
|
||||
ctx.expr_call_mut(sp, count_param, value)
|
||||
} else {
|
||||
ctx.expr(
|
||||
sp,
|
||||
hir::ExprKind::Err(
|
||||
ctx.dcx().span_delayed_bug(sp, "lowered bad format_args count"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
None => ctx.expr_lang_item_type_relative(sp, hir::LangItem::FormatCount, sym::Implied),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a hir expression for a format_args placeholder specification.
|
||||
///
|
||||
/// Generates
|
||||
///
|
||||
/// ```text
|
||||
/// <core::fmt::rt::Placeholder {
|
||||
/// position: …usize,
|
||||
/// flags: …u32,
|
||||
/// precision: <core::fmt::rt::Count::…>,
|
||||
/// width: <core::fmt::rt::Count::…>,
|
||||
/// }
|
||||
/// ```
|
||||
fn make_format_spec<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
sp: Span,
|
||||
placeholder: &FormatPlaceholder,
|
||||
argmap: &mut FxIndexMap<(usize, ArgumentType), Option<Span>>,
|
||||
) -> hir::Expr<'hir> {
|
||||
let position = match placeholder.argument.index {
|
||||
Ok(arg_index) => {
|
||||
let (i, _) = argmap.insert_full(
|
||||
(arg_index, ArgumentType::Format(placeholder.format_trait)),
|
||||
placeholder.span,
|
||||
);
|
||||
ctx.expr_usize(sp, i)
|
||||
}
|
||||
Err(_) => ctx.expr(
|
||||
sp,
|
||||
hir::ExprKind::Err(ctx.dcx().span_delayed_bug(sp, "lowered bad format_args count")),
|
||||
FormatCount::Literal(n) => (false, *n),
|
||||
FormatCount::Argument(arg) => (
|
||||
true,
|
||||
argmap.insert_full((arg.index.unwrap_or(usize::MAX), ArgumentType::Usize), arg.span).0
|
||||
as u16,
|
||||
),
|
||||
};
|
||||
let &FormatOptions {
|
||||
ref width,
|
||||
ref precision,
|
||||
alignment,
|
||||
fill,
|
||||
sign,
|
||||
alternate,
|
||||
zero_pad,
|
||||
debug_hex,
|
||||
} = &placeholder.format_options;
|
||||
let fill = fill.unwrap_or(' ');
|
||||
// These need to match the constants in library/core/src/fmt/rt.rs.
|
||||
let align = match alignment {
|
||||
Some(FormatAlignment::Left) => 0,
|
||||
Some(FormatAlignment::Right) => 1,
|
||||
Some(FormatAlignment::Center) => 2,
|
||||
None => 3,
|
||||
};
|
||||
// This needs to match the constants in library/core/src/fmt/rt.rs.
|
||||
let flags: u32 = fill as u32
|
||||
| ((sign == Some(FormatSign::Plus)) as u32) << 21
|
||||
| ((sign == Some(FormatSign::Minus)) as u32) << 22
|
||||
| (alternate as u32) << 23
|
||||
| (zero_pad as u32) << 24
|
||||
| ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
|
||||
| ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
|
||||
| (width.is_some() as u32) << 27
|
||||
| (precision.is_some() as u32) << 28
|
||||
| align << 29
|
||||
| 1 << 31; // Highest bit always set.
|
||||
let flags = ctx.expr_u32(sp, flags);
|
||||
let precision = make_count(ctx, sp, precision, argmap);
|
||||
let width = make_count(ctx, sp, width, argmap);
|
||||
let position = ctx.expr_field(Ident::new(sym::position, sp), ctx.arena.alloc(position), sp);
|
||||
let flags = ctx.expr_field(Ident::new(sym::flags, sp), ctx.arena.alloc(flags), sp);
|
||||
let precision = ctx.expr_field(Ident::new(sym::precision, sp), ctx.arena.alloc(precision), sp);
|
||||
let width = ctx.expr_field(Ident::new(sym::width, sp), ctx.arena.alloc(width), sp);
|
||||
let placeholder =
|
||||
ctx.arena.alloc(ctx.make_lang_item_qpath(hir::LangItem::FormatPlaceholder, sp, None));
|
||||
let fields = ctx.arena.alloc_from_iter([position, flags, precision, width]);
|
||||
ctx.expr(sp, hir::ExprKind::Struct(placeholder, fields, hir::StructTailExpr::None))
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_format_args<'hir>(
|
||||
@@ -405,85 +284,152 @@ fn expand_format_args<'hir>(
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let macsp = ctx.lower_span(macsp);
|
||||
|
||||
let mut incomplete_lit = String::new();
|
||||
let lit_pieces =
|
||||
ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| {
|
||||
match piece {
|
||||
&FormatArgsPiece::Literal(s) => {
|
||||
// Coalesce adjacent literal pieces.
|
||||
if let Some(FormatArgsPiece::Literal(_)) = fmt.template.get(i + 1) {
|
||||
incomplete_lit.push_str(s.as_str());
|
||||
None
|
||||
} else if !incomplete_lit.is_empty() {
|
||||
incomplete_lit.push_str(s.as_str());
|
||||
let s = Symbol::intern(&incomplete_lit);
|
||||
incomplete_lit.clear();
|
||||
Some(ctx.expr_str(fmt.span, s))
|
||||
} else {
|
||||
Some(ctx.expr_str(fmt.span, s))
|
||||
}
|
||||
}
|
||||
&FormatArgsPiece::Placeholder(_) => {
|
||||
// Inject empty string before placeholders when not already preceded by a literal piece.
|
||||
if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
|
||||
Some(ctx.expr_str(fmt.span, sym::empty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
let lit_pieces = ctx.expr_array_ref(fmt.span, lit_pieces);
|
||||
|
||||
// Whether we'll use the `Arguments::new_v1_formatted` form (true),
|
||||
// or the `Arguments::new_v1` form (false).
|
||||
let mut use_format_options = false;
|
||||
|
||||
// Create a list of all _unique_ (argument, format trait) combinations.
|
||||
// E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
|
||||
//
|
||||
// We use usize::MAX for arguments that don't exist, because that can never be a valid index
|
||||
// into the arguments array.
|
||||
let mut argmap = FxIndexMap::default();
|
||||
for piece in &fmt.template {
|
||||
let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
|
||||
if placeholder.format_options != Default::default() {
|
||||
// Can't use basic form if there's any formatting options.
|
||||
use_format_options = true;
|
||||
}
|
||||
if let Ok(index) = placeholder.argument.index {
|
||||
if argmap
|
||||
.insert((index, ArgumentType::Format(placeholder.format_trait)), placeholder.span)
|
||||
.is_some()
|
||||
{
|
||||
// Duplicate (argument, format trait) combination,
|
||||
// which we'll only put once in the args array.
|
||||
use_format_options = true;
|
||||
|
||||
let mut incomplete_lit = String::new();
|
||||
|
||||
let mut implicit_arg_index = 0;
|
||||
|
||||
let mut bytecode = Vec::new();
|
||||
|
||||
let template = if fmt.template.is_empty() {
|
||||
// Treat empty templates as a single literal piece (with an empty string),
|
||||
// so we produce `from_str("")` for those.
|
||||
&[FormatArgsPiece::Literal(sym::empty)][..]
|
||||
} else {
|
||||
&fmt.template[..]
|
||||
};
|
||||
|
||||
// See library/core/src/fmt/mod.rs for the format string encoding format.
|
||||
|
||||
for (i, piece) in template.iter().enumerate() {
|
||||
match piece {
|
||||
&FormatArgsPiece::Literal(sym) => {
|
||||
// Coalesce adjacent literal pieces.
|
||||
if let Some(FormatArgsPiece::Literal(_)) = template.get(i + 1) {
|
||||
incomplete_lit.push_str(sym.as_str());
|
||||
continue;
|
||||
}
|
||||
let mut s = if incomplete_lit.is_empty() {
|
||||
sym.as_str()
|
||||
} else {
|
||||
incomplete_lit.push_str(sym.as_str());
|
||||
&incomplete_lit
|
||||
};
|
||||
|
||||
// If this is the last piece and was the only piece, that means
|
||||
// there are no placeholders and the entire format string is just a literal.
|
||||
//
|
||||
// In that case, we can just use `from_str`.
|
||||
if i + 1 == template.len() && bytecode.is_empty() {
|
||||
// Generate:
|
||||
// <core::fmt::Arguments>::from_str("meow")
|
||||
let from_str = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
macsp,
|
||||
hir::LangItem::FormatArguments,
|
||||
if allow_const { sym::from_str } else { sym::from_str_nonconst },
|
||||
));
|
||||
let sym = if incomplete_lit.is_empty() { sym } else { Symbol::intern(s) };
|
||||
let s = ctx.expr_str(fmt.span, sym);
|
||||
let args = ctx.arena.alloc_from_iter([s]);
|
||||
return hir::ExprKind::Call(from_str, args);
|
||||
}
|
||||
|
||||
// Encode the literal in chunks of up to u16::MAX bytes, split at utf-8 boundaries.
|
||||
while !s.is_empty() {
|
||||
let len = s.floor_char_boundary(usize::from(u16::MAX));
|
||||
if len < 0x80 {
|
||||
bytecode.push(len as u8);
|
||||
} else {
|
||||
bytecode.push(0x80);
|
||||
bytecode.extend_from_slice(&(len as u16).to_le_bytes());
|
||||
}
|
||||
bytecode.extend(&s.as_bytes()[..len]);
|
||||
s = &s[len..];
|
||||
}
|
||||
|
||||
incomplete_lit.clear();
|
||||
}
|
||||
FormatArgsPiece::Placeholder(p) => {
|
||||
// Push the start byte and remember its index so we can set the option bits later.
|
||||
let i = bytecode.len();
|
||||
bytecode.push(0xC0);
|
||||
|
||||
let position = argmap
|
||||
.insert_full(
|
||||
(
|
||||
p.argument.index.unwrap_or(usize::MAX),
|
||||
ArgumentType::Format(p.format_trait),
|
||||
),
|
||||
p.span,
|
||||
)
|
||||
.0 as u64;
|
||||
|
||||
// This needs to match the constants in library/core/src/fmt/mod.rs.
|
||||
let o = &p.format_options;
|
||||
let align = match o.alignment {
|
||||
Some(FormatAlignment::Left) => 0,
|
||||
Some(FormatAlignment::Right) => 1,
|
||||
Some(FormatAlignment::Center) => 2,
|
||||
None => 3,
|
||||
};
|
||||
let default_flags = 0x6000_0020;
|
||||
let flags: u32 = o.fill.unwrap_or(' ') as u32
|
||||
| ((o.sign == Some(FormatSign::Plus)) as u32) << 21
|
||||
| ((o.sign == Some(FormatSign::Minus)) as u32) << 22
|
||||
| (o.alternate as u32) << 23
|
||||
| (o.zero_pad as u32) << 24
|
||||
| ((o.debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
|
||||
| ((o.debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
|
||||
| (o.width.is_some() as u32) << 27
|
||||
| (o.precision.is_some() as u32) << 28
|
||||
| align << 29;
|
||||
if flags != default_flags {
|
||||
bytecode[i] |= 1;
|
||||
bytecode.extend_from_slice(&flags.to_le_bytes());
|
||||
if let Some(val) = &o.width {
|
||||
let (indirect, val) = make_count(val, &mut argmap);
|
||||
// Only encode if nonzero; zero is the default.
|
||||
if indirect || val != 0 {
|
||||
bytecode[i] |= 1 << 1 | (indirect as u8) << 4;
|
||||
bytecode.extend_from_slice(&val.to_le_bytes());
|
||||
}
|
||||
}
|
||||
if let Some(val) = &o.precision {
|
||||
let (indirect, val) = make_count(val, &mut argmap);
|
||||
// Only encode if nonzero; zero is the default.
|
||||
if indirect || val != 0 {
|
||||
bytecode[i] |= 1 << 2 | (indirect as u8) << 5;
|
||||
bytecode.extend_from_slice(&val.to_le_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
if implicit_arg_index != position {
|
||||
bytecode[i] |= 1 << 3;
|
||||
bytecode.extend_from_slice(&(position as u16).to_le_bytes());
|
||||
}
|
||||
implicit_arg_index = position + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let format_options = use_format_options.then(|| {
|
||||
// Generate:
|
||||
// &[format_spec_0, format_spec_1, format_spec_2]
|
||||
let elements = ctx.arena.alloc_from_iter(fmt.template.iter().filter_map(|piece| {
|
||||
let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
|
||||
Some(make_format_spec(ctx, macsp, placeholder, &mut argmap))
|
||||
}));
|
||||
ctx.expr_array_ref(macsp, elements)
|
||||
});
|
||||
assert!(incomplete_lit.is_empty());
|
||||
|
||||
// Zero terminator.
|
||||
bytecode.push(0);
|
||||
|
||||
// Ensure all argument indexes actually fit in 16 bits, as we truncated them to 16 bits before.
|
||||
if argmap.len() > u16::MAX as usize {
|
||||
ctx.dcx().span_err(macsp, "too many format arguments");
|
||||
}
|
||||
|
||||
let arguments = fmt.arguments.all_args();
|
||||
|
||||
if allow_const && arguments.is_empty() && argmap.is_empty() {
|
||||
// Generate:
|
||||
// <core::fmt::Arguments>::new_const(lit_pieces)
|
||||
let new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
macsp,
|
||||
hir::LangItem::FormatArguments,
|
||||
sym::new_const,
|
||||
));
|
||||
let new_args = ctx.arena.alloc_from_iter([lit_pieces]);
|
||||
return hir::ExprKind::Call(new, new_args);
|
||||
}
|
||||
|
||||
let (let_statements, args) = if arguments.is_empty() {
|
||||
// Generate:
|
||||
// []
|
||||
@@ -512,22 +458,30 @@ fn expand_format_args<'hir>(
|
||||
// ];
|
||||
let args = ctx.arena.alloc_from_iter(argmap.iter().map(
|
||||
|(&(arg_index, ty), &placeholder_span)| {
|
||||
let arg = &arguments[arg_index];
|
||||
let placeholder_span =
|
||||
placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt());
|
||||
let arg_span = match arg.kind {
|
||||
FormatArgumentKind::Captured(_) => placeholder_span,
|
||||
_ => arg.expr.span.with_ctxt(macsp.ctxt()),
|
||||
};
|
||||
let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id);
|
||||
let arg = ctx.arena.alloc(ctx.expr(
|
||||
arg_span,
|
||||
hir::ExprKind::Field(
|
||||
args_ident_expr,
|
||||
Ident::new(sym::integer(arg_index), macsp),
|
||||
),
|
||||
));
|
||||
make_argument(ctx, placeholder_span, arg, ty)
|
||||
if let Some(arg) = arguments.get(arg_index) {
|
||||
let placeholder_span =
|
||||
placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt());
|
||||
let arg_span = match arg.kind {
|
||||
FormatArgumentKind::Captured(_) => placeholder_span,
|
||||
_ => arg.expr.span.with_ctxt(macsp.ctxt()),
|
||||
};
|
||||
let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id);
|
||||
let arg = ctx.arena.alloc(ctx.expr(
|
||||
arg_span,
|
||||
hir::ExprKind::Field(
|
||||
args_ident_expr,
|
||||
Ident::new(sym::integer(arg_index), macsp),
|
||||
),
|
||||
));
|
||||
make_argument(ctx, placeholder_span, arg, ty)
|
||||
} else {
|
||||
ctx.expr(
|
||||
macsp,
|
||||
hir::ExprKind::Err(
|
||||
ctx.dcx().span_delayed_bug(macsp, "missing format_args argument"),
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
));
|
||||
let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
|
||||
@@ -540,58 +494,38 @@ fn expand_format_args<'hir>(
|
||||
};
|
||||
|
||||
// Generate:
|
||||
// &args
|
||||
let args = ctx.expr_ref(macsp, args);
|
||||
|
||||
let call = if let Some(format_options) = format_options {
|
||||
// Generate:
|
||||
// unsafe {
|
||||
// <core::fmt::Arguments>::new_v1_formatted(
|
||||
// lit_pieces,
|
||||
// args,
|
||||
// format_options,
|
||||
// )
|
||||
// }
|
||||
let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
// unsafe {
|
||||
// <core::fmt::Arguments>::new(b"…", &args)
|
||||
// }
|
||||
let template = ctx.expr_byte_str(macsp, ByteSymbol::intern(&bytecode));
|
||||
let call = {
|
||||
let new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
macsp,
|
||||
hir::LangItem::FormatArguments,
|
||||
sym::new_v1_formatted,
|
||||
sym::new,
|
||||
));
|
||||
let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options]);
|
||||
let call = ctx.expr_call(macsp, new_v1_formatted, args);
|
||||
let hir_id = ctx.next_id();
|
||||
hir::ExprKind::Block(
|
||||
ctx.arena.alloc(hir::Block {
|
||||
stmts: &[],
|
||||
expr: Some(call),
|
||||
hir_id,
|
||||
rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
|
||||
span: macsp,
|
||||
targeted_by_break: false,
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
// Generate:
|
||||
// <core::fmt::Arguments>::new_v1(
|
||||
// lit_pieces,
|
||||
// args,
|
||||
// )
|
||||
let new_v1 = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
macsp,
|
||||
hir::LangItem::FormatArguments,
|
||||
sym::new_v1,
|
||||
));
|
||||
let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]);
|
||||
hir::ExprKind::Call(new_v1, new_args)
|
||||
let args = ctx.expr_ref(macsp, args);
|
||||
let new_args = ctx.arena.alloc_from_iter([template, args]);
|
||||
ctx.expr_call(macsp, new, new_args)
|
||||
};
|
||||
let call = hir::ExprKind::Block(
|
||||
ctx.arena.alloc(hir::Block {
|
||||
stmts: &[],
|
||||
expr: Some(call),
|
||||
hir_id: ctx.next_id(),
|
||||
rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
|
||||
span: macsp,
|
||||
targeted_by_break: false,
|
||||
}),
|
||||
None,
|
||||
);
|
||||
|
||||
if !let_statements.is_empty() {
|
||||
// Generate:
|
||||
// {
|
||||
// super let …
|
||||
// super let …
|
||||
// <core::fmt::Arguments>::new_…(…)
|
||||
// <core::fmt::Arguments>::new(…)
|
||||
// }
|
||||
let call = ctx.arena.alloc(ctx.expr(macsp, call));
|
||||
let block = ctx.block_all(macsp, ctx.arena.alloc_from_iter(let_statements), Some(call));
|
||||
|
||||
@@ -125,9 +125,9 @@ fn insert_nested(&mut self, item: LocalDefId) {
|
||||
}
|
||||
|
||||
impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
/// Because we want to track parent items and so forth, enable
|
||||
/// deep walking so that we walk nested items in the context of
|
||||
/// their outer items.
|
||||
// Because we want to track parent items and so forth, enable
|
||||
// deep walking so that we walk nested items in the context of
|
||||
// their outer items.
|
||||
|
||||
fn visit_nested_item(&mut self, item: ItemId) {
|
||||
debug!("visit_nested_item: {:?}", item);
|
||||
|
||||
@@ -183,7 +183,12 @@ fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
|
||||
impl_trait_defs: Vec::new(),
|
||||
impl_trait_bounds: Vec::new(),
|
||||
allow_contracts: [sym::contracts_internals].into(),
|
||||
allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(),
|
||||
allow_try_trait: [
|
||||
sym::try_trait_v2,
|
||||
sym::try_trait_v2_residual,
|
||||
sym::yeet_desugar_details,
|
||||
]
|
||||
.into(),
|
||||
allow_pattern_type: [sym::pattern_types, sym::pattern_type_range_trait].into(),
|
||||
allow_gen_future: if tcx.features().async_fn_track_caller() {
|
||||
[sym::gen_future, sym::closure_track_caller].into()
|
||||
|
||||
@@ -124,8 +124,8 @@ fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
|
||||
PatKind::Deref(inner) => {
|
||||
break hir::PatKind::Deref(self.lower_pat(inner));
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
break hir::PatKind::Ref(self.lower_pat(inner), *mutbl);
|
||||
PatKind::Ref(inner, pinned, mutbl) => {
|
||||
break hir::PatKind::Ref(self.lower_pat(inner), *pinned, *mutbl);
|
||||
}
|
||||
PatKind::Range(e1, e2, Spanned { node: end, .. }) => {
|
||||
break hir::PatKind::Range(
|
||||
|
||||
@@ -68,6 +68,10 @@ ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"`
|
||||
.label = `extern "{$abi}"` because of this
|
||||
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
ast_passes_c_variadic_bad_naked_extern = `...` is not supported for `extern "{$abi}"` naked functions
|
||||
.label = `extern "{$abi}"` because of this
|
||||
.help = C-variadic function must have a compatible calling convention
|
||||
|
||||
ast_passes_c_variadic_must_be_unsafe =
|
||||
functions with a C variable argument list must be unsafe
|
||||
.suggestion = add the `unsafe` keyword to this definition
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
|
||||
use rustc_abi::{CVariadicStatus, CanonAbi, ExternAbi, InterruptKind};
|
||||
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
@@ -35,6 +35,7 @@
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
use rustc_target::spec::{AbiMap, AbiMapping};
|
||||
use thin_vec::thin_vec;
|
||||
@@ -661,7 +662,7 @@ fn check_foreign_item_ascii_only(&self, ident: Ident) {
|
||||
/// C-variadics must be:
|
||||
/// - Non-const
|
||||
/// - Either foreign, or free and `unsafe extern "C"` semantically
|
||||
fn check_c_variadic_type(&self, fk: FnKind<'a>) {
|
||||
fn check_c_variadic_type(&self, fk: FnKind<'a>, attrs: &'a AttrVec) {
|
||||
// `...` is already rejected when it is not the final parameter.
|
||||
let variadic_param = match fk.decl().inputs.last() {
|
||||
Some(param) if matches!(param.ty.kind, TyKind::CVarArgs) => param,
|
||||
@@ -693,36 +694,92 @@ fn check_c_variadic_type(&self, fk: FnKind<'a>) {
|
||||
|
||||
match fn_ctxt {
|
||||
FnCtxt::Foreign => return,
|
||||
FnCtxt::Free | FnCtxt::Assoc(_) => match sig.header.ext {
|
||||
Extern::Implicit(_) => {
|
||||
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
|
||||
span: variadic_param.span,
|
||||
unsafe_span: sig.safety_span(),
|
||||
});
|
||||
FnCtxt::Free | FnCtxt::Assoc(_) => {
|
||||
match sig.header.ext {
|
||||
Extern::Implicit(_) => {
|
||||
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
|
||||
span: variadic_param.span,
|
||||
unsafe_span: sig.safety_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
|
||||
// Just bail if the ABI is not even recognized.
|
||||
let Ok(abi) = ExternAbi::from_str(symbol_unescaped.as_str()) else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.check_c_variadic_abi(abi, attrs, variadic_param.span, sig);
|
||||
|
||||
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
|
||||
span: variadic_param.span,
|
||||
unsafe_span: sig.safety_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Extern::None => {
|
||||
let err = errors::CVariadicNoExtern { span: variadic_param.span };
|
||||
self.dcx().emit_err(err);
|
||||
}
|
||||
}
|
||||
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
|
||||
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
|
||||
self.dcx().emit_err(errors::CVariadicBadExtern {
|
||||
span: variadic_param.span,
|
||||
abi: symbol_unescaped,
|
||||
extern_span: sig.extern_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_c_variadic_abi(
|
||||
&self,
|
||||
abi: ExternAbi,
|
||||
attrs: &'a AttrVec,
|
||||
dotdotdot_span: Span,
|
||||
sig: &FnSig,
|
||||
) {
|
||||
// For naked functions we accept any ABI that is accepted on c-variadic
|
||||
// foreign functions, if the c_variadic_naked_functions feature is enabled.
|
||||
if attr::contains_name(attrs, sym::naked) {
|
||||
match abi.supports_c_variadic() {
|
||||
CVariadicStatus::Stable if let ExternAbi::C { .. } = abi => {
|
||||
// With `c_variadic` naked c-variadic `extern "C"` functions are allowed.
|
||||
}
|
||||
CVariadicStatus::Stable => {
|
||||
// For e.g. aapcs or sysv64 `c_variadic_naked_functions` must also be enabled.
|
||||
if !self.features.enabled(sym::c_variadic_naked_functions) {
|
||||
let msg = format!("Naked c-variadic `extern {abi}` functions are unstable");
|
||||
feature_err(&self.sess, sym::c_variadic_naked_functions, sig.span, msg)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
CVariadicStatus::Unstable { feature } => {
|
||||
// Some ABIs need additional features.
|
||||
if !self.features.enabled(sym::c_variadic_naked_functions) {
|
||||
let msg = format!("Naked c-variadic `extern {abi}` functions are unstable");
|
||||
feature_err(&self.sess, sym::c_variadic_naked_functions, sig.span, msg)
|
||||
.emit();
|
||||
}
|
||||
|
||||
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
|
||||
span: variadic_param.span,
|
||||
unsafe_span: sig.safety_span(),
|
||||
});
|
||||
if !self.features.enabled(feature) {
|
||||
let msg = format!(
|
||||
"C-variadic functions with the {abi} calling convention are unstable"
|
||||
);
|
||||
feature_err(&self.sess, feature, sig.span, msg).emit();
|
||||
}
|
||||
}
|
||||
Extern::None => {
|
||||
let err = errors::CVariadicNoExtern { span: variadic_param.span };
|
||||
self.dcx().emit_err(err);
|
||||
CVariadicStatus::NotSupported => {
|
||||
// Some ABIs, e.g. `extern "Rust"`, never support c-variadic functions.
|
||||
self.dcx().emit_err(errors::CVariadicBadNakedExtern {
|
||||
span: dotdotdot_span,
|
||||
abi: abi.as_str(),
|
||||
extern_span: sig.extern_span(),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
} else if !matches!(abi, ExternAbi::C { .. }) {
|
||||
self.dcx().emit_err(errors::CVariadicBadExtern {
|
||||
span: dotdotdot_span,
|
||||
abi: abi.as_str(),
|
||||
extern_span: sig.extern_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1106,7 +1163,7 @@ fn visit_item(&mut self, item: &'a Item) {
|
||||
}
|
||||
|
||||
let kind = FnKind::Fn(FnCtxt::Free, &item.vis, &*func);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
self.visit_fn(kind, &item.attrs, item.span, item.id);
|
||||
}
|
||||
ItemKind::ForeignMod(ForeignMod { extern_span, abi, safety, .. }) => {
|
||||
let old_item = mem::replace(&mut self.extern_mod_span, Some(item.span));
|
||||
@@ -1473,7 +1530,7 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
|
||||
visit::walk_param_bound(self, bound)
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
|
||||
fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId) {
|
||||
// Only associated `fn`s can have `self` parameters.
|
||||
let self_semantic = match fk.ctxt() {
|
||||
Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
|
||||
@@ -1492,7 +1549,7 @@ fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
|
||||
self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig);
|
||||
}
|
||||
|
||||
self.check_c_variadic_type(fk);
|
||||
self.check_c_variadic_type(fk, attrs);
|
||||
|
||||
// Functions cannot both be `const async` or `const gen`
|
||||
if let Some(&FnHeader {
|
||||
@@ -1643,7 +1700,7 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
||||
{
|
||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, &func.ident);
|
||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
self.visit_fn(kind, &item.attrs, item.span, item.id);
|
||||
}
|
||||
AssocItemKind::Type(_) => {
|
||||
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
|
||||
|
||||
@@ -347,7 +347,18 @@ pub(crate) struct CVariadicMustBeUnsafe {
|
||||
pub(crate) struct CVariadicBadExtern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub abi: Symbol,
|
||||
pub abi: &'static str,
|
||||
#[label]
|
||||
pub extern_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_c_variadic_bad_naked_extern)]
|
||||
#[help]
|
||||
pub(crate) struct CVariadicBadNakedExtern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub abi: &'static str,
|
||||
#[label]
|
||||
pub extern_span: Span,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{NodeId, PatKind, attr, token};
|
||||
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
|
||||
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::{feature_err, feature_warn};
|
||||
@@ -392,7 +391,7 @@ fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
|
||||
visit::walk_poly_trait_ref(self, t);
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'a>, _: &AttrVec, span: Span, _: NodeId) {
|
||||
if let Some(_header) = fn_kind.header() {
|
||||
// Stability of const fn methods are covered in `visit_assoc_item` below.
|
||||
}
|
||||
|
||||
@@ -1807,8 +1807,14 @@ fn print_pat(&mut self, pat: &ast::Pat) {
|
||||
self.print_pat(inner);
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
PatKind::Ref(inner, pinned, mutbl) => {
|
||||
self.word("&");
|
||||
if pinned.is_pinned() {
|
||||
self.word("pin ");
|
||||
if mutbl.is_not() {
|
||||
self.word("const ");
|
||||
}
|
||||
}
|
||||
if mutbl.is_mut() {
|
||||
self.word("mut ");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
use rustc_ast::token::Token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrStyle, NodeId, token};
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span};
|
||||
|
||||
use crate::parser::MetaItemOrLitParser;
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||
|
||||
pub enum CfgSelectPredicate {
|
||||
Cfg(CfgEntry),
|
||||
Wildcard(Token),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CfgSelectBranches {
|
||||
/// All the conditional branches.
|
||||
pub reachable: Vec<(CfgEntry, TokenStream, Span)>,
|
||||
/// The first wildcard `_ => { ... }` branch.
|
||||
pub wildcard: Option<(Token, TokenStream, Span)>,
|
||||
/// All branches after the first wildcard, including further wildcards.
|
||||
/// These branches are kept for formatting.
|
||||
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
|
||||
}
|
||||
|
||||
pub fn parse_cfg_select(
|
||||
p: &mut Parser<'_>,
|
||||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
lint_node_id: NodeId,
|
||||
) -> Result<CfgSelectBranches, ErrorGuaranteed> {
|
||||
let mut branches = CfgSelectBranches::default();
|
||||
|
||||
while p.token != token::Eof {
|
||||
if p.eat_keyword(exp!(Underscore)) {
|
||||
let underscore = p.prev_token;
|
||||
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
|
||||
|
||||
let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
|
||||
let span = underscore.span.to(p.token.span);
|
||||
|
||||
match branches.wildcard {
|
||||
None => branches.wildcard = Some((underscore, tts, span)),
|
||||
Some(_) => {
|
||||
branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg_span = meta.span();
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
sess,
|
||||
cfg_span,
|
||||
cfg_span,
|
||||
AttrStyle::Inner,
|
||||
AttrPath {
|
||||
segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
|
||||
span: cfg_span,
|
||||
},
|
||||
ParsedDescription::Macro,
|
||||
cfg_span,
|
||||
lint_node_id,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&AttributeTemplate::default(),
|
||||
)?;
|
||||
|
||||
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
|
||||
|
||||
let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
|
||||
let span = cfg_span.to(p.token.span);
|
||||
|
||||
match branches.wildcard {
|
||||
None => branches.reachable.push((cfg, tts, span)),
|
||||
Some(_) => branches.unreachable.push((CfgSelectPredicate::Cfg(cfg), tts, span)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(branches)
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
pub(crate) mod body;
|
||||
pub(crate) mod cfg;
|
||||
pub(crate) mod cfg_old;
|
||||
pub(crate) mod cfg_select;
|
||||
pub(crate) mod codegen_attrs;
|
||||
pub(crate) mod confusables;
|
||||
pub(crate) mod crate_level;
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry,
|
||||
};
|
||||
pub use attributes::cfg_old::*;
|
||||
pub use attributes::cfg_select::*;
|
||||
pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version};
|
||||
pub use context::{Early, Late, OmitDoc, ShouldEmit};
|
||||
pub use interface::AttributeParser;
|
||||
|
||||
@@ -209,7 +209,7 @@ pub fn check_attribute_safety(
|
||||
|
||||
// - Normal builtin attribute
|
||||
// - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
|
||||
(Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
|
||||
(None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
|
||||
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
|
||||
span: unsafe_span,
|
||||
name: attr_item.path.clone(),
|
||||
@@ -218,15 +218,10 @@ pub fn check_attribute_safety(
|
||||
|
||||
// - Normal builtin attribute
|
||||
// - No explicit `#[unsafe(..)]` written.
|
||||
(Some(AttributeSafety::Normal), Safety::Default) => {
|
||||
(None | Some(AttributeSafety::Normal), Safety::Default) => {
|
||||
// OK
|
||||
}
|
||||
|
||||
// - Non-builtin attribute
|
||||
(None, Safety::Unsafe(_) | Safety::Default) => {
|
||||
// OK (not checked here)
|
||||
}
|
||||
|
||||
(
|
||||
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
|
||||
Safety::Safe(..),
|
||||
|
||||
@@ -3087,6 +3087,39 @@ fn report_local_value_does_not_live_long_enough(
|
||||
});
|
||||
|
||||
explanation.add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None);
|
||||
|
||||
// Detect buffer reuse pattern
|
||||
if let BorrowExplanation::UsedLater(_dropped_local, _, _, _) = explanation {
|
||||
// Check all locals at the borrow location to find Vec<&T> types
|
||||
for (local, local_decl) in self.body.local_decls.iter_enumerated() {
|
||||
if let ty::Adt(adt_def, args) = local_decl.ty.kind()
|
||||
&& self.infcx.tcx.is_diagnostic_item(sym::Vec, adt_def.did())
|
||||
&& args.len() > 0
|
||||
{
|
||||
let vec_inner_ty = args.type_at(0);
|
||||
// Check if Vec contains references
|
||||
if vec_inner_ty.is_ref() {
|
||||
let local_place = local.into();
|
||||
if let Some(local_name) = self.describe_place(local_place) {
|
||||
err.span_label(
|
||||
local_decl.source_info.span,
|
||||
format!("variable `{local_name}` declared here"),
|
||||
);
|
||||
err.note(
|
||||
format!(
|
||||
"`{local_name}` is a collection that stores borrowed references, \
|
||||
but {name} does not live long enough to be stored in it"
|
||||
)
|
||||
);
|
||||
err.help(
|
||||
"buffer reuse with borrowed references requires unsafe code or restructuring"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
|
||||
@@ -867,11 +867,12 @@ fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
|
||||
for (binding_span, opt_ref_pat) in finder.ref_pat_for_binding {
|
||||
if let Some(ref_pat) = opt_ref_pat
|
||||
&& !finder.cannot_remove.contains(&ref_pat.hir_id)
|
||||
&& let hir::PatKind::Ref(subpat, mutbl) = ref_pat.kind
|
||||
&& let hir::PatKind::Ref(subpat, pinned, mutbl) = ref_pat.kind
|
||||
&& let Some(ref_span) = ref_pat.span.trim_end(subpat.span)
|
||||
{
|
||||
let pinned_str = if pinned.is_pinned() { "pinned " } else { "" };
|
||||
let mutable_str = if mutbl.is_mut() { "mutable " } else { "" };
|
||||
let msg = format!("consider removing the {mutable_str}borrow");
|
||||
let msg = format!("consider removing the {pinned_str}{mutable_str}borrow");
|
||||
suggestions.push((ref_span, msg, "".to_string()));
|
||||
} else {
|
||||
let msg = "consider borrowing the pattern binding".to_string();
|
||||
|
||||
@@ -213,7 +213,7 @@ pub(crate) fn report_mutability_error(
|
||||
AccessKind::Mutate => {
|
||||
err = self.cannot_assign(span, &(item_msg + &reason));
|
||||
act = "assign";
|
||||
acted_on = "written";
|
||||
acted_on = "written to";
|
||||
span
|
||||
}
|
||||
AccessKind::MutableBorrow => {
|
||||
@@ -518,8 +518,8 @@ pub(crate) fn report_mutability_error(
|
||||
err.span_label(
|
||||
span,
|
||||
format!(
|
||||
"`{name}` is a `{pointer_sigil}` {pointer_desc}, \
|
||||
so the data it refers to cannot be {acted_on}",
|
||||
"`{name}` is a `{pointer_sigil}` {pointer_desc}, so it cannot be \
|
||||
{acted_on}",
|
||||
),
|
||||
);
|
||||
|
||||
@@ -542,7 +542,7 @@ pub(crate) fn report_mutability_error(
|
||||
self.expected_fn_found_fn_mut_call(&mut err, span, act);
|
||||
}
|
||||
|
||||
PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
|
||||
PlaceRef { local, projection: [.., ProjectionElem::Deref] } => {
|
||||
err.span_label(span, format!("cannot {act}"));
|
||||
|
||||
match opt_source {
|
||||
@@ -559,11 +559,36 @@ pub(crate) fn report_mutability_error(
|
||||
));
|
||||
self.suggest_map_index_mut_alternatives(ty, &mut err, span);
|
||||
}
|
||||
_ => (),
|
||||
_ => {
|
||||
let local = &self.body.local_decls[local];
|
||||
match local.local_info() {
|
||||
LocalInfo::StaticRef { def_id, .. } => {
|
||||
let span = self.infcx.tcx.def_span(def_id);
|
||||
err.span_label(span, format!("this `static` cannot be {acted_on}"));
|
||||
}
|
||||
LocalInfo::ConstRef { def_id } => {
|
||||
let span = self.infcx.tcx.def_span(def_id);
|
||||
err.span_label(span, format!("this `const` cannot be {acted_on}"));
|
||||
}
|
||||
LocalInfo::BlockTailTemp(_) | LocalInfo::Boring
|
||||
if !local.source_info.span.overlaps(span) =>
|
||||
{
|
||||
err.span_label(
|
||||
local.source_info.span,
|
||||
format!("this cannot be {acted_on}"),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
PlaceRef { local, .. } => {
|
||||
let local = &self.body.local_decls[local];
|
||||
if !local.source_info.span.overlaps(span) {
|
||||
err.span_label(local.source_info.span, format!("this cannot be {acted_on}"));
|
||||
}
|
||||
err.span_label(span, format!("cannot {act}"));
|
||||
}
|
||||
}
|
||||
@@ -772,11 +797,11 @@ fn construct_mut_suggestion_for_local_binding_patterns(
|
||||
&& let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(&body).break_value()
|
||||
&& let node = self.infcx.tcx.hir_node(hir_id)
|
||||
&& let hir::Node::LetStmt(hir::LetStmt {
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
|
||||
..
|
||||
})
|
||||
| hir::Node::Param(Param {
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
|
||||
..
|
||||
}) = node
|
||||
{
|
||||
@@ -1494,7 +1519,7 @@ fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result {
|
||||
}
|
||||
|
||||
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> Self::Result {
|
||||
if let hir::Pat { kind: hir::PatKind::Ref(_, _), span, .. } = param.pat
|
||||
if let hir::Pat { kind: hir::PatKind::Ref(_, _, _), span, .. } = param.pat
|
||||
&& *span == self.span
|
||||
{
|
||||
ControlFlow::Break(param.hir_id)
|
||||
|
||||
@@ -690,6 +690,17 @@ fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<
|
||||
);
|
||||
|
||||
diag.span_label(*span, format!("`{fr_name}` escapes the {escapes_from} body here"));
|
||||
} else {
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!("a temporary borrow escapes the {escapes_from} body here"),
|
||||
);
|
||||
if let Some((Some(outlived_name), _)) = outlived_fr_name_and_span {
|
||||
diag.help(format!(
|
||||
"`{outlived_name}` is declared outside the {escapes_from}, \
|
||||
so any data borrowed inside the {escapes_from} cannot be stored into it"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Only show an extra note if we can find an 'error region' for both of the region
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::{
|
||||
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, ShouldEmit, parse_cfg_select,
|
||||
};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
|
||||
use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectPredicate, parse_cfg_select};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
|
||||
use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
|
||||
@@ -9,11 +11,11 @@
|
||||
/// Selects the first arm whose predicate evaluates to true.
|
||||
fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
|
||||
for (cfg, tt, arm_span) in branches.reachable {
|
||||
if attr::cfg_matches(
|
||||
&cfg,
|
||||
if let EvalConfigResult::True = attr::eval_config_entry(
|
||||
&ecx.sess,
|
||||
&cfg,
|
||||
ecx.current_expansion.lint_node_id,
|
||||
Some(ecx.ecfg.features),
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
) {
|
||||
return Some((tt, arm_span));
|
||||
}
|
||||
@@ -27,37 +29,41 @@ pub(super) fn expand_cfg_select<'cx>(
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) {
|
||||
Ok(branches) => {
|
||||
if let Some((underscore, _, _)) = branches.wildcard {
|
||||
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
|
||||
for (predicate, _, _) in &branches.unreachable {
|
||||
let span = match predicate {
|
||||
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
|
||||
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
|
||||
};
|
||||
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
|
||||
ecx.dcx().emit_warn(err);
|
||||
ExpandResult::Ready(
|
||||
match parse_cfg_select(
|
||||
&mut ecx.new_parser_from_tts(tts),
|
||||
ecx.sess,
|
||||
Some(ecx.ecfg.features),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
) {
|
||||
Ok(branches) => {
|
||||
if let Some((underscore, _, _)) = branches.wildcard {
|
||||
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
|
||||
for (predicate, _, _) in &branches.unreachable {
|
||||
let span = match predicate {
|
||||
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
|
||||
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
|
||||
};
|
||||
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
|
||||
ecx.dcx().emit_warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((tts, arm_span)) = select_arm(ecx, branches) {
|
||||
return ExpandResult::from_tts(
|
||||
ecx,
|
||||
tts,
|
||||
sp,
|
||||
arm_span,
|
||||
Ident::with_dummy_span(sym::cfg_select),
|
||||
);
|
||||
} else {
|
||||
// Emit a compiler error when none of the predicates matched.
|
||||
let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((tts, arm_span)) = select_arm(ecx, branches) {
|
||||
return ExpandResult::from_tts(
|
||||
ecx,
|
||||
tts,
|
||||
sp,
|
||||
arm_span,
|
||||
Ident::with_dummy_span(sym::cfg_select),
|
||||
);
|
||||
} else {
|
||||
// Emit a compiler error when none of the predicates matched.
|
||||
let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let guar = err.emit();
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
})
|
||||
Err(guar) => DummyResult::any(sp, guar),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustc_ast::MetaItem;
|
||||
use rustc_ast::{MetaItem, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
@@ -24,6 +24,8 @@ pub(crate) fn expand_deriving_copy(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
trait_def.expand(cx, mitem, item, push);
|
||||
@@ -48,6 +50,8 @@ pub(crate) fn expand_deriving_const_param_ty(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
trait_def.expand(cx, mitem, item, push);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData};
|
||||
use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, Safety, VariantData};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::deriving::generic::ty::*;
|
||||
@@ -68,6 +68,29 @@ pub(crate) fn expand_deriving_clone(
|
||||
_ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
|
||||
}
|
||||
|
||||
// If the clone method is just copying the value, also mark the type as
|
||||
// `TrivialClone` to allow some library optimizations.
|
||||
if is_simple {
|
||||
let trivial_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(clone::TrivialClone),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: bounds.clone(),
|
||||
supports_unions: true,
|
||||
methods: Vec::new(),
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Unsafe(DUMMY_SP),
|
||||
// `TrivialClone` is not part of an API guarantee, so it shouldn't
|
||||
// appear in rustdoc output.
|
||||
document: false,
|
||||
};
|
||||
|
||||
trivial_def.expand_ext(cx, mitem, item, push, true);
|
||||
}
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(clone::Clone),
|
||||
@@ -88,6 +111,8 @@ pub(crate) fn expand_deriving_clone(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
trait_def.expand_ext(cx, mitem, item, push, is_simple)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustc_ast::{self as ast, MetaItem};
|
||||
use rustc_ast::{self as ast, MetaItem, Safety};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Span, sym};
|
||||
@@ -44,6 +44,8 @@ pub(crate) fn expand_deriving_eq(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
trait_def.expand_ext(cx, mitem, item, push, true)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustc_ast::MetaItem;
|
||||
use rustc_ast::{MetaItem, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use thin_vec::thin_vec;
|
||||
@@ -35,6 +35,8 @@ pub(crate) fn expand_deriving_ord(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability};
|
||||
use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Span, sym};
|
||||
use thin_vec::thin_vec;
|
||||
@@ -30,6 +30,8 @@ pub(crate) fn expand_deriving_partial_eq(
|
||||
associated_types: Vec::new(),
|
||||
is_const: false,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
structural_trait_def.expand(cx, mitem, item, push);
|
||||
|
||||
@@ -59,6 +61,8 @@ pub(crate) fn expand_deriving_partial_eq(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind};
|
||||
use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use thin_vec::thin_vec;
|
||||
@@ -65,6 +65,8 @@ pub(crate) fn expand_deriving_partial_ord(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustc_ast::{self as ast, EnumDef, MetaItem};
|
||||
use rustc_ast::{self as ast, EnumDef, MetaItem, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_session::config::FmtDebug;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
@@ -42,6 +42,8 @@ pub(crate) fn expand_deriving_debug(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::visit_opt;
|
||||
use rustc_ast::{EnumDef, VariantData, attr};
|
||||
use rustc_ast::{self as ast, EnumDef, Safety, VariantData, attr};
|
||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym};
|
||||
use smallvec::SmallVec;
|
||||
@@ -52,6 +51,8 @@ pub(crate) fn expand_deriving_default(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{ItemKind, VariantData};
|
||||
use rustc_ast::{ItemKind, Safety, VariantData};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
@@ -127,6 +127,8 @@ pub(crate) fn expand_deriving_from(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
from_trait_def.expand(cx, mitem, annotatable, push);
|
||||
|
||||
@@ -225,6 +225,12 @@ pub(crate) struct TraitDef<'a> {
|
||||
pub is_const: bool,
|
||||
|
||||
pub is_staged_api_crate: bool,
|
||||
|
||||
/// The safety of the `impl`.
|
||||
pub safety: Safety,
|
||||
|
||||
/// Whether the added `impl` should appear in rustdoc output.
|
||||
pub document: bool,
|
||||
}
|
||||
|
||||
pub(crate) struct MethodDef<'a> {
|
||||
@@ -826,13 +832,17 @@ fn create_derived_impl(
|
||||
)
|
||||
}
|
||||
|
||||
if !self.document {
|
||||
attrs.push(cx.attr_nested_word(sym::doc, sym::hidden, self.span));
|
||||
}
|
||||
|
||||
cx.item(
|
||||
self.span,
|
||||
attrs,
|
||||
ast::ItemKind::Impl(ast::Impl {
|
||||
generics: trait_generics,
|
||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||
safety: ast::Safety::Default,
|
||||
safety: self.safety,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: if self.is_const {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustc_ast::{MetaItem, Mutability};
|
||||
use rustc_ast::{MetaItem, Mutability, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Span, sym};
|
||||
use thin_vec::thin_vec;
|
||||
@@ -42,6 +42,8 @@ pub(crate) fn expand_deriving_hash(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
hash_trait_def.expand(cx, mitem, item, push);
|
||||
|
||||
@@ -916,8 +916,8 @@ pub(crate) fn codegen_call_with_unwind_action(
|
||||
pub(crate) fn lib_call_arg_param(tcx: TyCtxt<'_>, ty: Type, is_signed: bool) -> AbiParam {
|
||||
let param = AbiParam::new(ty);
|
||||
if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size().bits() {
|
||||
match (&tcx.sess.target.arch, tcx.sess.target.vendor.as_ref()) {
|
||||
(Arch::X86_64, _) | (Arch::AArch64, "apple") => match (ty, is_signed) {
|
||||
match (&tcx.sess.target.arch, tcx.sess.target.is_like_darwin) {
|
||||
(Arch::X86_64, _) | (Arch::AArch64, true) => match (ty, is_signed) {
|
||||
(types::I8 | types::I16, true) => param.sext(),
|
||||
(types::I8 | types::I16, false) => param.uext(),
|
||||
_ => param,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
pub(crate) fn f16_to_f32(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value {
|
||||
let (value, arg_ty) =
|
||||
if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 {
|
||||
if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 {
|
||||
(
|
||||
fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value),
|
||||
lib_call_arg_param(fx.tcx, types::I16, false),
|
||||
@@ -22,8 +22,7 @@ fn f16_to_f64(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value {
|
||||
}
|
||||
|
||||
pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value {
|
||||
let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64
|
||||
{
|
||||
let ret_ty = if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 {
|
||||
types::I16
|
||||
} else {
|
||||
types::F16
|
||||
@@ -38,8 +37,7 @@ pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value
|
||||
}
|
||||
|
||||
fn f64_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value {
|
||||
let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64
|
||||
{
|
||||
let ret_ty = if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 {
|
||||
types::I16
|
||||
} else {
|
||||
types::F16
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::OutputFilenames;
|
||||
use rustc_span::{Symbol, sym};
|
||||
use rustc_target::spec::Arch;
|
||||
use rustc_target::spec::{Abi, Arch, Env, Os};
|
||||
|
||||
pub use crate::config::*;
|
||||
use crate::prelude::*;
|
||||
@@ -163,15 +163,15 @@ fn init(&self, sess: &Session) {
|
||||
fn target_config(&self, sess: &Session) -> TargetConfig {
|
||||
// FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
|
||||
let target_features = match sess.target.arch {
|
||||
Arch::X86_64 if sess.target.os != "none" => {
|
||||
Arch::X86_64 if sess.target.os != Os::None => {
|
||||
// x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled
|
||||
vec![sym::fxsr, sym::sse, sym::sse2, Symbol::intern("x87")]
|
||||
}
|
||||
Arch::AArch64 => match &*sess.target.os {
|
||||
"none" => vec![],
|
||||
Arch::AArch64 => match &sess.target.os {
|
||||
Os::None => vec![],
|
||||
// On macOS the aes, sha2 and sha3 features are enabled by default and ring
|
||||
// fails to compile on macOS when they are not present.
|
||||
"macos" => vec![sym::neon, sym::aes, sym::sha2, sym::sha3],
|
||||
Os::MacOs => vec![sym::neon, sym::aes, sym::sha2, sym::sha3],
|
||||
// AArch64 mandates Neon support
|
||||
_ => vec![sym::neon],
|
||||
},
|
||||
@@ -184,9 +184,9 @@ fn target_config(&self, sess: &Session) -> TargetConfig {
|
||||
// targets due to GCC using a different ABI than LLVM. Therefore `f16` and `f128`
|
||||
// won't be available when using a LLVM-built sysroot.
|
||||
let has_reliable_f16_f128 = !(sess.target.arch == Arch::X86_64
|
||||
&& sess.target.os == "windows"
|
||||
&& sess.target.env == "gnu"
|
||||
&& sess.target.abi != "llvm");
|
||||
&& sess.target.os == Os::Windows
|
||||
&& sess.target.env == Env::Gnu
|
||||
&& sess.target.abi != Abi::Llvm);
|
||||
|
||||
TargetConfig {
|
||||
target_features,
|
||||
|
||||
+19
-9
@@ -62,7 +62,7 @@ jobs:
|
||||
- name: Build
|
||||
run: |
|
||||
./y.sh prepare --only-libcore
|
||||
EMBED_LTO_BITCODE=1 ./y.sh build --sysroot --release --release-sysroot
|
||||
./y.sh build --sysroot --release --release-sysroot
|
||||
./y.sh test --cargo-tests
|
||||
./y.sh clean all
|
||||
|
||||
@@ -72,19 +72,14 @@ jobs:
|
||||
git config --global user.name "User"
|
||||
./y.sh prepare
|
||||
|
||||
- name: Add more failing tests because of undefined symbol errors (FIXME)
|
||||
run: cat tests/failing-lto-tests.txt >> tests/failing-ui-tests.txt
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
# FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros.
|
||||
# FIXME(antoyo): this should probably not be needed since we embed the LTO bitcode.
|
||||
printf '[profile.release]\nlto = "fat"\n' >> build/build_sysroot/sysroot_src/library/Cargo.toml
|
||||
EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot --keep-lto-tests ${{ matrix.commands }}
|
||||
CG_RUSTFLAGS="-Cembed-bitcode=yes" ./y.sh test --release --clean --release-sysroot --build-sysroot --keep-lto-tests ${{ matrix.commands }}
|
||||
|
||||
- name: Run y.sh cargo build
|
||||
- name: LTO test
|
||||
run: |
|
||||
EMBED_LTO_BITCODE=1 CHANNEL="release" ./y.sh cargo build --release --manifest-path tests/hello-world/Cargo.toml
|
||||
CHANNEL="release" ./y.sh cargo build --release --manifest-path tests/hello-world/Cargo.toml
|
||||
call_found=$(objdump -dj .text tests/hello-world/target/release/hello_world | grep -c "call .*mylib.*my_func" ) ||:
|
||||
if [ $call_found -gt 0 ]; then
|
||||
echo "ERROR: call my_func found in asm"
|
||||
@@ -92,6 +87,21 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Cross-language LTO test
|
||||
run: |
|
||||
pushd tests/cross_lang_lto
|
||||
gcc -c -flto add.c -masm=intel -fPIC -O3
|
||||
ar rcs libadd.a add.o
|
||||
popd
|
||||
|
||||
CHANNEL="release" CG_RUSTFLAGS="-L native=. -Clinker-plugin-lto -Clinker=gcc" ./y.sh cargo build --release --manifest-path tests/cross_lang_lto/Cargo.toml
|
||||
call_found=$(objdump -dj .text tests/cross_lang_lto/target/release/cross_lang_lto | grep -c "call .*my_add" ) ||:
|
||||
if [ $call_found -gt 0 ]; then
|
||||
echo "ERROR: call my_add found in asm"
|
||||
echo "Test is done with cross-language LTO enabled, hence inlining should occur across object files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Summary job for the merge queue.
|
||||
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
|
||||
success_release:
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
# TODO: remove when we have binutils version 2.43 in the repo.
|
||||
- name: Install more recent binutils
|
||||
run: |
|
||||
echo "deb http://archive.ubuntu.com/ubuntu oracular main universe" | sudo tee /etc/apt/sources.list.d/oracular-copies.list
|
||||
echo "deb http://archive.ubuntu.com/ubuntu plucky main universe" | sudo tee /etc/apt/sources.list.d/plucky-copies.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install binutils
|
||||
|
||||
|
||||
@@ -56,18 +56,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gccjit"
|
||||
version = "2.9.0"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a0e310ef75f396cd11b2443b353d55376656ca92c13cba36f92b7aff346ac1a"
|
||||
checksum = "60362e038e71e4bdc1a5b23fb45e1aba587b5947fe0db58f4871d95608f89eca"
|
||||
dependencies = [
|
||||
"gccjit_sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gccjit_sys"
|
||||
version = "0.8.2"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95ed7572b30cd32430294dde6fb70822d58e67c6846a548647e8739776a0125b"
|
||||
checksum = "ddd542c8414e122217551c6af6b7d33acf51a227aee85276f218c087525e01bb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -24,7 +24,7 @@ default = ["master"]
|
||||
[dependencies]
|
||||
object = { version = "0.37.0", default-features = false, features = ["std", "read"] }
|
||||
tempfile = "3.20"
|
||||
gccjit = "2.8"
|
||||
gccjit = "2.10"
|
||||
#gccjit = { git = "https://github.com/rust-lang/gccjit.rs" }
|
||||
|
||||
# Local copy.
|
||||
|
||||
@@ -70,11 +70,17 @@ $ ../gcc/configure \
|
||||
$ make -j4 # You can replace `4` with another number depending on how many cores you have.
|
||||
```
|
||||
|
||||
If you want to run libgccjit tests, you will need to also enable the C++ language in the `configure`:
|
||||
If you want to run libgccjit tests, you will need to
|
||||
* Enable the C++ language in the `configure` step:
|
||||
|
||||
```bash
|
||||
--enable-languages=jit,c++
|
||||
```
|
||||
* Install [dejagnu](https://www.gnu.org/software/dejagnu/#downloading) to run the tests:
|
||||
|
||||
```bash
|
||||
$ sudo apt install dejagnu
|
||||
```
|
||||
|
||||
Then to run libgccjit tests:
|
||||
|
||||
@@ -135,16 +141,6 @@ $ CHANNEL="release" $CG_GCCJIT_DIR/y.sh cargo run
|
||||
|
||||
If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./y.sh test`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely.
|
||||
|
||||
### LTO
|
||||
|
||||
To use LTO, you need to set the variable `EMBED_LTO_BITCODE=1` in addition to setting `lto = "fat"` in the `Cargo.toml`.
|
||||
|
||||
Failing to set `EMBED_LTO_BITCODE` will give you the following error:
|
||||
|
||||
```
|
||||
error: failed to copy bitcode to object file: No such file or directory (os error 2)
|
||||
```
|
||||
|
||||
### Rustc
|
||||
|
||||
If you want to run `rustc` directly, you can do so with:
|
||||
|
||||
@@ -149,6 +149,9 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
|
||||
|
||||
// Copy files to sysroot
|
||||
let sysroot_path = start_dir.join(format!("sysroot/lib/rustlib/{}/lib/", config.target_triple));
|
||||
// To avoid errors like "multiple candidates for `rmeta` dependency `core` found", we clean the
|
||||
// sysroot directory before copying the sysroot build artifacts.
|
||||
let _ = fs::remove_dir_all(&sysroot_path);
|
||||
create_dir(&sysroot_path)?;
|
||||
let mut copier = |dir_to_copy: &Path| {
|
||||
// FIXME: should not use shell command!
|
||||
|
||||
@@ -69,8 +69,13 @@ fn clean_all() -> Result<(), String> {
|
||||
}
|
||||
|
||||
fn clean_ui_tests() -> Result<(), String> {
|
||||
let path = Path::new(crate::BUILD_DIR).join("rust/build/x86_64-unknown-linux-gnu/test/ui/");
|
||||
run_command(&[&"find", &path, &"-name", &"stamp", &"-delete"], None)?;
|
||||
let directories = ["run-make", "run-make-cargo", "ui"];
|
||||
for directory in directories {
|
||||
let path = Path::new(crate::BUILD_DIR)
|
||||
.join("rust/build/x86_64-unknown-linux-gnu/test/")
|
||||
.join(directory);
|
||||
run_command(&[&"find", &path, &"-name", &"stamp", &"-delete"], None)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Output;
|
||||
|
||||
use crate::rustc_info::get_rustc_path;
|
||||
use crate::utils::{
|
||||
@@ -7,6 +9,41 @@
|
||||
run_command_with_output, walk_dir,
|
||||
};
|
||||
|
||||
// This is needed on systems where nothing is configured.
|
||||
// git really needs something here, or it will fail.
|
||||
// Even using --author is not enough.
|
||||
const GIT_CMD: [&dyn AsRef<OsStr>; 9] = [
|
||||
&"git",
|
||||
&"-c",
|
||||
&"user.name=None",
|
||||
&"-c",
|
||||
&"user.email=none@example.com",
|
||||
&"-c",
|
||||
&"core.autocrlf=false",
|
||||
&"-c",
|
||||
&"commit.gpgSign=false",
|
||||
];
|
||||
|
||||
fn run_git_command(
|
||||
command: &dyn AsRef<OsStr>,
|
||||
input: &[&dyn AsRef<OsStr>],
|
||||
cwd: Option<&Path>,
|
||||
) -> Result<Output, String> {
|
||||
let git_cmd =
|
||||
&GIT_CMD.into_iter().chain([command]).chain(input.iter().cloned()).collect::<Vec<_>>()[..];
|
||||
run_command(git_cmd, cwd)
|
||||
}
|
||||
|
||||
fn run_git_command_with_output(
|
||||
command: &dyn AsRef<OsStr>,
|
||||
input: &[&dyn AsRef<OsStr>],
|
||||
cwd: Option<&Path>,
|
||||
) -> Result<(), String> {
|
||||
let git_cmd =
|
||||
&GIT_CMD.into_iter().chain([command]).chain(input.iter().cloned()).collect::<Vec<_>>()[..];
|
||||
run_command_with_output(git_cmd, cwd)
|
||||
}
|
||||
|
||||
fn prepare_libcore(
|
||||
sysroot_path: &Path,
|
||||
libgccjit12_patches: bool,
|
||||
@@ -55,19 +92,12 @@ fn prepare_libcore(
|
||||
run_command(&[&"cp", &"-r", &rustlib_dir.join("library"), &sysroot_dir], None)?;
|
||||
|
||||
println!("[GIT] init (cwd): `{}`", sysroot_dir.display());
|
||||
run_command(&[&"git", &"init"], Some(&sysroot_dir))?;
|
||||
run_git_command(&"init", &[], Some(&sysroot_dir))?;
|
||||
println!("[GIT] add (cwd): `{}`", sysroot_dir.display());
|
||||
run_command(&[&"git", &"add", &"."], Some(&sysroot_dir))?;
|
||||
run_git_command(&"add", &[&"."], Some(&sysroot_dir))?;
|
||||
println!("[GIT] commit (cwd): `{}`", sysroot_dir.display());
|
||||
|
||||
// This is needed on systems where nothing is configured.
|
||||
// git really needs something here, or it will fail.
|
||||
// Even using --author is not enough.
|
||||
run_command(&[&"git", &"config", &"user.email", &"none@example.com"], Some(&sysroot_dir))?;
|
||||
run_command(&[&"git", &"config", &"user.name", &"None"], Some(&sysroot_dir))?;
|
||||
run_command(&[&"git", &"config", &"core.autocrlf", &"false"], Some(&sysroot_dir))?;
|
||||
run_command(&[&"git", &"config", &"commit.gpgSign", &"false"], Some(&sysroot_dir))?;
|
||||
run_command(&[&"git", &"commit", &"-m", &"Initial commit", &"-q"], Some(&sysroot_dir))?;
|
||||
run_git_command(&"commit", &[&"-m", &"Initial commit", &"-q"], Some(&sysroot_dir))?;
|
||||
|
||||
let mut patches = Vec::new();
|
||||
walk_dir(
|
||||
@@ -105,10 +135,11 @@ fn prepare_libcore(
|
||||
for file_path in patches {
|
||||
println!("[GIT] apply `{}`", file_path.display());
|
||||
let path = Path::new("../../..").join(file_path);
|
||||
run_command_with_output(&[&"git", &"apply", &path], Some(&sysroot_dir))?;
|
||||
run_command_with_output(&[&"git", &"add", &"-A"], Some(&sysroot_dir))?;
|
||||
run_command_with_output(
|
||||
&[&"git", &"commit", &"--no-gpg-sign", &"-m", &format!("Patch {}", path.display())],
|
||||
run_git_command_with_output(&"apply", &[&path], Some(&sysroot_dir))?;
|
||||
run_git_command_with_output(&"add", &[&"-A"], Some(&sysroot_dir))?;
|
||||
run_git_command_with_output(
|
||||
&"commit",
|
||||
&[&"-m", &format!("Patch {}", path.display())],
|
||||
Some(&sysroot_dir),
|
||||
)?;
|
||||
}
|
||||
@@ -124,10 +155,11 @@ fn prepare_rand() -> Result<(), String> {
|
||||
let rand_dir = Path::new("build/rand");
|
||||
println!("[GIT] apply `{file_path}`");
|
||||
let path = Path::new("../..").join(file_path);
|
||||
run_command_with_output(&[&"git", &"apply", &path], Some(rand_dir))?;
|
||||
run_command_with_output(&[&"git", &"add", &"-A"], Some(rand_dir))?;
|
||||
run_command_with_output(
|
||||
&[&"git", &"commit", &"--no-gpg-sign", &"-m", &format!("Patch {}", path.display())],
|
||||
run_git_command_with_output(&"apply", &[&path], Some(rand_dir))?;
|
||||
run_git_command_with_output(&"add", &[&"-A"], Some(rand_dir))?;
|
||||
run_git_command_with_output(
|
||||
&"commit",
|
||||
&[&"-m", &format!("Patch {}", path.display())],
|
||||
Some(rand_dir),
|
||||
)?;
|
||||
|
||||
@@ -154,8 +186,8 @@ fn clone_and_setup<F>(repo_url: &str, checkout_commit: &str, extra: Option<F>) -
|
||||
println!("`{}` has already been cloned", clone_result.repo_name);
|
||||
}
|
||||
let repo_path = Path::new(crate::BUILD_DIR).join(&clone_result.repo_name);
|
||||
run_command(&[&"git", &"checkout", &"--", &"."], Some(&repo_path))?;
|
||||
run_command(&[&"git", &"checkout", &checkout_commit], Some(&repo_path))?;
|
||||
run_git_command(&"checkout", &[&"--", &"."], Some(&repo_path))?;
|
||||
run_git_command(&"checkout", &[&checkout_commit], Some(&repo_path))?;
|
||||
if let Some(extra) = extra {
|
||||
extra(&repo_path)?;
|
||||
}
|
||||
|
||||
@@ -910,6 +910,7 @@ fn test_rustc_inner<F>(
|
||||
prepare_files_callback: F,
|
||||
run_error_pattern_test: bool,
|
||||
test_type: &str,
|
||||
run_ignored_tests: bool,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
F: Fn(&Path) -> Result<bool, String>,
|
||||
@@ -944,17 +945,7 @@ fn test_rustc_inner<F>(
|
||||
rust_path.join("tests/ui"),
|
||||
&mut |dir| {
|
||||
let dir_name = dir.file_name().and_then(|name| name.to_str()).unwrap_or("");
|
||||
if [
|
||||
"abi",
|
||||
"extern",
|
||||
"unsized-locals",
|
||||
"proc-macro",
|
||||
"threads-sendsync",
|
||||
"borrowck",
|
||||
"test-attrs",
|
||||
]
|
||||
.contains(&dir_name)
|
||||
{
|
||||
if ["abi", "extern", "proc-macro", "threads-sendsync"].contains(&dir_name) {
|
||||
remove_dir_all(dir).map_err(|error| {
|
||||
format!("Failed to remove folder `{}`: {:?}", dir.display(), error)
|
||||
})?;
|
||||
@@ -1061,30 +1052,34 @@ fn file_handling(keep_lto_tests: bool) -> impl Fn(&Path) -> Result<(), String> {
|
||||
|
||||
env.get_mut("RUSTFLAGS").unwrap().clear();
|
||||
|
||||
run_command_with_output_and_env(
|
||||
&[
|
||||
&"./x.py",
|
||||
&"test",
|
||||
&"--run",
|
||||
&"always",
|
||||
&"--stage",
|
||||
&"0",
|
||||
&"--set",
|
||||
&"build.compiletest-allow-stage0=true",
|
||||
&format!("tests/{test_type}"),
|
||||
&"--compiletest-rustc-args",
|
||||
&rustc_args,
|
||||
],
|
||||
Some(&rust_path),
|
||||
Some(&env),
|
||||
)?;
|
||||
let test_dir = format!("tests/{test_type}");
|
||||
let mut command: Vec<&dyn AsRef<OsStr>> = vec![
|
||||
&"./x.py",
|
||||
&"test",
|
||||
&"--run",
|
||||
&"always",
|
||||
&"--stage",
|
||||
&"0",
|
||||
&"--set",
|
||||
&"build.compiletest-allow-stage0=true",
|
||||
&test_dir,
|
||||
&"--compiletest-rustc-args",
|
||||
&rustc_args,
|
||||
];
|
||||
|
||||
if run_ignored_tests {
|
||||
command.push(&"--");
|
||||
command.push(&"--ignored");
|
||||
}
|
||||
|
||||
run_command_with_output_and_env(&command, Some(&rust_path), Some(&env))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn test_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
test_rustc_inner(env, args, |_| Ok(false), false, "run-make")?;
|
||||
test_rustc_inner(env, args, |_| Ok(false), false, "run-make-cargo")?;
|
||||
test_rustc_inner(env, args, |_| Ok(false), false, "ui")
|
||||
test_rustc_inner(env, args, |_| Ok(false), false, "run-make", false)?;
|
||||
test_rustc_inner(env, args, |_| Ok(false), false, "run-make-cargo", false)?;
|
||||
test_rustc_inner(env, args, |_| Ok(false), false, "ui", false)
|
||||
}
|
||||
|
||||
fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
@@ -1094,6 +1089,7 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
retain_files_callback("tests/failing-run-make-tests.txt", "run-make"),
|
||||
false,
|
||||
"run-make",
|
||||
true,
|
||||
);
|
||||
|
||||
let run_make_cargo_result = test_rustc_inner(
|
||||
@@ -1102,6 +1098,7 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
retain_files_callback("tests/failing-run-make-tests.txt", "run-make-cargo"),
|
||||
false,
|
||||
"run-make",
|
||||
true,
|
||||
);
|
||||
|
||||
let ui_result = test_rustc_inner(
|
||||
@@ -1110,6 +1107,7 @@ fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
retain_files_callback("tests/failing-ui-tests.txt", "ui"),
|
||||
false,
|
||||
"ui",
|
||||
true,
|
||||
);
|
||||
|
||||
run_make_result.and(run_make_cargo_result).and(ui_result)
|
||||
@@ -1122,6 +1120,7 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
remove_files_callback("tests/failing-ui-tests.txt", "ui"),
|
||||
false,
|
||||
"ui",
|
||||
false,
|
||||
)?;
|
||||
test_rustc_inner(
|
||||
env,
|
||||
@@ -1129,6 +1128,7 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
remove_files_callback("tests/failing-run-make-tests.txt", "run-make"),
|
||||
false,
|
||||
"run-make",
|
||||
false,
|
||||
)?;
|
||||
test_rustc_inner(
|
||||
env,
|
||||
@@ -1136,6 +1136,7 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
remove_files_callback("tests/failing-run-make-tests.txt", "run-make-cargo"),
|
||||
false,
|
||||
"run-make-cargo",
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1146,6 +1147,7 @@ fn test_failing_ui_pattern_tests(env: &Env, args: &TestArg) -> Result<(), String
|
||||
remove_files_callback("tests/failing-ice-tests.txt", "ui"),
|
||||
true,
|
||||
"ui",
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -112,8 +112,7 @@ pub fn run_command_with_output(
|
||||
cwd: Option<&Path>,
|
||||
) -> Result<(), String> {
|
||||
let exit_status = exec_command(input, cwd, None)?;
|
||||
check_exit_status(input, cwd, exit_status, None, true)?;
|
||||
Ok(())
|
||||
check_exit_status(input, cwd, exit_status, None, true)
|
||||
}
|
||||
|
||||
pub fn run_command_with_output_and_env(
|
||||
@@ -122,8 +121,7 @@ pub fn run_command_with_output_and_env(
|
||||
env: Option<&HashMap<String, String>>,
|
||||
) -> Result<(), String> {
|
||||
let exit_status = exec_command(input, cwd, env)?;
|
||||
check_exit_status(input, cwd, exit_status, None, true)?;
|
||||
Ok(())
|
||||
check_exit_status(input, cwd, exit_status, None, true)
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
@@ -133,8 +131,7 @@ pub fn run_command_with_output_and_env_no_err(
|
||||
env: Option<&HashMap<String, String>>,
|
||||
) -> Result<(), String> {
|
||||
let exit_status = exec_command(input, cwd, env)?;
|
||||
check_exit_status(input, cwd, exit_status, None, false)?;
|
||||
Ok(())
|
||||
check_exit_status(input, cwd, exit_status, None, false)
|
||||
}
|
||||
|
||||
pub fn cargo_install(to_install: &str) -> Result<(), String> {
|
||||
|
||||
@@ -603,7 +603,7 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> fo
|
||||
impl<T> Box<T> {
|
||||
pub fn new(val: T) -> Box<T> {
|
||||
unsafe {
|
||||
let size = intrinsics::size_of::<T>();
|
||||
let size = size_of::<T>();
|
||||
let ptr = libc::malloc(size);
|
||||
intrinsics::copy(&val as *const T as *const u8, ptr, size);
|
||||
Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, Global)
|
||||
@@ -657,11 +657,11 @@ pub mod intrinsics {
|
||||
#[rustc_intrinsic]
|
||||
pub fn abort() -> !;
|
||||
#[rustc_intrinsic]
|
||||
pub fn size_of<T>() -> usize;
|
||||
pub const fn size_of<T>() -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub fn align_of<T>() -> usize;
|
||||
pub const fn align_of<T>() -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
@@ -671,7 +671,7 @@ pub mod intrinsics {
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn ctlz_nonzero<T>(x: T) -> u32;
|
||||
#[rustc_intrinsic]
|
||||
pub fn needs_drop<T: ?::Sized>() -> bool;
|
||||
pub const fn needs_drop<T: ?::Sized>() -> bool;
|
||||
#[rustc_intrinsic]
|
||||
pub fn bitreverse<T>(x: T) -> T;
|
||||
#[rustc_intrinsic]
|
||||
@@ -699,6 +699,24 @@ pub mod libc {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn size_of<T>() -> usize {
|
||||
<T as SizedTypeProperties>::SIZE
|
||||
}
|
||||
|
||||
pub const fn align_of<T>() -> usize {
|
||||
<T as SizedTypeProperties>::ALIGN
|
||||
}
|
||||
|
||||
trait SizedTypeProperties: Sized {
|
||||
#[lang = "mem_size_const"]
|
||||
const SIZE: usize = intrinsics::size_of::<Self>();
|
||||
|
||||
#[lang = "mem_align_const"]
|
||||
const ALIGN: usize = intrinsics::align_of::<Self>();
|
||||
}
|
||||
|
||||
impl<T> SizedTypeProperties for T {}
|
||||
|
||||
#[lang = "index"]
|
||||
pub trait Index<Idx: ?Sized> {
|
||||
type Output: ?Sized;
|
||||
|
||||
@@ -90,8 +90,8 @@ fn start<T: Termination + 'static>(
|
||||
) -> isize {
|
||||
if argc == 3 {
|
||||
unsafe { puts(*argv); }
|
||||
unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const u8)); }
|
||||
unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const u8)); }
|
||||
unsafe { puts(*((argv as usize + size_of::<*const u8>()) as *const *const u8)); }
|
||||
unsafe { puts(*((argv as usize + 2 * size_of::<*const u8>()) as *const *const u8)); }
|
||||
}
|
||||
|
||||
main().report();
|
||||
@@ -154,7 +154,7 @@ fn main() {
|
||||
let slice = &[0, 1] as &[i32];
|
||||
let slice_ptr = slice as *const [i32] as *const i32;
|
||||
|
||||
let align = intrinsics::align_of::<*const i32>();
|
||||
let align = align_of::<*const i32>();
|
||||
assert_eq!(slice_ptr as usize % align, 0);
|
||||
|
||||
//return;
|
||||
@@ -195,11 +195,9 @@ fn main() {
|
||||
assert_eq!(intrinsics::size_of_val(a) as u8, 8);
|
||||
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
|
||||
|
||||
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
|
||||
assert_eq!(align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::align_of_val(&a) as u8, align_of::<&str>() as u8);
|
||||
|
||||
/*
|
||||
* TODO: re-enable in the next sync.
|
||||
let u8_needs_drop = const { intrinsics::needs_drop::<u8>() };
|
||||
assert!(!u8_needs_drop);
|
||||
let slice_needs_drop = const { intrinsics::needs_drop::<[u8]>() };
|
||||
@@ -208,7 +206,6 @@ fn main() {
|
||||
assert!(noisy_drop);
|
||||
let noisy_unsized_drop = const { intrinsics::needs_drop::<NoisyDropUnsized>() };
|
||||
assert!(noisy_unsized_drop);
|
||||
*/
|
||||
|
||||
Unique {
|
||||
pointer: 0 as *const &str,
|
||||
|
||||
@@ -1 +1 @@
|
||||
4e995bd73c4490edfe5080ec6014d63aa9abed5f
|
||||
28b84db392ac0a572f1a2a2a1317aa5f2bc742cb
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2025-08-25"
|
||||
channel = "nightly-2025-11-04"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
||||
@@ -90,7 +90,7 @@ fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> {
|
||||
64 => cx.type_f64(),
|
||||
_ => bug!("unsupported float: {:?}", self),
|
||||
},
|
||||
RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()),
|
||||
RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use gccjit::{Context, OutputKind};
|
||||
use object::read::archive::ArchiveFile;
|
||||
@@ -39,7 +40,7 @@
|
||||
|
||||
use crate::back::write::save_temp_bitcode;
|
||||
use crate::errors::LtoBitcodeFromRlib;
|
||||
use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level};
|
||||
use crate::{GccCodegenBackend, GccContext, LTO_SUPPORTED, LtoMode, SyncContext, to_gcc_opt_level};
|
||||
|
||||
struct LtoData {
|
||||
// TODO(antoyo): use symbols_below_threshold.
|
||||
@@ -229,7 +230,7 @@ fn fat_lto(
|
||||
info!("linking {:?}", name);
|
||||
match bc_decoded {
|
||||
SerializedModule::Local(ref module_buffer) => {
|
||||
module.module_llvm.should_combine_object_files = true;
|
||||
module.module_llvm.lto_mode = LtoMode::Fat;
|
||||
module
|
||||
.module_llvm
|
||||
.context
|
||||
@@ -534,7 +535,7 @@ pub fn optimize_thin_module(
|
||||
// that LLVM Context and Module.
|
||||
//let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
|
||||
//let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &dcx)? as *const _;
|
||||
let mut should_combine_object_files = false;
|
||||
let mut lto_mode = LtoMode::None;
|
||||
let context = match thin_module.shared.thin_buffers.get(thin_module.idx) {
|
||||
Some(thin_buffer) => Arc::clone(&thin_buffer.context),
|
||||
None => {
|
||||
@@ -545,7 +546,7 @@ pub fn optimize_thin_module(
|
||||
SerializedModule::Local(ref module_buffer) => {
|
||||
let path = module_buffer.0.to_str().expect("path");
|
||||
context.add_driver_option(path);
|
||||
should_combine_object_files = true;
|
||||
lto_mode = LtoMode::Thin;
|
||||
/*module.module_llvm.should_combine_object_files = true;
|
||||
module
|
||||
.module_llvm
|
||||
@@ -560,11 +561,13 @@ pub fn optimize_thin_module(
|
||||
Arc::new(SyncContext::new(context))
|
||||
}
|
||||
};
|
||||
let lto_supported = LTO_SUPPORTED.load(Ordering::SeqCst);
|
||||
let module = ModuleCodegen::new_regular(
|
||||
thin_module.name().to_string(),
|
||||
GccContext {
|
||||
context,
|
||||
should_combine_object_files,
|
||||
lto_mode,
|
||||
lto_supported,
|
||||
// TODO(antoyo): use the correct relocation model here.
|
||||
relocation_model: RelocModel::Pic,
|
||||
temp_dir: None,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
use crate::base::add_pic_option;
|
||||
use crate::errors::CopyBitcode;
|
||||
use crate::{GccCodegenBackend, GccContext};
|
||||
use crate::{GccCodegenBackend, GccContext, LtoMode};
|
||||
|
||||
pub(crate) fn codegen(
|
||||
cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
@@ -25,12 +25,8 @@ pub(crate) fn codegen(
|
||||
{
|
||||
let context = &module.module_llvm.context;
|
||||
|
||||
let should_combine_object_files = module.module_llvm.should_combine_object_files;
|
||||
|
||||
// NOTE: Only generate object files with GIMPLE when this environment variable is set for
|
||||
// now because this requires a particular setup (same gcc/lto1/lto-wrapper commit as libgccjit).
|
||||
// TODO(antoyo): remove this environment variable.
|
||||
let fat_lto = env::var("EMBED_LTO_BITCODE").as_deref() == Ok("1");
|
||||
let lto_mode = module.module_llvm.lto_mode;
|
||||
let lto_supported = module.module_llvm.lto_supported;
|
||||
|
||||
let bc_out = cgcx.output_filenames.temp_path_for_cgu(
|
||||
OutputType::Bitcode,
|
||||
@@ -44,80 +40,46 @@ pub(crate) fn codegen(
|
||||
);
|
||||
|
||||
if config.bitcode_needed() {
|
||||
if fat_lto {
|
||||
let _timer = cgcx
|
||||
.prof
|
||||
.generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name);
|
||||
|
||||
// TODO(antoyo)
|
||||
/*if let Some(bitcode_filename) = bc_out.file_name() {
|
||||
cgcx.prof.artifact_size(
|
||||
"llvm_bitcode",
|
||||
bitcode_filename.to_string_lossy(),
|
||||
data.len() as u64,
|
||||
);
|
||||
}*/
|
||||
|
||||
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
|
||||
let _timer = cgcx
|
||||
.prof
|
||||
.generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name);
|
||||
|
||||
// TODO(antoyo)
|
||||
/*if let Some(bitcode_filename) = bc_out.file_name() {
|
||||
cgcx.prof.artifact_size(
|
||||
"llvm_bitcode",
|
||||
bitcode_filename.to_string_lossy(),
|
||||
data.len() as u64,
|
||||
);
|
||||
}*/
|
||||
|
||||
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg(
|
||||
"GCC_module_codegen_emit_bitcode",
|
||||
&*module.name,
|
||||
);
|
||||
.generic_activity_with_arg("GCC_module_codegen_emit_bitcode", &*module.name);
|
||||
if lto_supported {
|
||||
context.add_command_line_option("-flto=auto");
|
||||
context.add_command_line_option("-flto-partition=one");
|
||||
// TODO(antoyo): remove since we don't want fat objects when it is for Bitcode only.
|
||||
context.add_command_line_option("-ffat-lto-objects");
|
||||
context.compile_to_file(
|
||||
OutputKind::ObjectFile,
|
||||
bc_out.to_str().expect("path to str"),
|
||||
);
|
||||
}
|
||||
context
|
||||
.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
|
||||
}
|
||||
|
||||
if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg(
|
||||
"GCC_module_codegen_embed_bitcode",
|
||||
&*module.name,
|
||||
);
|
||||
if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
|
||||
let _timer = cgcx
|
||||
.prof
|
||||
.generic_activity_with_arg("GCC_module_codegen_embed_bitcode", &*module.name);
|
||||
if lto_supported {
|
||||
// TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
|
||||
//embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
|
||||
|
||||
context.add_command_line_option("-flto=auto");
|
||||
context.add_command_line_option("-flto-partition=one");
|
||||
context.add_command_line_option("-ffat-lto-objects");
|
||||
// TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
|
||||
context.compile_to_file(
|
||||
OutputKind::ObjectFile,
|
||||
bc_out.to_str().expect("path to str"),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg(
|
||||
"GCC_module_codegen_emit_bitcode",
|
||||
&*module.name,
|
||||
);
|
||||
context.compile_to_file(
|
||||
OutputKind::ObjectFile,
|
||||
bc_out.to_str().expect("path to str"),
|
||||
);
|
||||
}
|
||||
|
||||
if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
|
||||
// TODO(antoyo): we might want to emit to emit an error here, saying to set the
|
||||
// environment variable EMBED_LTO_BITCODE.
|
||||
let _timer = cgcx.prof.generic_activity_with_arg(
|
||||
"GCC_module_codegen_embed_bitcode",
|
||||
&*module.name,
|
||||
);
|
||||
// TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
|
||||
//embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
|
||||
|
||||
// TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
|
||||
context.compile_to_file(
|
||||
OutputKind::ObjectFile,
|
||||
bc_out.to_str().expect("path to str"),
|
||||
);
|
||||
}
|
||||
// TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
|
||||
context
|
||||
.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +128,10 @@ pub(crate) fn codegen(
|
||||
context.set_debug_info(true);
|
||||
context.dump_to_file(path, true);
|
||||
}
|
||||
if should_combine_object_files {
|
||||
if lto_mode != LtoMode::None {
|
||||
let fat_lto = lto_mode == LtoMode::Fat;
|
||||
// We need to check if we're doing LTO since this code is also used for the
|
||||
// dummy ThinLTO implementation to combine the object files.
|
||||
if fat_lto {
|
||||
context.add_command_line_option("-flto=auto");
|
||||
context.add_command_line_option("-flto-partition=one");
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::context::CodegenCx;
|
||||
use crate::{GccContext, LockedTargetInfo, SyncContext, gcc_util, new_context};
|
||||
use crate::{GccContext, LockedTargetInfo, LtoMode, SyncContext, gcc_util, new_context};
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
pub fn visibility_to_gcc(visibility: Visibility) -> gccjit::Visibility {
|
||||
@@ -74,6 +74,7 @@ pub fn compile_codegen_unit(
|
||||
tcx: TyCtxt<'_>,
|
||||
cgu_name: Symbol,
|
||||
target_info: LockedTargetInfo,
|
||||
lto_supported: bool,
|
||||
) -> (ModuleCodegen<GccContext>, u64) {
|
||||
let prof_timer = tcx.prof.generic_activity("codegen_module");
|
||||
let start_time = Instant::now();
|
||||
@@ -82,7 +83,7 @@ pub fn compile_codegen_unit(
|
||||
let (module, _) = tcx.dep_graph.with_task(
|
||||
dep_node,
|
||||
tcx,
|
||||
(cgu_name, target_info),
|
||||
(cgu_name, target_info, lto_supported),
|
||||
module_codegen,
|
||||
Some(dep_graph::hash_result),
|
||||
);
|
||||
@@ -95,7 +96,7 @@ pub fn compile_codegen_unit(
|
||||
|
||||
fn module_codegen(
|
||||
tcx: TyCtxt<'_>,
|
||||
(cgu_name, target_info): (Symbol, LockedTargetInfo),
|
||||
(cgu_name, target_info, lto_supported): (Symbol, LockedTargetInfo, bool),
|
||||
) -> ModuleCodegen<GccContext> {
|
||||
let cgu = tcx.codegen_unit(cgu_name);
|
||||
// Instantiate monomorphizations without filling out definitions yet...
|
||||
@@ -247,7 +248,8 @@ fn module_codegen(
|
||||
GccContext {
|
||||
context: Arc::new(SyncContext::new(context)),
|
||||
relocation_model: tcx.sess.relocation_model(),
|
||||
should_combine_object_files: false,
|
||||
lto_supported,
|
||||
lto_mode: LtoMode::None,
|
||||
temp_dir: None,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -668,32 +668,38 @@ fn unreachable(&mut self) {
|
||||
}
|
||||
|
||||
fn add(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.gcc_add(a, b)
|
||||
self.assign_to_var(self.gcc_add(a, b))
|
||||
}
|
||||
|
||||
fn fadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
a + b
|
||||
self.assign_to_var(a + b)
|
||||
}
|
||||
|
||||
// TODO(antoyo): should we also override the `unchecked_` versions?
|
||||
fn sub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.gcc_sub(a, b)
|
||||
self.assign_to_var(self.gcc_sub(a, b))
|
||||
}
|
||||
|
||||
fn fsub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
a - b
|
||||
self.assign_to_var(a - b)
|
||||
}
|
||||
|
||||
fn mul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.gcc_mul(a, b)
|
||||
self.assign_to_var(self.gcc_mul(a, b))
|
||||
}
|
||||
|
||||
fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.cx.context.new_binary_op(self.location, BinaryOp::Mult, a.get_type(), a, b)
|
||||
self.assign_to_var(self.cx.context.new_binary_op(
|
||||
self.location,
|
||||
BinaryOp::Mult,
|
||||
a.get_type(),
|
||||
a,
|
||||
b,
|
||||
))
|
||||
}
|
||||
|
||||
fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.gcc_udiv(a, b)
|
||||
self.assign_to_var(self.gcc_udiv(a, b))
|
||||
}
|
||||
|
||||
fn exactudiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
@@ -702,11 +708,11 @@ fn exactudiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let a = self.gcc_int_cast(a, a_type);
|
||||
let b_type = b.get_type().to_unsigned(self);
|
||||
let b = self.gcc_int_cast(b, b_type);
|
||||
self.gcc_udiv(a, b)
|
||||
self.assign_to_var(self.gcc_udiv(a, b))
|
||||
}
|
||||
|
||||
fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.gcc_sdiv(a, b)
|
||||
self.assign_to_var(self.gcc_sdiv(a, b))
|
||||
}
|
||||
|
||||
fn exactsdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
@@ -715,19 +721,19 @@ fn exactsdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// should be the same.
|
||||
let typ = a.get_type().to_signed(self);
|
||||
let b = self.gcc_int_cast(b, typ);
|
||||
self.gcc_sdiv(a, b)
|
||||
self.assign_to_var(self.gcc_sdiv(a, b))
|
||||
}
|
||||
|
||||
fn fdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
a / b
|
||||
self.assign_to_var(a / b)
|
||||
}
|
||||
|
||||
fn urem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.gcc_urem(a, b)
|
||||
self.assign_to_var(self.gcc_urem(a, b))
|
||||
}
|
||||
|
||||
fn srem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.gcc_srem(a, b)
|
||||
self.assign_to_var(self.gcc_srem(a, b))
|
||||
}
|
||||
|
||||
fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
@@ -865,22 +871,26 @@ fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
|
||||
|
||||
fn fadd_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// NOTE: it seems like we cannot enable fast-mode for a single operation in GCC.
|
||||
set_rvalue_location(self, lhs + rhs)
|
||||
let result = set_rvalue_location(self, lhs + rhs);
|
||||
self.assign_to_var(result)
|
||||
}
|
||||
|
||||
fn fsub_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// NOTE: it seems like we cannot enable fast-mode for a single operation in GCC.
|
||||
set_rvalue_location(self, lhs - rhs)
|
||||
let result = set_rvalue_location(self, lhs - rhs);
|
||||
self.assign_to_var(result)
|
||||
}
|
||||
|
||||
fn fmul_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// NOTE: it seems like we cannot enable fast-mode for a single operation in GCC.
|
||||
set_rvalue_location(self, lhs * rhs)
|
||||
let result = set_rvalue_location(self, lhs * rhs);
|
||||
self.assign_to_var(result)
|
||||
}
|
||||
|
||||
fn fdiv_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// NOTE: it seems like we cannot enable fast-mode for a single operation in GCC.
|
||||
set_rvalue_location(self, lhs / rhs)
|
||||
let result = set_rvalue_location(self, lhs / rhs);
|
||||
self.assign_to_var(result)
|
||||
}
|
||||
|
||||
fn frem_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
@@ -892,22 +902,22 @@ fn frem_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
|
||||
fn fadd_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// NOTE: it seems like we cannot enable fast-mode for a single operation in GCC.
|
||||
lhs + rhs
|
||||
self.assign_to_var(lhs + rhs)
|
||||
}
|
||||
|
||||
fn fsub_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// NOTE: it seems like we cannot enable fast-mode for a single operation in GCC.
|
||||
lhs - rhs
|
||||
self.assign_to_var(lhs - rhs)
|
||||
}
|
||||
|
||||
fn fmul_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// NOTE: it seems like we cannot enable fast-mode for a single operation in GCC.
|
||||
lhs * rhs
|
||||
self.assign_to_var(lhs * rhs)
|
||||
}
|
||||
|
||||
fn fdiv_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// NOTE: it seems like we cannot enable fast-mode for a single operation in GCC.
|
||||
lhs / rhs
|
||||
self.assign_to_var(lhs / rhs)
|
||||
}
|
||||
|
||||
fn frem_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
@@ -2409,6 +2419,15 @@ pub fn vector_select(
|
||||
let res = then_vals | else_vals;
|
||||
self.bitcast_if_needed(res, result_type)
|
||||
}
|
||||
|
||||
// GCC doesn't like deeply nested expressions.
|
||||
// By assigning intermediate expressions to a variable, this allow us to avoid deeply nested
|
||||
// expressions and GCC will use much less RAM.
|
||||
fn assign_to_var(&self, value: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let var = self.current_func().new_local(self.location, value.get_type(), "opResult");
|
||||
self.llbb().add_assignment(self.location, var, value);
|
||||
var.to_rvalue()
|
||||
}
|
||||
}
|
||||
|
||||
fn difference_or_zero<'gcc>(
|
||||
|
||||
@@ -83,12 +83,11 @@ pub fn gcc_lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let a_size = a_type.get_size();
|
||||
let b_size = b_type.get_size();
|
||||
match a_size.cmp(&b_size) {
|
||||
std::cmp::Ordering::Less => {
|
||||
let a = self.context.new_cast(self.location, a, b_type);
|
||||
a >> b
|
||||
}
|
||||
std::cmp::Ordering::Equal => a >> b,
|
||||
std::cmp::Ordering::Greater => {
|
||||
_ => {
|
||||
// NOTE: it is OK to cast even if b has a type bigger than a because b has
|
||||
// been masked by codegen_ssa before calling Builder::lshr or
|
||||
// Builder::ashr.
|
||||
let b = self.context.new_cast(self.location, b, a_type);
|
||||
a >> b
|
||||
}
|
||||
@@ -692,12 +691,10 @@ pub fn gcc_shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let a_size = a_type.get_size();
|
||||
let b_size = b_type.get_size();
|
||||
match a_size.cmp(&b_size) {
|
||||
std::cmp::Ordering::Less => {
|
||||
let a = self.context.new_cast(self.location, a, b_type);
|
||||
a << b
|
||||
}
|
||||
std::cmp::Ordering::Equal => a << b,
|
||||
std::cmp::Ordering::Greater => {
|
||||
_ => {
|
||||
// NOTE: it is OK to cast even if b has a type bigger than a because b has
|
||||
// been masked by codegen_ssa before calling Builder::shl.
|
||||
let b = self.context.new_cast(self.location, b, a_type);
|
||||
a << b
|
||||
}
|
||||
|
||||
@@ -85,12 +85,41 @@ fn aarch64(name: &str, full_name: &str) -> &'static str {
|
||||
fn amdgcn(name: &str, full_name: &str) -> &'static str {
|
||||
match name {
|
||||
// amdgcn
|
||||
"add.max.i32" => "__builtin_amdgcn_add_max_i32",
|
||||
"add.max.u32" => "__builtin_amdgcn_add_max_u32",
|
||||
"add.min.i32" => "__builtin_amdgcn_add_min_i32",
|
||||
"add.min.u32" => "__builtin_amdgcn_add_min_u32",
|
||||
"alignbyte" => "__builtin_amdgcn_alignbyte",
|
||||
"ashr.pk.i8.i32" => "__builtin_amdgcn_ashr_pk_i8_i32",
|
||||
"ashr.pk.u8.i32" => "__builtin_amdgcn_ashr_pk_u8_i32",
|
||||
"buffer.wbinvl1" => "__builtin_amdgcn_buffer_wbinvl1",
|
||||
"buffer.wbinvl1.sc" => "__builtin_amdgcn_buffer_wbinvl1_sc",
|
||||
"buffer.wbinvl1.vol" => "__builtin_amdgcn_buffer_wbinvl1_vol",
|
||||
"cluster.id.x" => "__builtin_amdgcn_cluster_id_x",
|
||||
"cluster.id.y" => "__builtin_amdgcn_cluster_id_y",
|
||||
"cluster.id.z" => "__builtin_amdgcn_cluster_id_z",
|
||||
"cluster.load.async.to.lds.b128" => {
|
||||
"__builtin_amdgcn_cluster_load_async_to_lds_b128"
|
||||
}
|
||||
"cluster.load.async.to.lds.b32" => {
|
||||
"__builtin_amdgcn_cluster_load_async_to_lds_b32"
|
||||
}
|
||||
"cluster.load.async.to.lds.b64" => {
|
||||
"__builtin_amdgcn_cluster_load_async_to_lds_b64"
|
||||
}
|
||||
"cluster.load.async.to.lds.b8" => {
|
||||
"__builtin_amdgcn_cluster_load_async_to_lds_b8"
|
||||
}
|
||||
"cluster.workgroup.flat.id" => "__builtin_amdgcn_cluster_workgroup_flat_id",
|
||||
"cluster.workgroup.id.x" => "__builtin_amdgcn_cluster_workgroup_id_x",
|
||||
"cluster.workgroup.id.y" => "__builtin_amdgcn_cluster_workgroup_id_y",
|
||||
"cluster.workgroup.id.z" => "__builtin_amdgcn_cluster_workgroup_id_z",
|
||||
"cluster.workgroup.max.flat.id" => {
|
||||
"__builtin_amdgcn_cluster_workgroup_max_flat_id"
|
||||
}
|
||||
"cluster.workgroup.max.id.x" => "__builtin_amdgcn_cluster_workgroup_max_id_x",
|
||||
"cluster.workgroup.max.id.y" => "__builtin_amdgcn_cluster_workgroup_max_id_y",
|
||||
"cluster.workgroup.max.id.z" => "__builtin_amdgcn_cluster_workgroup_max_id_z",
|
||||
"cubeid" => "__builtin_amdgcn_cubeid",
|
||||
"cubema" => "__builtin_amdgcn_cubema",
|
||||
"cubesc" => "__builtin_amdgcn_cubesc",
|
||||
@@ -101,18 +130,36 @@ fn amdgcn(name: &str, full_name: &str) -> &'static str {
|
||||
"cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8",
|
||||
"cvt.f32.fp8.e5m3" => "__builtin_amdgcn_cvt_f32_fp8_e5m3",
|
||||
"cvt.off.f32.i4" => "__builtin_amdgcn_cvt_off_f32_i4",
|
||||
"cvt.pk.bf8.f16" => "__builtin_amdgcn_cvt_pk_bf8_f16",
|
||||
"cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32",
|
||||
"cvt.pk.f16.bf8" => "__builtin_amdgcn_cvt_pk_f16_bf8",
|
||||
"cvt.pk.f16.fp8" => "__builtin_amdgcn_cvt_pk_f16_fp8",
|
||||
"cvt.pk.f32.bf8" => "__builtin_amdgcn_cvt_pk_f32_bf8",
|
||||
"cvt.pk.f32.fp8" => "__builtin_amdgcn_cvt_pk_f32_fp8",
|
||||
"cvt.pk.fp8.f16" => "__builtin_amdgcn_cvt_pk_fp8_f16",
|
||||
"cvt.pk.fp8.f32" => "__builtin_amdgcn_cvt_pk_fp8_f32",
|
||||
"cvt.pk.fp8.f32.e5m3" => "__builtin_amdgcn_cvt_pk_fp8_f32_e5m3",
|
||||
"cvt.pk.i16" => "__builtin_amdgcn_cvt_pk_i16",
|
||||
"cvt.pk.u16" => "__builtin_amdgcn_cvt_pk_u16",
|
||||
"cvt.pk.u8.f32" => "__builtin_amdgcn_cvt_pk_u8_f32",
|
||||
"cvt.pknorm.i16" => "__builtin_amdgcn_cvt_pknorm_i16",
|
||||
"cvt.pknorm.u16" => "__builtin_amdgcn_cvt_pknorm_u16",
|
||||
"cvt.pkrtz" => "__builtin_amdgcn_cvt_pkrtz",
|
||||
"cvt.scale.pk16.bf16.bf6" => "__builtin_amdgcn_cvt_scale_pk16_bf16_bf6",
|
||||
"cvt.scale.pk16.bf16.fp6" => "__builtin_amdgcn_cvt_scale_pk16_bf16_fp6",
|
||||
"cvt.scale.pk16.f16.bf6" => "__builtin_amdgcn_cvt_scale_pk16_f16_bf6",
|
||||
"cvt.scale.pk16.f16.fp6" => "__builtin_amdgcn_cvt_scale_pk16_f16_fp6",
|
||||
"cvt.scale.pk16.f32.bf6" => "__builtin_amdgcn_cvt_scale_pk16_f32_bf6",
|
||||
"cvt.scale.pk16.f32.fp6" => "__builtin_amdgcn_cvt_scale_pk16_f32_fp6",
|
||||
"cvt.scale.pk8.bf16.bf8" => "__builtin_amdgcn_cvt_scale_pk8_bf16_bf8",
|
||||
"cvt.scale.pk8.bf16.fp4" => "__builtin_amdgcn_cvt_scale_pk8_bf16_fp4",
|
||||
"cvt.scale.pk8.bf16.fp8" => "__builtin_amdgcn_cvt_scale_pk8_bf16_fp8",
|
||||
"cvt.scale.pk8.f16.bf8" => "__builtin_amdgcn_cvt_scale_pk8_f16_bf8",
|
||||
"cvt.scale.pk8.f16.fp4" => "__builtin_amdgcn_cvt_scale_pk8_f16_fp4",
|
||||
"cvt.scale.pk8.f16.fp8" => "__builtin_amdgcn_cvt_scale_pk8_f16_fp8",
|
||||
"cvt.scale.pk8.f32.bf8" => "__builtin_amdgcn_cvt_scale_pk8_f32_bf8",
|
||||
"cvt.scale.pk8.f32.fp4" => "__builtin_amdgcn_cvt_scale_pk8_f32_fp4",
|
||||
"cvt.scale.pk8.f32.fp8" => "__builtin_amdgcn_cvt_scale_pk8_f32_fp8",
|
||||
"cvt.scalef32.2xpk16.bf6.f32" => "__builtin_amdgcn_cvt_scalef32_2xpk16_bf6_f32",
|
||||
"cvt.scalef32.2xpk16.fp6.f32" => "__builtin_amdgcn_cvt_scalef32_2xpk16_fp6_f32",
|
||||
"cvt.scalef32.f16.bf8" => "__builtin_amdgcn_cvt_scalef32_f16_bf8",
|
||||
@@ -137,6 +184,12 @@ fn amdgcn(name: &str, full_name: &str) -> &'static str {
|
||||
"cvt.scalef32.pk.fp8.bf16" => "__builtin_amdgcn_cvt_scalef32_pk_fp8_bf16",
|
||||
"cvt.scalef32.pk.fp8.f16" => "__builtin_amdgcn_cvt_scalef32_pk_fp8_f16",
|
||||
"cvt.scalef32.pk.fp8.f32" => "__builtin_amdgcn_cvt_scalef32_pk_fp8_f32",
|
||||
"cvt.scalef32.pk16.bf6.bf16" => "__builtin_amdgcn_cvt_scalef32_pk16_bf6_bf16",
|
||||
"cvt.scalef32.pk16.bf6.f16" => "__builtin_amdgcn_cvt_scalef32_pk16_bf6_f16",
|
||||
"cvt.scalef32.pk16.bf6.f32" => "__builtin_amdgcn_cvt_scalef32_pk16_bf6_f32",
|
||||
"cvt.scalef32.pk16.fp6.bf16" => "__builtin_amdgcn_cvt_scalef32_pk16_fp6_bf16",
|
||||
"cvt.scalef32.pk16.fp6.f16" => "__builtin_amdgcn_cvt_scalef32_pk16_fp6_f16",
|
||||
"cvt.scalef32.pk16.fp6.f32" => "__builtin_amdgcn_cvt_scalef32_pk16_fp6_f32",
|
||||
"cvt.scalef32.pk32.bf16.bf6" => "__builtin_amdgcn_cvt_scalef32_pk32_bf16_bf6",
|
||||
"cvt.scalef32.pk32.bf16.fp6" => "__builtin_amdgcn_cvt_scalef32_pk32_bf16_fp6",
|
||||
"cvt.scalef32.pk32.bf6.bf16" => "__builtin_amdgcn_cvt_scalef32_pk32_bf6_bf16",
|
||||
@@ -147,6 +200,15 @@ fn amdgcn(name: &str, full_name: &str) -> &'static str {
|
||||
"cvt.scalef32.pk32.f32.fp6" => "__builtin_amdgcn_cvt_scalef32_pk32_f32_fp6",
|
||||
"cvt.scalef32.pk32.fp6.bf16" => "__builtin_amdgcn_cvt_scalef32_pk32_fp6_bf16",
|
||||
"cvt.scalef32.pk32.fp6.f16" => "__builtin_amdgcn_cvt_scalef32_pk32_fp6_f16",
|
||||
"cvt.scalef32.pk8.bf8.bf16" => "__builtin_amdgcn_cvt_scalef32_pk8_bf8_bf16",
|
||||
"cvt.scalef32.pk8.bf8.f16" => "__builtin_amdgcn_cvt_scalef32_pk8_bf8_f16",
|
||||
"cvt.scalef32.pk8.bf8.f32" => "__builtin_amdgcn_cvt_scalef32_pk8_bf8_f32",
|
||||
"cvt.scalef32.pk8.fp4.bf16" => "__builtin_amdgcn_cvt_scalef32_pk8_fp4_bf16",
|
||||
"cvt.scalef32.pk8.fp4.f16" => "__builtin_amdgcn_cvt_scalef32_pk8_fp4_f16",
|
||||
"cvt.scalef32.pk8.fp4.f32" => "__builtin_amdgcn_cvt_scalef32_pk8_fp4_f32",
|
||||
"cvt.scalef32.pk8.fp8.bf16" => "__builtin_amdgcn_cvt_scalef32_pk8_fp8_bf16",
|
||||
"cvt.scalef32.pk8.fp8.f16" => "__builtin_amdgcn_cvt_scalef32_pk8_fp8_f16",
|
||||
"cvt.scalef32.pk8.fp8.f32" => "__builtin_amdgcn_cvt_scalef32_pk8_fp8_f32",
|
||||
"cvt.scalef32.sr.bf8.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_bf8_bf16",
|
||||
"cvt.scalef32.sr.bf8.f16" => "__builtin_amdgcn_cvt_scalef32_sr_bf8_f16",
|
||||
"cvt.scalef32.sr.bf8.f32" => "__builtin_amdgcn_cvt_scalef32_sr_bf8_f32",
|
||||
@@ -156,6 +218,24 @@ fn amdgcn(name: &str, full_name: &str) -> &'static str {
|
||||
"cvt.scalef32.sr.pk.fp4.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_bf16",
|
||||
"cvt.scalef32.sr.pk.fp4.f16" => "__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_f16",
|
||||
"cvt.scalef32.sr.pk.fp4.f32" => "__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_f32",
|
||||
"cvt.scalef32.sr.pk16.bf6.bf16" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk16_bf6_bf16"
|
||||
}
|
||||
"cvt.scalef32.sr.pk16.bf6.f16" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk16_bf6_f16"
|
||||
}
|
||||
"cvt.scalef32.sr.pk16.bf6.f32" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk16_bf6_f32"
|
||||
}
|
||||
"cvt.scalef32.sr.pk16.fp6.bf16" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk16_fp6_bf16"
|
||||
}
|
||||
"cvt.scalef32.sr.pk16.fp6.f16" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk16_fp6_f16"
|
||||
}
|
||||
"cvt.scalef32.sr.pk16.fp6.f32" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk16_fp6_f32"
|
||||
}
|
||||
"cvt.scalef32.sr.pk32.bf6.bf16" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_bf16"
|
||||
}
|
||||
@@ -174,10 +254,30 @@ fn amdgcn(name: &str, full_name: &str) -> &'static str {
|
||||
"cvt.scalef32.sr.pk32.fp6.f32" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f32"
|
||||
}
|
||||
"cvt.scalef32.sr.pk8.bf8.bf16" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk8_bf8_bf16"
|
||||
}
|
||||
"cvt.scalef32.sr.pk8.bf8.f16" => "__builtin_amdgcn_cvt_scalef32_sr_pk8_bf8_f16",
|
||||
"cvt.scalef32.sr.pk8.bf8.f32" => "__builtin_amdgcn_cvt_scalef32_sr_pk8_bf8_f32",
|
||||
"cvt.scalef32.sr.pk8.fp4.bf16" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk8_fp4_bf16"
|
||||
}
|
||||
"cvt.scalef32.sr.pk8.fp4.f16" => "__builtin_amdgcn_cvt_scalef32_sr_pk8_fp4_f16",
|
||||
"cvt.scalef32.sr.pk8.fp4.f32" => "__builtin_amdgcn_cvt_scalef32_sr_pk8_fp4_f32",
|
||||
"cvt.scalef32.sr.pk8.fp8.bf16" => {
|
||||
"__builtin_amdgcn_cvt_scalef32_sr_pk8_fp8_bf16"
|
||||
}
|
||||
"cvt.scalef32.sr.pk8.fp8.f16" => "__builtin_amdgcn_cvt_scalef32_sr_pk8_fp8_f16",
|
||||
"cvt.scalef32.sr.pk8.fp8.f32" => "__builtin_amdgcn_cvt_scalef32_sr_pk8_fp8_f32",
|
||||
"cvt.sr.bf16.f32" => "__builtin_amdgcn_cvt_sr_bf16_f32",
|
||||
"cvt.sr.bf8.f16" => "__builtin_amdgcn_cvt_sr_bf8_f16",
|
||||
"cvt.sr.bf8.f32" => "__builtin_amdgcn_cvt_sr_bf8_f32",
|
||||
"cvt.sr.f16.f32" => "__builtin_amdgcn_cvt_sr_f16_f32",
|
||||
"cvt.sr.fp8.f16" => "__builtin_amdgcn_cvt_sr_fp8_f16",
|
||||
"cvt.sr.fp8.f32" => "__builtin_amdgcn_cvt_sr_fp8_f32",
|
||||
"cvt.sr.fp8.f32.e5m3" => "__builtin_amdgcn_cvt_sr_fp8_f32_e5m3",
|
||||
"cvt.sr.pk.bf16.f32" => "__builtin_amdgcn_cvt_sr_pk_bf16_f32",
|
||||
"cvt.sr.pk.f16.f32" => "__builtin_amdgcn_cvt_sr_pk_f16_f32",
|
||||
"dispatch.id" => "__builtin_amdgcn_dispatch_id",
|
||||
"dot4.f32.bf8.bf8" => "__builtin_amdgcn_dot4_f32_bf8_bf8",
|
||||
"dot4.f32.bf8.fp8" => "__builtin_amdgcn_dot4_f32_bf8_fp8",
|
||||
@@ -297,8 +397,20 @@ fn amdgcn(name: &str, full_name: &str) -> &'static str {
|
||||
"mqsad.u32.u8" => "__builtin_amdgcn_mqsad_u32_u8",
|
||||
"msad.u8" => "__builtin_amdgcn_msad_u8",
|
||||
"perm" => "__builtin_amdgcn_perm",
|
||||
"perm.pk16.b4.u4" => "__builtin_amdgcn_perm_pk16_b4_u4",
|
||||
"perm.pk16.b6.u4" => "__builtin_amdgcn_perm_pk16_b6_u4",
|
||||
"perm.pk16.b8.u4" => "__builtin_amdgcn_perm_pk16_b8_u4",
|
||||
"permlane.bcast" => "__builtin_amdgcn_permlane_bcast",
|
||||
"permlane.down" => "__builtin_amdgcn_permlane_down",
|
||||
"permlane.idx.gen" => "__builtin_amdgcn_permlane_idx_gen",
|
||||
"permlane.up" => "__builtin_amdgcn_permlane_up",
|
||||
"permlane.xor" => "__builtin_amdgcn_permlane_xor",
|
||||
"permlane16.var" => "__builtin_amdgcn_permlane16_var",
|
||||
"permlanex16.var" => "__builtin_amdgcn_permlanex16_var",
|
||||
"pk.add.max.i16" => "__builtin_amdgcn_pk_add_max_i16",
|
||||
"pk.add.max.u16" => "__builtin_amdgcn_pk_add_max_u16",
|
||||
"pk.add.min.i16" => "__builtin_amdgcn_pk_add_min_i16",
|
||||
"pk.add.min.u16" => "__builtin_amdgcn_pk_add_min_u16",
|
||||
"prng.b32" => "__builtin_amdgcn_prng_b32",
|
||||
"qsad.pk.u16.u8" => "__builtin_amdgcn_qsad_pk_u16_u8",
|
||||
"queue.ptr" => "__builtin_amdgcn_queue_ptr",
|
||||
@@ -306,11 +418,15 @@ fn amdgcn(name: &str, full_name: &str) -> &'static str {
|
||||
"rcp.legacy" => "__builtin_amdgcn_rcp_legacy",
|
||||
"rsq.legacy" => "__builtin_amdgcn_rsq_legacy",
|
||||
"s.barrier" => "__builtin_amdgcn_s_barrier",
|
||||
"s.barrier.init" => "__builtin_amdgcn_s_barrier_init",
|
||||
"s.barrier.join" => "__builtin_amdgcn_s_barrier_join",
|
||||
"s.barrier.leave" => "__builtin_amdgcn_s_barrier_leave",
|
||||
"s.barrier.signal" => "__builtin_amdgcn_s_barrier_signal",
|
||||
"s.barrier.signal.isfirst" => "__builtin_amdgcn_s_barrier_signal_isfirst",
|
||||
"s.barrier.signal.var" => "__builtin_amdgcn_s_barrier_signal_var",
|
||||
"s.barrier.wait" => "__builtin_amdgcn_s_barrier_wait",
|
||||
"s.buffer.prefetch.data" => "__builtin_amdgcn_s_buffer_prefetch_data",
|
||||
"s.cluster.barrier" => "__builtin_amdgcn_s_cluster_barrier",
|
||||
"s.dcache.inv" => "__builtin_amdgcn_s_dcache_inv",
|
||||
"s.dcache.inv.vol" => "__builtin_amdgcn_s_dcache_inv_vol",
|
||||
"s.dcache.wb" => "__builtin_amdgcn_s_dcache_wb",
|
||||
@@ -1900,6 +2016,8 @@ fn hexagon(name: &str, full_name: &str) -> &'static str {
|
||||
"V6.vfneg.hf.128B" => "__builtin_HEXAGON_V6_vfneg_hf_128B",
|
||||
"V6.vfneg.sf" => "__builtin_HEXAGON_V6_vfneg_sf",
|
||||
"V6.vfneg.sf.128B" => "__builtin_HEXAGON_V6_vfneg_sf_128B",
|
||||
"V6.vgather.vscattermh" => "__builtin_HEXAGON_V6_vgather_vscattermh",
|
||||
"V6.vgather.vscattermh.128B" => "__builtin_HEXAGON_V6_vgather_vscattermh_128B",
|
||||
"V6.vgathermh" => "__builtin_HEXAGON_V6_vgathermh",
|
||||
"V6.vgathermh.128B" => "__builtin_HEXAGON_V6_vgathermh_128B",
|
||||
"V6.vgathermhq" => "__builtin_HEXAGON_V6_vgathermhq",
|
||||
@@ -2382,6 +2500,8 @@ fn hexagon(name: &str, full_name: &str) -> &'static str {
|
||||
"V6.vsub.hf.f8.128B" => "__builtin_HEXAGON_V6_vsub_hf_f8_128B",
|
||||
"V6.vsub.hf.hf" => "__builtin_HEXAGON_V6_vsub_hf_hf",
|
||||
"V6.vsub.hf.hf.128B" => "__builtin_HEXAGON_V6_vsub_hf_hf_128B",
|
||||
"V6.vsub.hf.mix" => "__builtin_HEXAGON_V6_vsub_hf_mix",
|
||||
"V6.vsub.hf.mix.128B" => "__builtin_HEXAGON_V6_vsub_hf_mix_128B",
|
||||
"V6.vsub.qf16" => "__builtin_HEXAGON_V6_vsub_qf16",
|
||||
"V6.vsub.qf16.128B" => "__builtin_HEXAGON_V6_vsub_qf16_128B",
|
||||
"V6.vsub.qf16.mix" => "__builtin_HEXAGON_V6_vsub_qf16_mix",
|
||||
@@ -2396,6 +2516,8 @@ fn hexagon(name: &str, full_name: &str) -> &'static str {
|
||||
"V6.vsub.sf.bf.128B" => "__builtin_HEXAGON_V6_vsub_sf_bf_128B",
|
||||
"V6.vsub.sf.hf" => "__builtin_HEXAGON_V6_vsub_sf_hf",
|
||||
"V6.vsub.sf.hf.128B" => "__builtin_HEXAGON_V6_vsub_sf_hf_128B",
|
||||
"V6.vsub.sf.mix" => "__builtin_HEXAGON_V6_vsub_sf_mix",
|
||||
"V6.vsub.sf.mix.128B" => "__builtin_HEXAGON_V6_vsub_sf_mix_128B",
|
||||
"V6.vsub.sf.sf" => "__builtin_HEXAGON_V6_vsub_sf_sf",
|
||||
"V6.vsub.sf.sf.128B" => "__builtin_HEXAGON_V6_vsub_sf_sf_128B",
|
||||
"V6.vsubb" => "__builtin_HEXAGON_V6_vsubb",
|
||||
@@ -4883,6 +5005,26 @@ fn nvvm(name: &str, full_name: &str) -> &'static str {
|
||||
"f2ull.rp.ftz" => "__nvvm_f2ull_rp_ftz",
|
||||
"f2ull.rz" => "__nvvm_f2ull_rz",
|
||||
"f2ull.rz.ftz" => "__nvvm_f2ull_rz_ftz",
|
||||
"f32x4.to.e2m1x4.rs.relu.satfinite" => {
|
||||
"__nvvm_f32x4_to_e2m1x4_rs_relu_satfinite"
|
||||
}
|
||||
"f32x4.to.e2m1x4.rs.satfinite" => "__nvvm_f32x4_to_e2m1x4_rs_satfinite",
|
||||
"f32x4.to.e2m3x4.rs.relu.satfinite" => {
|
||||
"__nvvm_f32x4_to_e2m3x4_rs_relu_satfinite"
|
||||
}
|
||||
"f32x4.to.e2m3x4.rs.satfinite" => "__nvvm_f32x4_to_e2m3x4_rs_satfinite",
|
||||
"f32x4.to.e3m2x4.rs.relu.satfinite" => {
|
||||
"__nvvm_f32x4_to_e3m2x4_rs_relu_satfinite"
|
||||
}
|
||||
"f32x4.to.e3m2x4.rs.satfinite" => "__nvvm_f32x4_to_e3m2x4_rs_satfinite",
|
||||
"f32x4.to.e4m3x4.rs.relu.satfinite" => {
|
||||
"__nvvm_f32x4_to_e4m3x4_rs_relu_satfinite"
|
||||
}
|
||||
"f32x4.to.e4m3x4.rs.satfinite" => "__nvvm_f32x4_to_e4m3x4_rs_satfinite",
|
||||
"f32x4.to.e5m2x4.rs.relu.satfinite" => {
|
||||
"__nvvm_f32x4_to_e5m2x4_rs_relu_satfinite"
|
||||
}
|
||||
"f32x4.to.e5m2x4.rs.satfinite" => "__nvvm_f32x4_to_e5m2x4_rs_satfinite",
|
||||
"fabs.d" => "__nvvm_fabs_d",
|
||||
"fabs.f" => "__nvvm_fabs_f",
|
||||
"fabs.ftz.f" => "__nvvm_fabs_ftz_f",
|
||||
@@ -4902,10 +5044,18 @@ fn nvvm(name: &str, full_name: &str) -> &'static str {
|
||||
"ff.to.ue8m0x2.rz.satfinite" => "__nvvm_ff_to_ue8m0x2_rz_satfinite",
|
||||
"ff2bf16x2.rn" => "__nvvm_ff2bf16x2_rn",
|
||||
"ff2bf16x2.rn.relu" => "__nvvm_ff2bf16x2_rn_relu",
|
||||
"ff2bf16x2.rs" => "__nvvm_ff2bf16x2_rs",
|
||||
"ff2bf16x2.rs.relu" => "__nvvm_ff2bf16x2_rs_relu",
|
||||
"ff2bf16x2.rs.relu.satfinite" => "__nvvm_ff2bf16x2_rs_relu_satfinite",
|
||||
"ff2bf16x2.rs.satfinite" => "__nvvm_ff2bf16x2_rs_satfinite",
|
||||
"ff2bf16x2.rz" => "__nvvm_ff2bf16x2_rz",
|
||||
"ff2bf16x2.rz.relu" => "__nvvm_ff2bf16x2_rz_relu",
|
||||
"ff2f16x2.rn" => "__nvvm_ff2f16x2_rn",
|
||||
"ff2f16x2.rn.relu" => "__nvvm_ff2f16x2_rn_relu",
|
||||
"ff2f16x2.rs" => "__nvvm_ff2f16x2_rs",
|
||||
"ff2f16x2.rs.relu" => "__nvvm_ff2f16x2_rs_relu",
|
||||
"ff2f16x2.rs.relu.satfinite" => "__nvvm_ff2f16x2_rs_relu_satfinite",
|
||||
"ff2f16x2.rs.satfinite" => "__nvvm_ff2f16x2_rs_satfinite",
|
||||
"ff2f16x2.rz" => "__nvvm_ff2f16x2_rz",
|
||||
"ff2f16x2.rz.relu" => "__nvvm_ff2f16x2_rz_relu",
|
||||
"floor.d" => "__nvvm_floor_d",
|
||||
@@ -5129,6 +5279,7 @@ fn nvvm(name: &str, full_name: &str) -> &'static str {
|
||||
"read.ptx.sreg.envreg8" => "__nvvm_read_ptx_sreg_envreg8",
|
||||
"read.ptx.sreg.envreg9" => "__nvvm_read_ptx_sreg_envreg9",
|
||||
"read.ptx.sreg.globaltimer" => "__nvvm_read_ptx_sreg_globaltimer",
|
||||
"read.ptx.sreg.globaltimer.lo" => "__nvvm_read_ptx_sreg_globaltimer_lo",
|
||||
"read.ptx.sreg.gridid" => "__nvvm_read_ptx_sreg_gridid",
|
||||
// [DUPLICATE]: "read.ptx.sreg.gridid" => "__nvvm_read_ptx_sreg_",
|
||||
"read.ptx.sreg.laneid" => "__nvvm_read_ptx_sreg_laneid",
|
||||
@@ -5803,6 +5954,8 @@ fn ppc(name: &str, full_name: &str) -> &'static str {
|
||||
"altivec.vupklsw" => "__builtin_altivec_vupklsw",
|
||||
"bcdadd" => "__builtin_ppc_bcdadd",
|
||||
"bcdadd.p" => "__builtin_ppc_bcdadd_p",
|
||||
"bcdcopysign" => "__builtin_ppc_bcdcopysign",
|
||||
"bcdsetsign" => "__builtin_ppc_bcdsetsign",
|
||||
"bcdsub" => "__builtin_ppc_bcdsub",
|
||||
"bcdsub.p" => "__builtin_ppc_bcdsub_p",
|
||||
"bpermd" => "__builtin_bpermd",
|
||||
@@ -6160,6 +6313,9 @@ fn riscv(name: &str, full_name: &str) -> &'static str {
|
||||
"aes64im" => "__builtin_riscv_aes64im",
|
||||
"aes64ks1i" => "__builtin_riscv_aes64ks1i",
|
||||
"aes64ks2" => "__builtin_riscv_aes64ks2",
|
||||
"mips.ehb" => "__builtin_riscv_mips_ehb",
|
||||
"mips.ihb" => "__builtin_riscv_mips_ihb",
|
||||
"mips.pause" => "__builtin_riscv_mips_pause",
|
||||
"sha512sig0" => "__builtin_riscv_sha512sig0",
|
||||
"sha512sig0h" => "__builtin_riscv_sha512sig0h",
|
||||
"sha512sig0l" => "__builtin_riscv_sha512sig0l",
|
||||
|
||||
@@ -308,10 +308,6 @@ fn codegen_intrinsic_call(
|
||||
.or_else(|| get_simple_function_f128(self, name))
|
||||
.or_else(|| get_simple_function_f128_2args(self, name));
|
||||
|
||||
// FIXME(tempdragon): Re-enable `clippy::suspicious_else_formatting` if the following issue is solved:
|
||||
// https://github.com/rust-lang/rust-clippy/issues/12497
|
||||
// and leave `else if use_integer_compare` to be placed "as is".
|
||||
#[allow(clippy::suspicious_else_formatting)]
|
||||
let value = match name {
|
||||
_ if simple.is_some() => {
|
||||
let func = simple.expect("simple intrinsic function");
|
||||
|
||||
@@ -72,10 +72,7 @@
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
#[cfg(not(feature = "master"))]
|
||||
use std::sync::atomic::AtomicBool;
|
||||
#[cfg(not(feature = "master"))]
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use back::lto::{ThinBuffer, ThinData};
|
||||
@@ -167,8 +164,11 @@ fn supports_target_dependent_type(&self, typ: CType) -> bool {
|
||||
#[derive(Clone)]
|
||||
pub struct GccCodegenBackend {
|
||||
target_info: LockedTargetInfo,
|
||||
lto_supported: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
impl CodegenBackend for GccCodegenBackend {
|
||||
fn locale_resource(&self) -> &'static str {
|
||||
crate::DEFAULT_LOCALE_RESOURCE
|
||||
@@ -193,7 +193,13 @@ fn init(&self, _sess: &Session) {
|
||||
}
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
gccjit::set_global_personality_function_name(b"rust_eh_personality\0");
|
||||
{
|
||||
let lto_supported = gccjit::is_lto_supported();
|
||||
LTO_SUPPORTED.store(lto_supported, Ordering::SeqCst);
|
||||
self.lto_supported.store(lto_supported, Ordering::SeqCst);
|
||||
|
||||
gccjit::set_global_personality_function_name(b"rust_eh_personality\0");
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "master"))]
|
||||
{
|
||||
@@ -276,10 +282,12 @@ fn codegen_allocator(
|
||||
module_name: &str,
|
||||
methods: &[AllocatorMethod],
|
||||
) -> Self::Module {
|
||||
let lto_supported = self.lto_supported.load(Ordering::SeqCst);
|
||||
let mut mods = GccContext {
|
||||
context: Arc::new(SyncContext::new(new_context(tcx))),
|
||||
relocation_model: tcx.sess.relocation_model(),
|
||||
should_combine_object_files: false,
|
||||
lto_mode: LtoMode::None,
|
||||
lto_supported,
|
||||
temp_dir: None,
|
||||
};
|
||||
|
||||
@@ -294,7 +302,12 @@ fn compile_codegen_unit(
|
||||
tcx: TyCtxt<'_>,
|
||||
cgu_name: Symbol,
|
||||
) -> (ModuleCodegen<Self::Module>, u64) {
|
||||
base::compile_codegen_unit(tcx, cgu_name, self.target_info.clone())
|
||||
base::compile_codegen_unit(
|
||||
tcx,
|
||||
cgu_name,
|
||||
self.target_info.clone(),
|
||||
self.lto_supported.load(Ordering::SeqCst),
|
||||
)
|
||||
}
|
||||
|
||||
fn target_machine_factory(
|
||||
@@ -308,12 +321,20 @@ fn target_machine_factory(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum LtoMode {
|
||||
None,
|
||||
Thin,
|
||||
Fat,
|
||||
}
|
||||
|
||||
pub struct GccContext {
|
||||
context: Arc<SyncContext>,
|
||||
/// This field is needed in order to be able to set the flag -fPIC when necessary when doing
|
||||
/// LTO.
|
||||
relocation_model: RelocModel,
|
||||
should_combine_object_files: bool,
|
||||
lto_mode: LtoMode,
|
||||
lto_supported: bool,
|
||||
// Temporary directory used by LTO. We keep it here so that it's not removed before linking.
|
||||
temp_dir: Option<TempDir>,
|
||||
}
|
||||
@@ -425,7 +446,10 @@ pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
|
||||
supports_128bit_integers: AtomicBool::new(false),
|
||||
})));
|
||||
|
||||
Box::new(GccCodegenBackend { target_info: LockedTargetInfo { info } })
|
||||
Box::new(GccCodegenBackend {
|
||||
lto_supported: Arc::new(AtomicBool::new(false)),
|
||||
target_info: LockedTargetInfo { info },
|
||||
})
|
||||
}
|
||||
|
||||
fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "cross_lang_lto"
|
||||
version = "0.1.0"
|
||||
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "cross_lang_lto"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t my_add(uint32_t a, uint32_t b) {
|
||||
return a + b;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Compile the C code with:
|
||||
* gcc -c -flto add.c -ffat-lto-objects
|
||||
* ar rcs libadd.a add.o
|
||||
*
|
||||
* Compile the Rust code with:
|
||||
* CG_RUSTFLAGS="-L native=. -Clinker-plugin-lto -Clinker=gcc" y cargo run --release
|
||||
*/
|
||||
|
||||
#[link(name="add")]
|
||||
unsafe extern "C" {
|
||||
fn my_add(a: u32, b: u32) -> u32;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let res = unsafe { my_add(30, 12) };
|
||||
println!("{}", res);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
tests/ui/lint/unsafe_code/forge_unsafe_block.rs
|
||||
tests/ui/lint/unused-qualification-in-derive-expansion.rs
|
||||
tests/ui/macros/macro-quote-test.rs
|
||||
tests/ui/macros/proc_macro.rs
|
||||
tests/ui/panic-runtime/lto-unwind.rs
|
||||
tests/ui/resolve/derive-macro-1.rs
|
||||
tests/ui/resolve/derive-macro-2.rs
|
||||
tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-pretty.rs
|
||||
tests/ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs
|
||||
tests/ui/rfcs/rfc-3348-c-string-literals/edition-spans.rs
|
||||
tests/ui/rust-2018/suggestions-not-always-applicable.rs
|
||||
tests/ui/rust-2021/reserved-prefixes-via-macro.rs
|
||||
tests/ui/underscore-imports/duplicate.rs
|
||||
tests/ui/async-await/issues/issue-60674.rs
|
||||
tests/ui/attributes/main-removed-2/main.rs
|
||||
tests/ui/cfg/assume-incomplete-release/assume-incomplete.rs
|
||||
tests/ui/crate-loading/cross-compiled-proc-macro.rs
|
||||
tests/ui/derives/derive-marker-tricky.rs
|
||||
tests/ui/diagnostic_namespace/existing_proc_macros.rs
|
||||
tests/ui/fmt/format-args-capture-issue-106408.rs
|
||||
tests/ui/fmt/indoc-issue-106408.rs
|
||||
tests/ui/hygiene/issue-77523-def-site-async-await.rs
|
||||
tests/ui/inherent-impls-overlap-check/no-overlap.rs
|
||||
tests/ui/enum-discriminant/issue-46519.rs
|
||||
tests/ui/issues/issue-45731.rs
|
||||
tests/ui/lint/test-allow-dead-extern-static-no-warning.rs
|
||||
tests/ui/macros/macro-comma-behavior-rpass.rs
|
||||
tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs
|
||||
tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
|
||||
tests/ui/macros/stringify.rs
|
||||
tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test.rs
|
||||
tests/ui/binding/fn-arg-incomplete-pattern-drop-order.rs
|
||||
tests/ui/lto/debuginfo-lto-alloc.rs
|
||||
@@ -1,35 +1,11 @@
|
||||
tests/run-make/a-b-a-linker-guard/
|
||||
tests/run-make/CURRENT_RUSTC_VERSION/
|
||||
tests/run-make/cross-lang-lto/
|
||||
tests/run-make/cross-lang-lto-upstream-rlibs/
|
||||
tests/run-make/doctests-keep-binaries/
|
||||
tests/run-make/doctests-runtool/
|
||||
tests/run-make/emit-shared-files/
|
||||
tests/run-make/exit-code/
|
||||
tests/run-make/llvm-ident/
|
||||
tests/run-make/native-link-modifier-bundle/
|
||||
tests/run-make/remap-path-prefix-dwarf/
|
||||
tests/run-make/repr128-dwarf/
|
||||
tests/run-make/rlib-format-packed-bundled-libs/
|
||||
tests/run-make/rlib-format-packed-bundled-libs-2/
|
||||
tests/run-make/rustdoc-determinism/
|
||||
tests/run-make/rustdoc-error-lines/
|
||||
tests/run-make/rustdoc-map-file/
|
||||
tests/run-make/rustdoc-output-path/
|
||||
tests/run-make/rustdoc-scrape-examples-invalid-expr/
|
||||
tests/run-make/rustdoc-scrape-examples-multiple/
|
||||
tests/run-make/rustdoc-scrape-examples-ordering/
|
||||
tests/run-make/rustdoc-scrape-examples-remap/
|
||||
tests/run-make/rustdoc-scrape-examples-test/
|
||||
tests/run-make/rustdoc-scrape-examples-whitespace/
|
||||
tests/run-make/rustdoc-scrape-examples-macros/
|
||||
tests/run-make/rustdoc-with-out-dir-option/
|
||||
tests/run-make/rustdoc-verify-output-files/
|
||||
tests/run-make/rustdoc-themes/
|
||||
tests/run-make/rustdoc-with-short-out-dir-option/
|
||||
tests/run-make/rustdoc-with-output-option/
|
||||
tests/run-make/arguments-non-c-like-enum/
|
||||
tests/run-make/c-link-to-rust-staticlib/
|
||||
tests/run-make/foreign-double-unwind/
|
||||
tests/run-make/foreign-exceptions/
|
||||
tests/run-make/glibc-staticlib-args/
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
tests/ui/allocator/no_std-alloc-error-handler-custom.rs
|
||||
tests/ui/allocator/no_std-alloc-error-handler-default.rs
|
||||
tests/ui/asm/may_unwind.rs
|
||||
tests/ui/asm/x86_64/may_unwind.rs
|
||||
tests/ui/drop/dynamic-drop-async.rs
|
||||
@@ -17,7 +15,6 @@ tests/ui/panic-runtime/link-to-abort.rs
|
||||
tests/ui/parser/unclosed-delimiter-in-dep.rs
|
||||
tests/ui/consts/missing_span_in_backtrace.rs
|
||||
tests/ui/drop/dynamic-drop.rs
|
||||
tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs
|
||||
tests/ui/simd/issue-17170.rs
|
||||
tests/ui/simd/issue-39720.rs
|
||||
tests/ui/drop/panic-during-drop-14875.rs
|
||||
@@ -31,11 +28,9 @@ tests/ui/coroutine/resume-after-return.rs
|
||||
tests/ui/simd/masked-load-store.rs
|
||||
tests/ui/simd/repr_packed.rs
|
||||
tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
|
||||
tests/ui/consts/try-operator.rs
|
||||
tests/ui/coroutine/unwind-abort-mix.rs
|
||||
tests/ui/consts/issue-miri-1910.rs
|
||||
tests/ui/consts/const_cmp_type_id.rs
|
||||
tests/ui/consts/issue-73976-monomorphic.rs
|
||||
tests/ui/consts/issue-94675.rs
|
||||
tests/ui/traits/const-traits/const-drop-fail.rs
|
||||
tests/ui/runtime/on-broken-pipe/child-processes.rs
|
||||
@@ -53,7 +48,6 @@ tests/ui/sanitizer/cfi/virtual-auto.rs
|
||||
tests/ui/sanitizer/cfi/sized-associated-ty.rs
|
||||
tests/ui/sanitizer/cfi/can-reveal-opaques.rs
|
||||
tests/ui/sanitizer/kcfi-mangling.rs
|
||||
tests/ui/statics/const_generics.rs
|
||||
tests/ui/backtrace/dylib-dep.rs
|
||||
tests/ui/delegation/fn-header.rs
|
||||
tests/ui/consts/const-eval/parse_ints.rs
|
||||
@@ -74,13 +68,7 @@ tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs
|
||||
tests/ui/simd/simd-bitmask-notpow2.rs
|
||||
tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs
|
||||
tests/ui/numbers-arithmetic/u128-as-f32.rs
|
||||
tests/ui/lto/all-crates.rs
|
||||
tests/ui/uninhabited/uninhabited-transparent-return-abi.rs
|
||||
tests/ui/coroutine/panic-drops-resume.rs
|
||||
tests/ui/coroutine/panic-drops.rs
|
||||
tests/ui/coroutine/panic-safe.rs
|
||||
tests/ui/process/nofile-limit.rs
|
||||
tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
|
||||
tests/ui/linking/no-gc-encapsulation-symbols.rs
|
||||
tests/ui/panics/unwind-force-no-unwind-tables.rs
|
||||
tests/ui/attributes/fn-align-dyn.rs
|
||||
@@ -88,3 +76,4 @@ tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs
|
||||
tests/ui/explicit-tail-calls/recursion-etc.rs
|
||||
tests/ui/explicit-tail-calls/indexer.rs
|
||||
tests/ui/explicit-tail-calls/drop-order.rs
|
||||
tests/ui/c-variadic/valid.rs
|
||||
|
||||
@@ -683,7 +683,7 @@ fn handle_offload<'ll>(cx: &'ll SimpleCx<'_>, old_fn: &llvm::Value) {
|
||||
// Here we map the old arguments to the new arguments, with an offset of 1 to make sure
|
||||
// that we don't use the newly added `%dyn_ptr`.
|
||||
unsafe {
|
||||
llvm::LLVMRustOffloadMapper(cx.llmod(), old_fn, new_fn);
|
||||
llvm::LLVMRustOffloadMapper(old_fn, new_fn);
|
||||
}
|
||||
|
||||
llvm::set_linkage(new_fn, llvm::get_linkage(old_fn));
|
||||
|
||||
@@ -760,30 +760,18 @@ fn write_operand_repeatedly(
|
||||
count: u64,
|
||||
dest: PlaceRef<'tcx, &'ll Value>,
|
||||
) {
|
||||
let zero = self.const_usize(0);
|
||||
let count = self.const_usize(count);
|
||||
|
||||
let header_bb = self.append_sibling_block("repeat_loop_header");
|
||||
let body_bb = self.append_sibling_block("repeat_loop_body");
|
||||
let next_bb = self.append_sibling_block("repeat_loop_next");
|
||||
|
||||
self.br(header_bb);
|
||||
|
||||
let mut header_bx = Self::build(self.cx, header_bb);
|
||||
let i = header_bx.phi(self.val_ty(zero), &[zero], &[self.llbb()]);
|
||||
|
||||
let keep_going = header_bx.icmp(IntPredicate::IntULT, i, count);
|
||||
header_bx.cond_br(keep_going, body_bb, next_bb);
|
||||
|
||||
let mut body_bx = Self::build(self.cx, body_bb);
|
||||
let dest_elem = dest.project_index(&mut body_bx, i);
|
||||
cg_elem.val.store(&mut body_bx, dest_elem);
|
||||
|
||||
let next = body_bx.unchecked_uadd(i, self.const_usize(1));
|
||||
body_bx.br(header_bb);
|
||||
header_bx.add_incoming_to_phi(i, next, body_bb);
|
||||
|
||||
*self = Self::build(self.cx, next_bb);
|
||||
if self.cx.sess().opts.optimize == OptLevel::No {
|
||||
// To let debuggers single-step over lines like
|
||||
//
|
||||
// let foo = ["bar"; 42];
|
||||
//
|
||||
// we need the debugger-friendly LLVM IR that `_unoptimized()`
|
||||
// provides. The `_optimized()` version generates trickier LLVM IR.
|
||||
// See PR #148058 for a failed attempt at handling that.
|
||||
self.write_operand_repeatedly_unoptimized(cg_elem, count, dest);
|
||||
} else {
|
||||
self.write_operand_repeatedly_optimized(cg_elem, count, dest);
|
||||
}
|
||||
}
|
||||
|
||||
fn range_metadata(&mut self, load: &'ll Value, range: WrappingRange) {
|
||||
@@ -1514,6 +1502,78 @@ pub(crate) fn set_unpredictable(&mut self, inst: &'ll Value) {
|
||||
self.set_metadata_node(inst, llvm::MD_unpredictable, &[]);
|
||||
}
|
||||
|
||||
fn write_operand_repeatedly_optimized(
|
||||
&mut self,
|
||||
cg_elem: OperandRef<'tcx, &'ll Value>,
|
||||
count: u64,
|
||||
dest: PlaceRef<'tcx, &'ll Value>,
|
||||
) {
|
||||
let zero = self.const_usize(0);
|
||||
let count = self.const_usize(count);
|
||||
|
||||
let header_bb = self.append_sibling_block("repeat_loop_header");
|
||||
let body_bb = self.append_sibling_block("repeat_loop_body");
|
||||
let next_bb = self.append_sibling_block("repeat_loop_next");
|
||||
|
||||
self.br(header_bb);
|
||||
|
||||
let mut header_bx = Self::build(self.cx, header_bb);
|
||||
let i = header_bx.phi(self.val_ty(zero), &[zero], &[self.llbb()]);
|
||||
|
||||
let keep_going = header_bx.icmp(IntPredicate::IntULT, i, count);
|
||||
header_bx.cond_br(keep_going, body_bb, next_bb);
|
||||
|
||||
let mut body_bx = Self::build(self.cx, body_bb);
|
||||
let dest_elem = dest.project_index(&mut body_bx, i);
|
||||
cg_elem.val.store(&mut body_bx, dest_elem);
|
||||
|
||||
let next = body_bx.unchecked_uadd(i, self.const_usize(1));
|
||||
body_bx.br(header_bb);
|
||||
header_bx.add_incoming_to_phi(i, next, body_bb);
|
||||
|
||||
*self = Self::build(self.cx, next_bb);
|
||||
}
|
||||
|
||||
fn write_operand_repeatedly_unoptimized(
|
||||
&mut self,
|
||||
cg_elem: OperandRef<'tcx, &'ll Value>,
|
||||
count: u64,
|
||||
dest: PlaceRef<'tcx, &'ll Value>,
|
||||
) {
|
||||
let zero = self.const_usize(0);
|
||||
let count = self.const_usize(count);
|
||||
let start = dest.project_index(self, zero).val.llval;
|
||||
let end = dest.project_index(self, count).val.llval;
|
||||
|
||||
let header_bb = self.append_sibling_block("repeat_loop_header");
|
||||
let body_bb = self.append_sibling_block("repeat_loop_body");
|
||||
let next_bb = self.append_sibling_block("repeat_loop_next");
|
||||
|
||||
self.br(header_bb);
|
||||
|
||||
let mut header_bx = Self::build(self.cx, header_bb);
|
||||
let current = header_bx.phi(self.val_ty(start), &[start], &[self.llbb()]);
|
||||
|
||||
let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end);
|
||||
header_bx.cond_br(keep_going, body_bb, next_bb);
|
||||
|
||||
let mut body_bx = Self::build(self.cx, body_bb);
|
||||
let align = dest.val.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
|
||||
cg_elem
|
||||
.val
|
||||
.store(&mut body_bx, PlaceRef::new_sized_aligned(current, cg_elem.layout, align));
|
||||
|
||||
let next = body_bx.inbounds_gep(
|
||||
self.backend_type(cg_elem.layout),
|
||||
current,
|
||||
&[self.const_usize(1)],
|
||||
);
|
||||
body_bx.br(header_bb);
|
||||
header_bx.add_incoming_to_phi(current, next, body_bb);
|
||||
|
||||
*self = Self::build(self.cx, next_bb);
|
||||
}
|
||||
|
||||
pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
||||
self.call_intrinsic("llvm.minnum", &[self.val_ty(lhs)], &[lhs, rhs])
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use rustc_codegen_ssa::common;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv};
|
||||
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
||||
use rustc_target::spec::Arch;
|
||||
use rustc_target::spec::{Arch, Env};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::context::CodegenCx;
|
||||
@@ -145,7 +145,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
|
||||
if cx.use_dll_storage_attrs
|
||||
&& let Some(library) = tcx.native_library(instance_def_id)
|
||||
&& library.kind.is_dllimport()
|
||||
&& !matches!(tcx.sess.target.env.as_ref(), "gnu" | "uclibc")
|
||||
&& !matches!(tcx.sess.target.env, Env::Gnu | Env::Uclibc)
|
||||
{
|
||||
llvm::set_dllimport_storage_class(llfn);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::{
|
||||
Arch, HasTargetSpec, RelocModel, SmallDataThresholdSupport, Target, TlsModel,
|
||||
Abi, Arch, Env, HasTargetSpec, Os, RelocModel, SmallDataThresholdSupport, Target, TlsModel,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
@@ -335,9 +335,9 @@ pub(crate) unsafe fn create_module<'ll>(
|
||||
|
||||
// Control Flow Guard is currently only supported by MSVC and LLVM on Windows.
|
||||
if sess.target.is_like_msvc
|
||||
|| (sess.target.options.os == "windows"
|
||||
&& sess.target.options.env == "gnu"
|
||||
&& sess.target.options.abi == "llvm")
|
||||
|| (sess.target.options.os == Os::Windows
|
||||
&& sess.target.options.env == Env::Gnu
|
||||
&& sess.target.options.abi == Abi::Llvm)
|
||||
{
|
||||
match sess.opts.cg.control_flow_guard {
|
||||
CFGuard::Disabled => {}
|
||||
@@ -669,7 +669,7 @@ pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'
|
||||
/// This corresponds to the `-fobjc-abi-version=` flag in Clang / GCC.
|
||||
pub(crate) fn objc_abi_version(&self) -> u32 {
|
||||
assert!(self.tcx.sess.target.is_like_darwin);
|
||||
if self.tcx.sess.target.arch == Arch::X86 && self.tcx.sess.target.os == "macos" {
|
||||
if self.tcx.sess.target.arch == Arch::X86 && self.tcx.sess.target.os == Os::MacOs {
|
||||
// 32-bit x86 macOS uses ABI version 1 (a.k.a. the "fragile ABI").
|
||||
1
|
||||
} else {
|
||||
@@ -710,7 +710,7 @@ pub(crate) fn add_objc_module_flags(&self) {
|
||||
},
|
||||
);
|
||||
|
||||
if self.tcx.sess.target.env == "sim" {
|
||||
if self.tcx.sess.target.env == Env::Sim {
|
||||
llvm::add_module_flag_u32(
|
||||
self.llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Error,
|
||||
@@ -963,7 +963,7 @@ pub(crate) fn eh_catch_typeinfo(&self) -> &'ll Value {
|
||||
return eh_catch_typeinfo;
|
||||
}
|
||||
let tcx = self.tcx;
|
||||
assert!(self.sess().target.os == "emscripten");
|
||||
assert!(self.sess().target.os == Os::Emscripten);
|
||||
let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() {
|
||||
Some(def_id) => self.get_static(def_id),
|
||||
_ => {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
|
||||
use rustc_target::callconv::PassMode;
|
||||
use rustc_target::spec::Os;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::abi::FnAbiLlvmExt;
|
||||
@@ -681,7 +682,7 @@ fn catch_unwind_intrinsic<'ll, 'tcx>(
|
||||
codegen_msvc_try(bx, try_func, data, catch_func, dest);
|
||||
} else if wants_wasm_eh(bx.sess()) {
|
||||
codegen_wasm_try(bx, try_func, data, catch_func, dest);
|
||||
} else if bx.sess().target.os == "emscripten" {
|
||||
} else if bx.sess().target.os == Os::Emscripten {
|
||||
codegen_emcc_try(bx, try_func, data, catch_func, dest);
|
||||
} else {
|
||||
codegen_gnu_try(bx, try_func, data, catch_func, dest);
|
||||
|
||||
@@ -2025,7 +2025,7 @@ pub(crate) fn LLVMRustCreateRangeAttribute(
|
||||
) -> &Attribute;
|
||||
|
||||
// Operations on functions
|
||||
pub(crate) fn LLVMRustOffloadMapper<'a>(M: &'a Module, Fn: &'a Value, Fn: &'a Value);
|
||||
pub(crate) fn LLVMRustOffloadMapper<'a>(Fn: &'a Value, Fn: &'a Value);
|
||||
pub(crate) fn LLVMRustGetOrInsertFunction<'a>(
|
||||
M: &'a Module,
|
||||
Name: *const c_char,
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{PrintKind, PrintRequest};
|
||||
use rustc_target::spec::{Arch, MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
|
||||
use rustc_target::spec::{
|
||||
Abi, Arch, Env, MergeFunctions, Os, PanicStrategy, SmallDataThresholdSupport,
|
||||
};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
@@ -104,7 +106,7 @@ fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
|
||||
add("-wasm-enable-eh", false);
|
||||
}
|
||||
|
||||
if sess.target.os == "emscripten"
|
||||
if sess.target.os == Os::Emscripten
|
||||
&& !sess.opts.unstable_opts.emscripten_wasm_eh
|
||||
&& sess.panic_strategy().unwinds()
|
||||
{
|
||||
@@ -351,9 +353,9 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig {
|
||||
/// Determine whether or not experimental float types are reliable based on known bugs.
|
||||
fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
||||
let target_arch = &sess.target.arch;
|
||||
let target_os = sess.target.options.os.as_ref();
|
||||
let target_env = sess.target.options.env.as_ref();
|
||||
let target_abi = sess.target.options.abi.as_ref();
|
||||
let target_os = &sess.target.options.os;
|
||||
let target_env = &sess.target.options.env;
|
||||
let target_abi = &sess.target.options.abi;
|
||||
let target_pointer_width = sess.target.pointer_width;
|
||||
let version = get_version();
|
||||
let lt_20_1_1 = version < (20, 1, 1);
|
||||
@@ -371,7 +373,7 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
||||
// Selection failure <https://github.com/llvm/llvm-project/issues/50374> (fixed in llvm21)
|
||||
(Arch::S390x, _) if lt_21_0_0 => false,
|
||||
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
|
||||
(Arch::X86_64, "windows") if target_env == "gnu" && target_abi != "llvm" => false,
|
||||
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false,
|
||||
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
|
||||
(Arch::CSky, _) => false,
|
||||
(Arch::Hexagon, _) if lt_21_0_0 => false, // (fixed in llvm21)
|
||||
@@ -403,7 +405,7 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
||||
// not fail if our compiler-builtins is linked. (fixed in llvm21)
|
||||
(Arch::X86, _) if lt_21_0_0 => false,
|
||||
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
|
||||
(Arch::X86_64, "windows") if target_env == "gnu" && target_abi != "llvm" => false,
|
||||
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false,
|
||||
// There are no known problems on other platforms, so the only requirement is that symbols
|
||||
// are available. `compiler-builtins` provides all symbols required for core `f128`
|
||||
// support, so this should work for everything else.
|
||||
@@ -424,9 +426,9 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
||||
// (ld is 80-bit extended precision).
|
||||
//
|
||||
// musl does not implement the symbols required for f128 math at all.
|
||||
_ if target_env == "musl" => false,
|
||||
_ if *target_env == Env::Musl => false,
|
||||
(Arch::X86_64, _) => false,
|
||||
(_, "linux") if target_pointer_width == 64 => true,
|
||||
(_, Os::Linux) if target_pointer_width == 64 => true,
|
||||
_ => false,
|
||||
} && cfg.has_reliable_f128;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
use rustc_target::spec::Arch;
|
||||
use rustc_target::spec::{Abi, Arch};
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::llvm::{Type, Value};
|
||||
@@ -270,7 +270,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>(
|
||||
|
||||
// Rust does not currently support any powerpc softfloat targets.
|
||||
let target = &bx.cx.tcx.sess.target;
|
||||
let is_soft_float_abi = target.abi == "softfloat";
|
||||
let is_soft_float_abi = target.abi == Abi::SoftFloat;
|
||||
assert!(!is_soft_float_abi);
|
||||
|
||||
// All instances of VaArgSafe are passed directly.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_session::Session;
|
||||
pub(super) use rustc_target::spec::apple::OSVersion;
|
||||
use rustc_target::spec::{Arch, Target};
|
||||
use rustc_target::spec::{Arch, Env, Os, Target};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::errors::{XcrunError, XcrunSdkPathWarning};
|
||||
@@ -17,35 +17,35 @@
|
||||
|
||||
/// The canonical name of the desired SDK for a given target.
|
||||
pub(super) fn sdk_name(target: &Target) -> &'static str {
|
||||
match (&*target.os, &*target.env) {
|
||||
("macos", "") => "MacOSX",
|
||||
("ios", "") => "iPhoneOS",
|
||||
("ios", "sim") => "iPhoneSimulator",
|
||||
match (&target.os, &target.env) {
|
||||
(Os::MacOs, Env::Unspecified) => "MacOSX",
|
||||
(Os::IOs, Env::Unspecified) => "iPhoneOS",
|
||||
(Os::IOs, Env::Sim) => "iPhoneSimulator",
|
||||
// Mac Catalyst uses the macOS SDK
|
||||
("ios", "macabi") => "MacOSX",
|
||||
("tvos", "") => "AppleTVOS",
|
||||
("tvos", "sim") => "AppleTVSimulator",
|
||||
("visionos", "") => "XROS",
|
||||
("visionos", "sim") => "XRSimulator",
|
||||
("watchos", "") => "WatchOS",
|
||||
("watchos", "sim") => "WatchSimulator",
|
||||
(Os::IOs, Env::MacAbi) => "MacOSX",
|
||||
(Os::TvOs, Env::Unspecified) => "AppleTVOS",
|
||||
(Os::TvOs, Env::Sim) => "AppleTVSimulator",
|
||||
(Os::VisionOs, Env::Unspecified) => "XROS",
|
||||
(Os::VisionOs, Env::Sim) => "XRSimulator",
|
||||
(Os::WatchOs, Env::Unspecified) => "WatchOS",
|
||||
(Os::WatchOs, Env::Sim) => "WatchSimulator",
|
||||
(os, abi) => unreachable!("invalid os '{os}' / abi '{abi}' combination for Apple target"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn macho_platform(target: &Target) -> u32 {
|
||||
match (&*target.os, &*target.env) {
|
||||
("macos", _) => object::macho::PLATFORM_MACOS,
|
||||
("ios", "macabi") => object::macho::PLATFORM_MACCATALYST,
|
||||
("ios", "sim") => object::macho::PLATFORM_IOSSIMULATOR,
|
||||
("ios", _) => object::macho::PLATFORM_IOS,
|
||||
("watchos", "sim") => object::macho::PLATFORM_WATCHOSSIMULATOR,
|
||||
("watchos", _) => object::macho::PLATFORM_WATCHOS,
|
||||
("tvos", "sim") => object::macho::PLATFORM_TVOSSIMULATOR,
|
||||
("tvos", _) => object::macho::PLATFORM_TVOS,
|
||||
("visionos", "sim") => object::macho::PLATFORM_XROSSIMULATOR,
|
||||
("visionos", _) => object::macho::PLATFORM_XROS,
|
||||
_ => unreachable!("tried to get Mach-O platform for non-Apple target"),
|
||||
match (&target.os, &target.env) {
|
||||
(Os::MacOs, _) => object::macho::PLATFORM_MACOS,
|
||||
(Os::IOs, Env::MacAbi) => object::macho::PLATFORM_MACCATALYST,
|
||||
(Os::IOs, Env::Sim) => object::macho::PLATFORM_IOSSIMULATOR,
|
||||
(Os::IOs, _) => object::macho::PLATFORM_IOS,
|
||||
(Os::WatchOs, Env::Sim) => object::macho::PLATFORM_WATCHOSSIMULATOR,
|
||||
(Os::WatchOs, _) => object::macho::PLATFORM_WATCHOS,
|
||||
(Os::TvOs, Env::Sim) => object::macho::PLATFORM_TVOSSIMULATOR,
|
||||
(Os::TvOs, _) => object::macho::PLATFORM_TVOS,
|
||||
(Os::VisionOs, Env::Sim) => object::macho::PLATFORM_XROSSIMULATOR,
|
||||
(Os::VisionOs, _) => object::macho::PLATFORM_XROS,
|
||||
(os, env) => unreachable!("invalid os '{os}' / env '{env}' combination for Apple target"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,9 +46,9 @@
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::crt_objects::CrtObjects;
|
||||
use rustc_target::spec::{
|
||||
BinaryFormat, Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault,
|
||||
LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, RelocModel, RelroLevel, SanitizerSet,
|
||||
SplitDebuginfo,
|
||||
Abi, BinaryFormat, Cc, Env, LinkOutputKind, LinkSelfContainedComponents,
|
||||
LinkSelfContainedDefault, LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, Os, RelocModel,
|
||||
RelroLevel, SanitizerSet, SplitDebuginfo,
|
||||
};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
@@ -1407,11 +1407,9 @@ fn adjust_flavor_to_features(
|
||||
Some(LinkerFlavorCli::Llbc) => Some(LinkerFlavor::Llbc),
|
||||
Some(LinkerFlavorCli::Ptx) => Some(LinkerFlavor::Ptx),
|
||||
// The linker flavors that corresponds to targets needs logic that keeps the base LinkerFlavor
|
||||
_ => sess
|
||||
.opts
|
||||
.cg
|
||||
.linker_flavor
|
||||
.map(|flavor| sess.target.linker_flavor.with_cli_hints(flavor)),
|
||||
linker_flavor => {
|
||||
linker_flavor.map(|flavor| sess.target.linker_flavor.with_cli_hints(flavor))
|
||||
}
|
||||
};
|
||||
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor, features) {
|
||||
return ret;
|
||||
@@ -1819,7 +1817,7 @@ fn self_contained_components(
|
||||
LinkSelfContainedDefault::InferredForMusl => sess.crt_static(Some(crate_type)),
|
||||
LinkSelfContainedDefault::InferredForMingw => {
|
||||
sess.host == sess.target
|
||||
&& sess.target.vendor != "uwp"
|
||||
&& sess.target.abi != Abi::Uwp
|
||||
&& detect_self_contained_mingw(sess, linker)
|
||||
}
|
||||
}
|
||||
@@ -1845,7 +1843,7 @@ fn add_pre_link_objects(
|
||||
let empty = Default::default();
|
||||
let objects = if self_contained {
|
||||
&opts.pre_link_objects_self_contained
|
||||
} else if !(sess.target.os == "fuchsia" && matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))) {
|
||||
} else if !(sess.target.os == Os::Fuchsia && matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))) {
|
||||
&opts.pre_link_objects
|
||||
} else {
|
||||
&empty
|
||||
@@ -2496,7 +2494,7 @@ fn add_order_independent_options(
|
||||
|
||||
let apple_sdk_root = add_apple_sdk(cmd, sess, flavor);
|
||||
|
||||
if sess.target.os == "fuchsia"
|
||||
if sess.target.os == Os::Fuchsia
|
||||
&& crate_type == CrateType::Executable
|
||||
&& !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
|
||||
{
|
||||
@@ -2515,7 +2513,7 @@ fn add_order_independent_options(
|
||||
cmd.no_crt_objects();
|
||||
}
|
||||
|
||||
if sess.target.os == "emscripten" {
|
||||
if sess.target.os == Os::Emscripten {
|
||||
cmd.cc_arg(if sess.opts.unstable_opts.emscripten_wasm_eh {
|
||||
"-fwasm-exceptions"
|
||||
} else if sess.panic_strategy().unwinds() {
|
||||
@@ -3070,8 +3068,8 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
|
||||
|
||||
// `sess.target.arch` (`target_arch`) is not detailed enough.
|
||||
let llvm_arch = sess.target.llvm_target.split_once('-').expect("LLVM target must have arch").0;
|
||||
let target_os = &*sess.target.os;
|
||||
let target_env = &*sess.target.env;
|
||||
let target_os = &sess.target.os;
|
||||
let target_env = &sess.target.env;
|
||||
|
||||
// The architecture name to forward to the linker.
|
||||
//
|
||||
@@ -3123,12 +3121,12 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
|
||||
// > - xros-simulator
|
||||
// > - driverkit
|
||||
let platform_name = match (target_os, target_env) {
|
||||
(os, "") => os,
|
||||
("ios", "macabi") => "mac-catalyst",
|
||||
("ios", "sim") => "ios-simulator",
|
||||
("tvos", "sim") => "tvos-simulator",
|
||||
("watchos", "sim") => "watchos-simulator",
|
||||
("visionos", "sim") => "visionos-simulator",
|
||||
(os, Env::Unspecified) => os.desc(),
|
||||
(Os::IOs, Env::MacAbi) => "mac-catalyst",
|
||||
(Os::IOs, Env::Sim) => "ios-simulator",
|
||||
(Os::TvOs, Env::Sim) => "tvos-simulator",
|
||||
(Os::WatchOs, Env::Sim) => "watchos-simulator",
|
||||
(Os::VisionOs, Env::Sim) => "visionos-simulator",
|
||||
_ => bug!("invalid OS/env combination for Apple target: {target_os}, {target_env}"),
|
||||
};
|
||||
|
||||
@@ -3192,7 +3190,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
|
||||
// fairly safely use `-target`. See also the following, where it is
|
||||
// made explicit that the recommendation by LLVM developers is to use
|
||||
// `-target`: <https://github.com/llvm/llvm-project/issues/88271>
|
||||
if target_os == "macos" {
|
||||
if *target_os == Os::MacOs {
|
||||
// `-arch` communicates the architecture.
|
||||
//
|
||||
// CC forwards the `-arch` to the linker, so we use the same value
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
|
||||
use rustc_target::spec::{Arch, Cc, LinkOutputKind, LinkerFlavor, Lld};
|
||||
use rustc_target::spec::{Abi, Arch, Cc, LinkOutputKind, LinkerFlavor, Lld, Os};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use super::command::Command;
|
||||
@@ -83,7 +83,7 @@ pub(crate) fn get_linker<'a>(
|
||||
// To comply with the Windows App Certification Kit,
|
||||
// MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
|
||||
let t = &sess.target;
|
||||
if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" {
|
||||
if matches!(flavor, LinkerFlavor::Msvc(..)) && t.abi == Abi::Uwp {
|
||||
if let Some(ref tool) = msvc_tool {
|
||||
let original_path = tool.path();
|
||||
if let Some(root_lib_path) = original_path.ancestors().nth(4) {
|
||||
@@ -134,12 +134,12 @@ pub(crate) fn get_linker<'a>(
|
||||
|
||||
// FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
|
||||
// to the linker args construction.
|
||||
assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
|
||||
assert!(cmd.get_args().is_empty() || sess.target.abi == Abi::Uwp);
|
||||
match flavor {
|
||||
LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => {
|
||||
LinkerFlavor::Unix(Cc::No) if sess.target.os == Os::L4Re => {
|
||||
Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
|
||||
}
|
||||
LinkerFlavor::Unix(Cc::No) if sess.target.os == "aix" => {
|
||||
LinkerFlavor::Unix(Cc::No) if sess.target.os == Os::Aix => {
|
||||
Box::new(AixLinker::new(cmd, sess)) as Box<dyn Linker>
|
||||
}
|
||||
LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
|
||||
@@ -573,7 +573,7 @@ fn set_output_kind(
|
||||
// any `#[link]` attributes in the `libc` crate, see #72782 for details.
|
||||
// FIXME: Switch to using `#[link]` attributes in the `libc` crate
|
||||
// similarly to other targets.
|
||||
if self.sess.target.os == "vxworks"
|
||||
if self.sess.target.os == Os::VxWorks
|
||||
&& matches!(
|
||||
output_kind,
|
||||
LinkOutputKind::StaticNoPicExe
|
||||
@@ -595,7 +595,7 @@ fn set_output_kind(
|
||||
}
|
||||
|
||||
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
|
||||
if self.sess.target.os == "illumos" && name == "c" {
|
||||
if self.sess.target.os == Os::Illumos && name == "c" {
|
||||
// libc will be added via late_link_args on illumos so that it will
|
||||
// appear last in the library search order.
|
||||
// FIXME: This should be replaced by a more complete and generic
|
||||
@@ -1439,7 +1439,7 @@ fn export_symbols(
|
||||
// symbols explicitly passed via the `--export` flags above and hides all
|
||||
// others. Various bits and pieces of wasm32-unknown-unknown tooling use
|
||||
// this, so be sure these symbols make their way out of the linker as well.
|
||||
if self.sess.target.os == "unknown" || self.sess.target.os == "none" {
|
||||
if matches!(self.sess.target.os, Os::Unknown | Os::None) {
|
||||
self.link_args(&["--export=__heap_base", "--export=__data_end"]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::sym;
|
||||
use rustc_target::spec::{RelocModel, Target, ef_avr_arch};
|
||||
use rustc_target::spec::{Abi, Os, RelocModel, Target, ef_avr_arch};
|
||||
use tracing::debug;
|
||||
|
||||
use super::apple;
|
||||
@@ -260,10 +260,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
||||
}
|
||||
|
||||
pub(super) fn elf_os_abi(sess: &Session) -> u8 {
|
||||
match sess.target.options.os.as_ref() {
|
||||
"hermit" => elf::ELFOSABI_STANDALONE,
|
||||
"freebsd" => elf::ELFOSABI_FREEBSD,
|
||||
"solaris" => elf::ELFOSABI_SOLARIS,
|
||||
match sess.target.options.os {
|
||||
Os::Hermit => elf::ELFOSABI_STANDALONE,
|
||||
Os::FreeBsd => elf::ELFOSABI_FREEBSD,
|
||||
Os::Solaris => elf::ELFOSABI_SOLARIS,
|
||||
_ => elf::ELFOSABI_NONE,
|
||||
}
|
||||
}
|
||||
@@ -379,11 +379,11 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
|
||||
}
|
||||
}
|
||||
Architecture::Csky => {
|
||||
let e_flags = match sess.target.options.abi.as_ref() {
|
||||
"abiv2" => elf::EF_CSKY_ABIV2,
|
||||
_ => elf::EF_CSKY_ABIV1,
|
||||
};
|
||||
e_flags
|
||||
if matches!(sess.target.options.abi, Abi::AbiV2) {
|
||||
elf::EF_CSKY_ABIV2
|
||||
} else {
|
||||
elf::EF_CSKY_ABIV1
|
||||
}
|
||||
}
|
||||
Architecture::PowerPc64 => {
|
||||
const EF_PPC64_ABI_UNKNOWN: u32 = 0;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_session::config::{CrateType, OomStrategy};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::{Arch, TlsModel};
|
||||
use rustc_target::spec::{Arch, Os, TlsModel};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::back::symbol_export;
|
||||
@@ -711,7 +711,7 @@ pub(crate) fn extend_exported_symbols<'tcx>(
|
||||
) {
|
||||
let (callconv, _) = calling_convention_for_symbol(tcx, symbol);
|
||||
|
||||
if callconv != CanonAbi::GpuKernel || tcx.sess.target.os != "amdhsa" {
|
||||
if callconv != CanonAbi::GpuKernel || tcx.sess.target.os != Os::AmdHsa {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
use rustc_session::config::{self, CrateType, EntryFnType};
|
||||
use rustc_span::{DUMMY_SP, Symbol, sym};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::Arch;
|
||||
use rustc_target::spec::{Arch, Os};
|
||||
use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
|
||||
use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
|
||||
use tracing::{debug, info};
|
||||
@@ -366,7 +366,7 @@ pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
// us
|
||||
pub fn wants_wasm_eh(sess: &Session) -> bool {
|
||||
sess.target.is_like_wasm
|
||||
&& (sess.target.os != "emscripten" || sess.opts.unstable_opts.emscripten_wasm_eh)
|
||||
&& (sess.target.os != Os::Emscripten || sess.opts.unstable_opts.emscripten_wasm_eh)
|
||||
}
|
||||
|
||||
/// Returns `true` if this session's target will use SEH-based unwinding.
|
||||
@@ -500,7 +500,7 @@ fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
) -> Bx::Function {
|
||||
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`, or
|
||||
// `usize efi_main(void *handle, void *system_table)` depending on the target.
|
||||
let llfty = if cx.sess().target.os.contains("uefi") {
|
||||
let llfty = if cx.sess().target.os == Os::Uefi {
|
||||
cx.type_func(&[cx.type_ptr(), cx.type_ptr()], cx.type_isize())
|
||||
} else if cx.sess().target.main_needs_argc_argv {
|
||||
cx.type_func(&[cx.type_int(), cx.type_ptr()], cx.type_int())
|
||||
@@ -562,7 +562,7 @@ fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
};
|
||||
|
||||
let result = bx.call(start_ty, None, None, start_fn, &args, None, instance);
|
||||
if cx.sess().target.os.contains("uefi") {
|
||||
if cx.sess().target.os == Os::Uefi {
|
||||
bx.ret(result);
|
||||
} else {
|
||||
let cast = bx.intcast(result, cx.type_int(), true);
|
||||
@@ -576,7 +576,7 @@ fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
/// Obtain the `argc` and `argv` values to pass to the rust start function
|
||||
/// (i.e., the "start" lang item).
|
||||
fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Value, Bx::Value) {
|
||||
if bx.cx().sess().target.os.contains("uefi") {
|
||||
if bx.cx().sess().target.os == Os::Uefi {
|
||||
// Params for UEFI
|
||||
let param_handle = bx.get_param(0);
|
||||
let param_system_table = bx.get_param(1);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use rustc_target::spec::Os;
|
||||
|
||||
use crate::errors;
|
||||
use crate::target_features::{
|
||||
@@ -258,7 +259,7 @@ fn process_builtin_attrs(
|
||||
UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER,
|
||||
UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER,
|
||||
UsedBy::Default => {
|
||||
let used_form = if tcx.sess.target.os == "illumos" {
|
||||
let used_form = if tcx.sess.target.os == Os::Illumos {
|
||||
// illumos' `ld` doesn't support a section header that would represent
|
||||
// `#[used(linker)]`, see
|
||||
// https://github.com/rust-lang/rust/issues/146169. For that target,
|
||||
@@ -468,16 +469,18 @@ fn check_result(
|
||||
})
|
||||
}
|
||||
|
||||
// warn for nonblocking async fn.
|
||||
// warn for nonblocking async functions, blocks and closures.
|
||||
// This doesn't behave as expected, because the executor can run blocking code without the sanitizer noticing.
|
||||
if codegen_fn_attrs.sanitizers.rtsan_setting == RtsanSetting::Nonblocking
|
||||
&& let Some(sanitize_span) = interesting_spans.sanitize
|
||||
// async function
|
||||
&& (tcx.asyncness(did).is_async() || (tcx.is_closure_like(did.into())
|
||||
// async fn
|
||||
&& (tcx.asyncness(did).is_async()
|
||||
// async block
|
||||
&& (tcx.coroutine_is_async(did.into())
|
||||
// async closure
|
||||
|| tcx.coroutine_is_async(tcx.coroutine_for_closure(did)))))
|
||||
|| tcx.is_coroutine(did.into())
|
||||
// async closure
|
||||
|| (tcx.is_closure_like(did.into())
|
||||
&& tcx.hir_node_by_def_id(did).expect_closure().kind
|
||||
!= rustc_hir::ClosureKind::Closure))
|
||||
{
|
||||
let hir_id = tcx.local_def_id_to_hir_id(did);
|
||||
tcx.node_span_lint(
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_session::cstore::{DllCallingConvention, DllImport};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::Target;
|
||||
use rustc_target::spec::{Abi, Env, Os, Target};
|
||||
|
||||
use crate::traits::*;
|
||||
|
||||
@@ -171,7 +171,7 @@ pub fn asm_const_to_str<'tcx>(
|
||||
}
|
||||
|
||||
pub fn is_mingw_gnu_toolchain(target: &Target) -> bool {
|
||||
target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
|
||||
target.os == Os::Windows && target.env == Env::Gnu && target.abi == Abi::Unspecified
|
||||
}
|
||||
|
||||
pub fn i686_decorated_name(
|
||||
|
||||
@@ -1498,14 +1498,10 @@ pub fn mem_copy_repeatedly(
|
||||
|
||||
// Prepare getting source provenance.
|
||||
let src_bytes = src_alloc.get_bytes_unchecked(src_range).as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation
|
||||
// first copy the provenance to a temporary buffer, because
|
||||
// `get_bytes_mut` will clear the provenance, which is correct,
|
||||
// since we don't want to keep any provenance at the target.
|
||||
// This will also error if copying partial provenance is not supported.
|
||||
let provenance = src_alloc
|
||||
.provenance()
|
||||
.prepare_copy(src_range, self)
|
||||
.map_err(|e| e.to_interp_error(src_alloc_id))?;
|
||||
// First copy the provenance to a temporary buffer, because
|
||||
// `get_bytes_unchecked_for_overwrite_ptr` will clear the provenance (in preparation for
|
||||
// inserting the new provenance), and that can overlap with the source range.
|
||||
let provenance = src_alloc.provenance_prepare_copy(src_range, self);
|
||||
// Prepare a copy of the initialization mask.
|
||||
let init = src_alloc.init_mask().prepare_copy(src_range);
|
||||
|
||||
|
||||
@@ -704,6 +704,7 @@ fn write_immediate_to_mplace_no_validate(
|
||||
// wrong type.
|
||||
|
||||
let tcx = *self.tcx;
|
||||
let will_later_validate = M::enforce_validity(self, layout);
|
||||
let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout })? else {
|
||||
// zero-sized access
|
||||
return interp_ok(());
|
||||
@@ -714,23 +715,31 @@ fn write_immediate_to_mplace_no_validate(
|
||||
alloc.write_scalar(alloc_range(Size::ZERO, scalar.size()), scalar)?;
|
||||
}
|
||||
Immediate::ScalarPair(a_val, b_val) => {
|
||||
let BackendRepr::ScalarPair(a, b) = layout.backend_repr else {
|
||||
let BackendRepr::ScalarPair(_a, b) = layout.backend_repr else {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
|
||||
layout
|
||||
)
|
||||
};
|
||||
let b_offset = a.size(&tcx).align_to(b.align(&tcx).abi);
|
||||
let a_size = a_val.size();
|
||||
let b_offset = a_size.align_to(b.align(&tcx).abi);
|
||||
assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields
|
||||
|
||||
// It is tempting to verify `b_offset` against `layout.fields.offset(1)`,
|
||||
// but that does not work: We could be a newtype around a pair, then the
|
||||
// fields do not match the `ScalarPair` components.
|
||||
|
||||
alloc.write_scalar(alloc_range(Size::ZERO, a_val.size()), a_val)?;
|
||||
// In preparation, if we do *not* later reset the padding, we clear the entire
|
||||
// destination now to ensure that no stray pointer fragments are being
|
||||
// preserved (see <https://github.com/rust-lang/rust/issues/148470>).
|
||||
// We can skip this if there is no padding (e.g. for wide pointers).
|
||||
if !will_later_validate && a_size + b_val.size() != layout.size {
|
||||
alloc.write_uninit_full();
|
||||
}
|
||||
|
||||
alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?;
|
||||
alloc.write_scalar(alloc_range(b_offset, b_val.size()), b_val)?;
|
||||
// We don't have to reset padding here, `write_immediate` will anyway do a validation run.
|
||||
}
|
||||
Immediate::Uninit => alloc.write_uninit_full(),
|
||||
}
|
||||
|
||||
@@ -53,13 +53,13 @@ impl !DynSend for std::env::VarsOs {}
|
||||
|
||||
macro_rules! already_send {
|
||||
($([$ty: ty])*) => {
|
||||
$(unsafe impl DynSend for $ty where $ty: Send {})*
|
||||
$(unsafe impl DynSend for $ty where Self: Send {})*
|
||||
};
|
||||
}
|
||||
|
||||
// These structures are already `Send`.
|
||||
already_send!(
|
||||
[std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File]
|
||||
[std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File][std::panic::Location<'_>]
|
||||
[rustc_arena::DroplessArena][jobserver_crate::Client][jobserver_crate::HelperThread]
|
||||
[crate::memmap::Mmap][crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice]
|
||||
);
|
||||
@@ -127,14 +127,14 @@ impl !DynSync for std::env::VarsOs {}
|
||||
|
||||
macro_rules! already_sync {
|
||||
($([$ty: ty])*) => {
|
||||
$(unsafe impl DynSync for $ty where $ty: Sync {})*
|
||||
$(unsafe impl DynSync for $ty where Self: Sync {})*
|
||||
};
|
||||
}
|
||||
|
||||
// These structures are already `Sync`.
|
||||
already_sync!(
|
||||
[std::sync::atomic::AtomicBool][std::sync::atomic::AtomicUsize][std::sync::atomic::AtomicU8]
|
||||
[std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File]
|
||||
[std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File][std::panic::Location<'_>]
|
||||
[jobserver_crate::Client][jobserver_crate::HelperThread][crate::memmap::Mmap]
|
||||
[crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice]
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::stable_hasher::{HashStable, StableHasher};
|
||||
use crate::sync::{MappedReadGuard, ReadGuard, RwLock};
|
||||
use crate::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, RwLock, WriteGuard};
|
||||
|
||||
/// The `Steal` struct is intended to used as the value for a query.
|
||||
/// Specifically, we sometimes have queries (*cough* MIR *cough*)
|
||||
@@ -40,9 +40,17 @@ pub fn borrow(&self) -> MappedReadGuard<'_, T> {
|
||||
ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())
|
||||
}
|
||||
|
||||
/// An escape hatch for rustc drivers to mutate `Steal` caches.
|
||||
///
|
||||
/// Use at your own risk. This can badly break incremental compilation
|
||||
/// and anything else that relies on the immutability of query caches.
|
||||
#[track_caller]
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
self.value.get_mut().as_mut().expect("attempt to read from stolen value")
|
||||
pub fn risky_hack_borrow_mut(&self) -> MappedWriteGuard<'_, T> {
|
||||
let borrow = self.value.borrow_mut();
|
||||
if borrow.is_none() {
|
||||
panic!("attempted to read from stolen value: {}", std::any::type_name::<T>());
|
||||
}
|
||||
WriteGuard::map(borrow, |opt| opt.as_mut().unwrap())
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
||||
@@ -152,7 +152,8 @@ pub(super) fn install() {
|
||||
libc::sigaltstack(&alt_stack, ptr::null_mut());
|
||||
|
||||
let mut sa: libc::sigaction = mem::zeroed();
|
||||
sa.sa_sigaction = print_stack_trace as libc::sighandler_t;
|
||||
sa.sa_sigaction =
|
||||
print_stack_trace as unsafe extern "C" fn(libc::c_int) as libc::sighandler_t;
|
||||
sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK;
|
||||
libc::sigemptyset(&mut sa.sa_mask);
|
||||
for (signum, _signame) in KILL_SIGNALS {
|
||||
|
||||
@@ -5,7 +5,7 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
annotate-snippets = "0.12.8"
|
||||
annotate-snippets = "0.12.9"
|
||||
anstream = "0.6.20"
|
||||
anstyle = "1.0.13"
|
||||
derive_setters = "0.1.6"
|
||||
|
||||
@@ -350,22 +350,27 @@ fn emit_messages_default(
|
||||
"all spans must be disjoint",
|
||||
);
|
||||
|
||||
let lo = subst.parts.iter().map(|part| part.span.lo()).min()?;
|
||||
let lo_file = sm.lookup_source_file(lo);
|
||||
let hi = subst.parts.iter().map(|part| part.span.hi()).max()?;
|
||||
let hi_file = sm.lookup_source_file(hi);
|
||||
|
||||
// The different spans might belong to different contexts, if so ignore suggestion.
|
||||
if lo_file.stable_id != hi_file.stable_id {
|
||||
return None;
|
||||
}
|
||||
|
||||
// We can't splice anything if the source is unavailable.
|
||||
if !sm.ensure_source_file_source_present(&lo_file) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Account for cases where we are suggesting the same code that's already
|
||||
// there. This shouldn't happen often, but in some cases for multipart
|
||||
// suggestions it's much easier to handle it here than in the origin.
|
||||
subst.parts.retain(|p| is_different(sm, &p.snippet, p.span));
|
||||
|
||||
let item_span = subst.parts.first()?;
|
||||
let file = sm.lookup_source_file(item_span.span.lo());
|
||||
if should_show_source_code(
|
||||
&self.ignored_directories_in_source_blocks,
|
||||
sm,
|
||||
&file,
|
||||
) {
|
||||
Some(subst)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
if subst.parts.is_empty() { None } else { Some(subst) }
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -745,14 +750,20 @@ fn shrink_file(
|
||||
) -> Option<(Span, String, usize)> {
|
||||
let lo_byte = spans.iter().map(|s| s.lo()).min()?;
|
||||
let lo_loc = sm.lookup_char_pos(lo_byte);
|
||||
let lo = lo_loc.file.line_bounds(lo_loc.line.saturating_sub(1)).start;
|
||||
|
||||
let hi_byte = spans.iter().map(|s| s.hi()).max()?;
|
||||
let hi_loc = sm.lookup_char_pos(hi_byte);
|
||||
let hi = lo_loc.file.line_bounds(hi_loc.line.saturating_sub(1)).end;
|
||||
|
||||
if lo_loc.file.stable_id != hi_loc.file.stable_id {
|
||||
// this may happen when spans cross file boundaries due to macro expansion.
|
||||
return None;
|
||||
}
|
||||
|
||||
let lo = lo_loc.file.line_bounds(lo_loc.line.saturating_sub(1)).start;
|
||||
let hi = hi_loc.file.line_bounds(hi_loc.line.saturating_sub(1)).end;
|
||||
|
||||
let bounding_span = Span::with_root_ctxt(lo, hi);
|
||||
let source = sm.span_to_snippet(bounding_span).unwrap_or_default();
|
||||
let source = sm.span_to_snippet(bounding_span).ok()?;
|
||||
let offset_line = sm.doctest_offset_line(file_name, lo_loc.line);
|
||||
|
||||
Some((bounding_span, source, offset_line))
|
||||
|
||||
@@ -1704,7 +1704,7 @@ fn emit_messages_default_inner(
|
||||
}
|
||||
// print out the span location and spacer before we print the annotated source
|
||||
// to do this, we need to know if this span will be primary
|
||||
let is_primary = primary_lo.file.name == annotated_file.file.name;
|
||||
let is_primary = primary_lo.file.stable_id == annotated_file.file.stable_id;
|
||||
if is_primary {
|
||||
let loc = primary_lo.clone();
|
||||
if !self.short_message {
|
||||
@@ -2322,11 +2322,6 @@ fn emit_suggestion_default(
|
||||
show_code_change
|
||||
{
|
||||
for part in parts {
|
||||
let snippet = if let Ok(snippet) = sm.span_to_snippet(part.span) {
|
||||
snippet
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
|
||||
let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display;
|
||||
|
||||
@@ -2402,7 +2397,7 @@ fn emit_suggestion_default(
|
||||
// LL - REMOVED <- row_num - 2 - (newlines - first_i - 1)
|
||||
// LL + NEWER
|
||||
// | <- row_num
|
||||
|
||||
let snippet = sm.span_to_snippet(part.span).unwrap_or_default();
|
||||
let newlines = snippet.lines().count();
|
||||
if newlines > 0 && row_num > newlines {
|
||||
// Account for removals where the part being removed spans multiple
|
||||
@@ -3108,7 +3103,7 @@ fn add_annotation_to_file(
|
||||
) {
|
||||
for slot in file_vec.iter_mut() {
|
||||
// Look through each of our files for the one we're adding to
|
||||
if slot.file.name == file.name {
|
||||
if slot.file.stable_id == file.stable_id {
|
||||
// See if we already have a line for it
|
||||
for line_slot in &mut slot.lines {
|
||||
if line_slot.line_index == line_index {
|
||||
@@ -3471,14 +3466,9 @@ fn drop(&mut self) {
|
||||
|
||||
pub fn stderr_destination(color: ColorConfig) -> Destination {
|
||||
let buffer_writer = std::io::stderr();
|
||||
let choice = color.to_color_choice();
|
||||
// We need to resolve `ColorChoice::Auto` before `Box`ing since
|
||||
// `ColorChoice::Auto` on `dyn Write` will always resolve to `Never`
|
||||
let choice = if matches!(choice, ColorChoice::Auto) {
|
||||
AutoStream::choice(&buffer_writer)
|
||||
} else {
|
||||
choice
|
||||
};
|
||||
let choice = get_stderr_color_choice(color, &buffer_writer);
|
||||
// On Windows we'll be performing global synchronization on the entire
|
||||
// system for emitting rustc errors, so there's no need to buffer
|
||||
// anything.
|
||||
@@ -3493,6 +3483,11 @@ pub fn stderr_destination(color: ColorConfig) -> Destination {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_stderr_color_choice(color: ColorConfig, stderr: &std::io::Stderr) -> ColorChoice {
|
||||
let choice = color.to_color_choice();
|
||||
if matches!(choice, ColorChoice::Auto) { AutoStream::choice(stderr) } else { choice }
|
||||
}
|
||||
|
||||
/// On Windows, BRIGHT_BLUE is hard to read on black. Use cyan instead.
|
||||
///
|
||||
/// See #36178.
|
||||
|
||||
@@ -1099,6 +1099,9 @@ pub fn expn_data(
|
||||
pub struct DeriveResolution {
|
||||
pub path: ast::Path,
|
||||
pub item: Annotatable,
|
||||
// FIXME: currently this field is only used in `is_none`/`is_some` conditions. However, the
|
||||
// `Arc<SyntaxExtension>` will be used if the FIXME in `MacroExpander::fully_expand_fragment`
|
||||
// is completed.
|
||||
pub exts: Option<Arc<SyntaxExtension>>,
|
||||
pub is_const: bool,
|
||||
}
|
||||
|
||||
@@ -886,9 +886,6 @@ fn expand_invoc(
|
||||
}
|
||||
}
|
||||
} else if let SyntaxExtensionKind::NonMacroAttr = ext {
|
||||
if let ast::Safety::Unsafe(span) = attr.get_normal_item().unsafety {
|
||||
self.cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute");
|
||||
}
|
||||
// `-Zmacro-stats` ignores these because they don't do any real expansion.
|
||||
self.cx.expanded_inert_attrs.mark(&attr);
|
||||
item.visit_attrs(|attrs| attrs.insert(pos, attr));
|
||||
|
||||
@@ -749,7 +749,7 @@ fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span>
|
||||
let self_loc = self.psess().source_map().lookup_char_pos(first.lo());
|
||||
let other_loc = self.psess().source_map().lookup_char_pos(second.lo());
|
||||
|
||||
if self_loc.file.name != other_loc.file.name {
|
||||
if self_loc.file.stable_id != other_loc.file.stable_id {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
@@ -215,6 +215,8 @@ macro_rules! declare_features {
|
||||
(accepted, extern_crate_self, "1.34.0", Some(56409)),
|
||||
/// Allows access to crate names passed via `--extern` through prelude.
|
||||
(accepted, extern_prelude, "1.30.0", Some(44660)),
|
||||
/// Allows using `system` as a calling convention with varargs.
|
||||
(accepted, extern_system_varargs, "CURRENT_RUSTC_VERSION", Some(136946)),
|
||||
/// Allows using F16C intrinsics from `core::arch::{x86, x86_64}`.
|
||||
(accepted, f16c_target_feature, "1.68.0", Some(44839)),
|
||||
/// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
|
||||
|
||||
@@ -410,6 +410,9 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(unstable, avx10_target_feature, "1.88.0", Some(138843)),
|
||||
/// Allows using C-variadics.
|
||||
(unstable, c_variadic, "1.34.0", Some(44930)),
|
||||
/// Allows defining c-variadic naked functions with any extern ABI that is allowed
|
||||
/// on c-variadic foreign functions.
|
||||
(unstable, c_variadic_naked_functions, "CURRENT_RUSTC_VERSION", Some(148767)),
|
||||
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
|
||||
(unstable, cfg_contract_checks, "1.86.0", Some(128044)),
|
||||
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
|
||||
@@ -498,8 +501,6 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
|
||||
/// Allows using `#[export_stable]` which indicates that an item is exportable.
|
||||
(incomplete, export_stable, "1.88.0", Some(139939)),
|
||||
/// Allows using `system` as a calling convention with varargs.
|
||||
(unstable, extern_system_varargs, "1.86.0", Some(136946)),
|
||||
/// Allows defining `extern type`s.
|
||||
(unstable, extern_types, "1.23.0", Some(43467)),
|
||||
/// Allow using 128-bit (quad precision) floating point numbers.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user