Auto merge of #100977 - JohnTitor:rollup-8hc7rxh, r=JohnTitor

Rollup of 8 pull requests

Successful merges:

 - #99332 (Stabilize `#![feature(label_break_value)]`)
 - #99954 (let-else: break out to one scope higher for let-else)
 - #100188 (Parser will not suggest invalid expression when use public)
 - #100780 (save_analysis: Migrate diagnostic)
 - #100808 (Migrate `rustc_interface` diagnostics )
 - #100921 (Add a warning about `Option/Result::and()` being eagerly evaluated)
 - #100960 (rustdoc: ayu code color selector more specific)
 - #100964 (Sync rustc_codegen_cranelift)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-08-25 02:32:11 +00:00
commit 9b9bc63599
110 changed files with 2658 additions and 1443 deletions

View File

@ -4421,9 +4421,11 @@ dependencies = [
"rustc_ast",
"rustc_ast_pretty",
"rustc_data_structures",
"rustc_errors",
"rustc_hir",
"rustc_hir_pretty",
"rustc_lexer",
"rustc_macros",
"rustc_middle",
"rustc_session",
"rustc_span",

View File

@ -13,7 +13,7 @@
#![feature(const_default_impls)]
#![feature(const_trait_impl)]
#![feature(if_let_guard)]
#![feature(label_break_value)]
#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(min_specialization)]
#![feature(negative_impls)]
#![feature(slice_internals)]

View File

@ -647,14 +647,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::ExprKind::TryBlock(_) => {
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
}
ast::ExprKind::Block(_, Some(label)) => {
gate_feature_post!(
&self,
label_break_value,
label.ident.span,
"labels on blocks are unstable"
);
}
_ => {}
}
visit::walk_expr(self, e)
@ -823,7 +815,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(box_patterns, "box pattern syntax is experimental");
gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
gate_all!(try_blocks, "`try` blocks are unstable");
gate_all!(label_break_value, "labels on blocks are unstable");
gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
gate_all!(type_ascription, "type ascription is experimental");

View File

@ -22,4 +22,4 @@ task:
- # Reduce amount of benchmark runs as they are slow
- export COMPILE_RUNS=2
- export RUN_RUNS=2
- ./test.sh
- ./y.rs test

View File

@ -103,7 +103,7 @@ jobs:
# Enable extra checks
export CG_CLIF_ENABLE_VERIFIER=1
./test.sh
./y.rs test
- name: Package prebuilt cg_clif
run: tar cvfJ cg_clif.tar.xz build
@ -162,14 +162,14 @@ jobs:
#name: Test
run: |
# Enable backtraces for easier debugging
#export RUST_BACKTRACE=1
#$Env:RUST_BACKTRACE=1
# Reduce amount of benchmark runs as they are slow
#export COMPILE_RUNS=2
#export RUN_RUNS=2
#$Env:COMPILE_RUNS=2
#$Env:RUN_RUNS=2
# Enable extra checks
#export CG_CLIF_ENABLE_VERIFIER=1
#$Env:CG_CLIF_ENABLE_VERIFIER=1
./y.exe build

View File

@ -8,6 +8,8 @@ perf.data.old
*.string*
/y.bin
/y.bin.dSYM
/y.exe
/y.pdb
/build
/build_sysroot/sysroot_src
/build_sysroot/compiler-builtins
@ -17,3 +19,4 @@ perf.data.old
/regex
/simple-raytracer
/portable-simd
/abi-checker

View File

@ -50,18 +50,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift-bforest"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "749d0d6022c9038dccf480bdde2a38d435937335bf2bb0f14e815d94517cdce8"
checksum = "93945adbccc8d731503d3038814a51e8317497c9e205411820348132fa01a358"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e94370cc7b37bf652ccd8bb8f09bd900997f7ccf97520edfc75554bb5c4abbea"
checksum = "2b482acc9d0d0d1ad3288a90a8150ee648be3dce8dc8c8669ff026f72debdc31"
dependencies = [
"cranelift-bforest",
"cranelift-codegen-meta",
@ -77,30 +77,30 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a3cea8fdab90e44018c5b9a1dfd460d8ee265ac354337150222a354628bdb6"
checksum = "f9ec188d71e663192ef9048f204e410a7283b609942efc9fcc77da6d496edbb8"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ac72f76f2698598951ab26d8c96eaa854810e693e7dd52523958b5909fde6b2"
checksum = "3ad794b1b1c2c7bd9f7b76cfe0f084eaf7753e55d56191c3f7d89e8fa4978b99"
[[package]]
name = "cranelift-entity"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09eaeacfcd2356fe0e66b295e8f9d59fdd1ac3ace53ba50de14d628ec902f72d"
checksum = "342da0d5056f4119d3c311c4aab2460ceb6ee6e127bb395b76dd2279a09ea7a5"
[[package]]
name = "cranelift-frontend"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dba69c9980d5ffd62c18a2bde927855fcd7c8dc92f29feaf8636052662cbd99c"
checksum = "dfff792f775b07d4d9cfe9f1c767ce755c6cbadda1bbd6db18a1c75ff9f7376a"
dependencies = [
"cranelift-codegen",
"log",
@ -110,15 +110,15 @@ dependencies = [
[[package]]
name = "cranelift-isle"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2920dc1e05cac40304456ed3301fde2c09bd6a9b0210bcfa2f101398d628d5b"
checksum = "8d51089478849f2ac8ef60a8a2d5346c8d4abfec0e45ac5b24530ef9f9499e1e"
[[package]]
name = "cranelift-jit"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c3c5ed067f2c81577e431f3039148a9c187b33cc79e0d1731fede27d801ec56"
checksum = "095936e41720f86004b4c57ce88e6a13af28646bb3a6fb4afbebd5ae90c50029"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -129,14 +129,14 @@ dependencies = [
"log",
"region",
"target-lexicon",
"winapi",
"windows-sys",
]
[[package]]
name = "cranelift-module"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eee6784303bf9af235237a4885f7417e09a35df896d38ea969a0081064b3ede4"
checksum = "704a1aea4723d97eafe0fb7af110f6f6868b1ac95f5380bbc9adb2a3b8cf97e8"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -144,9 +144,9 @@ dependencies = [
[[package]]
name = "cranelift-native"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f04dfa45f9b2a6f587c564d6b63388e00cd6589d2df6ea2758cf79e1a13285e6"
checksum = "885debe62f2078638d6585f54c9f05f5c2008f22ce5a2a9100ada785fc065dbd"
dependencies = [
"cranelift-codegen",
"libc",
@ -155,9 +155,9 @@ dependencies = [
[[package]]
name = "cranelift-object"
version = "0.85.3"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf38b2c505db749276793116c0cb30bd096206c7810e471677a453134881881"
checksum = "aac1310cf1081ae8eca916c92cd163b977c77cab6e831fa812273c26ff921816"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -187,9 +187,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
"cfg-if",
"libc",
@ -198,27 +198,21 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.26.1"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
dependencies = [
"indexmap",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash",
]
[[package]]
name = "indexmap"
@ -227,14 +221,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
"hashbrown",
]
[[package]]
name = "libc"
version = "0.2.126"
version = "0.2.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
[[package]]
name = "libloading"
@ -248,9 +242,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.14"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
@ -266,33 +260,33 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.4.1"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "object"
version = "0.28.4"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
dependencies = [
"crc32fast",
"hashbrown 0.11.2",
"hashbrown",
"indexmap",
"memchr",
]
[[package]]
name = "once_cell"
version = "1.10.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "regalloc2"
version = "0.2.3"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a8d23b35d7177df3b9d31ed8a9ab4bf625c668be77a319d4f5efd4a5257701c"
checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779"
dependencies = [
"fxhash",
"log",
@ -340,15 +334,15 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec"
[[package]]
name = "smallvec"
version = "1.8.1"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
[[package]]
name = "target-lexicon"
version = "0.12.3"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1"
checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1"
[[package]]
name = "version_check"
@ -358,9 +352,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
@ -383,3 +377,46 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"

View File

@ -8,15 +8,15 @@ crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
cranelift-codegen = { version = "0.85.3", features = ["unwind", "all-arch"] }
cranelift-frontend = "0.85.3"
cranelift-module = "0.85.3"
cranelift-native = "0.85.3"
cranelift-jit = { version = "0.85.3", optional = true }
cranelift-object = "0.85.3"
cranelift-codegen = { version = "0.87.0", features = ["unwind", "all-arch"] }
cranelift-frontend = "0.87.0"
cranelift-module = "0.87.0"
cranelift-native = "0.87.0"
cranelift-jit = { version = "0.87.0", optional = true }
cranelift-object = "0.87.0"
target-lexicon = "0.12.0"
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
object = { version = "0.28.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
indexmap = "1.9.1"

View File

@ -52,9 +52,7 @@ configuration options.
## Not yet supported
* Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041))
* On Linux there is support for invoking an external assembler for `global_asm!` and `asm!`.
`llvm_asm!` will remain unimplemented forever. `asm!` doesn't yet support reg classes. You
have to specify specific registers instead.
* On UNIX there is support for invoking an external assembler for `global_asm!` and `asm!`.
* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), some basic things work)
## License

View File

@ -56,9 +56,9 @@ dependencies = [
[[package]]
name = "compiler_builtins"
version = "0.1.75"
version = "0.1.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6e3183e88f659a862835db8f4b67dbeed3d93e44dd4927eef78edb1c149d784"
checksum = "4f873ce2bd3550b0b565f878b3d04ea8253f4259dc3d20223af2e1ba86f5ecca"
dependencies = [
"rustc-std-workspace-core",
]
@ -69,9 +69,9 @@ version = "0.0.0"
[[package]]
name = "dlmalloc"
version = "0.2.3"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6fe28e0bf9357092740362502f5cc7955d8dc125ebda71dec72336c2e15c62e"
checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a"
dependencies = [
"compiler_builtins",
"libc",
@ -80,9 +80,9 @@ dependencies = [
[[package]]
name = "fortanix-sgx-abi"
version = "0.3.3"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c56c422ef86062869b2d57ae87270608dc5929969dd130a6e248979cf4fb6ca6"
checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
@ -123,9 +123,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.2.4"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7668753748e445859e4e373c3d41117235d9feed578392f5a3a73efdc751ca4a"
checksum = "897cd85af6387be149f55acf168e41be176a02de7872403aaab184afc2f327e6"
dependencies = [
"compiler_builtins",
"libc",
@ -135,9 +135,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.126"
version = "0.2.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
dependencies = [
"rustc-std-workspace-core",
]

View File

@ -0,0 +1,60 @@
use super::build_sysroot;
use super::config;
use super::utils::spawn_and_wait;
use build_system::SysrootKind;
use std::env;
use std::path::Path;
use std::process::Command;
pub(crate) fn run(
channel: &str,
sysroot_kind: SysrootKind,
target_dir: &Path,
cg_clif_build_dir: &Path,
host_triple: &str,
target_triple: &str,
) {
if !config::get_bool("testsuite.abi-checker") {
eprintln!("[SKIP] abi-checker");
return;
}
if host_triple != target_triple {
eprintln!("[SKIP] abi-checker (cross-compilation not supported)");
return;
}
eprintln!("Building sysroot for abi-checker");
build_sysroot::build_sysroot(
channel,
sysroot_kind,
target_dir,
cg_clif_build_dir,
host_triple,
target_triple,
);
eprintln!("Running abi-checker");
let mut abi_checker_path = env::current_dir().unwrap();
abi_checker_path.push("abi-checker");
env::set_current_dir(abi_checker_path.clone()).unwrap();
let build_dir = abi_checker_path.parent().unwrap().join("build");
let cg_clif_dylib_path = build_dir.join(if cfg!(windows) { "bin" } else { "lib" }).join(
env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
);
let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
let mut cmd = Command::new("cargo");
cmd.arg("run");
cmd.arg("--target");
cmd.arg(target_triple);
cmd.arg("--");
cmd.arg("--pairs");
cmd.args(pairs);
cmd.arg("--add-rustc-codegen-backend");
cmd.arg(format!("cgclif:{}", cg_clif_dylib_path.display()));
spawn_and_wait(cmd);
}

View File

@ -2,6 +2,8 @@ use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use super::utils::is_ci;
pub(crate) fn build_backend(
channel: &str,
host_triple: &str,
@ -14,7 +16,7 @@ pub(crate) fn build_backend(
let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default();
if env::var("CI").as_ref().map(|val| &**val) == Ok("true") {
if is_ci() {
// Deny warnings on CI
rustflags += " -Dwarnings";

View File

@ -2,7 +2,7 @@ use std::fs;
use std::path::{Path, PathBuf};
use std::process::{self, Command};
use super::rustc_info::{get_file_name, get_rustc_version};
use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name};
use super::utils::{spawn_and_wait, try_hard_link};
use super::SysrootKind;
@ -10,10 +10,12 @@ pub(crate) fn build_sysroot(
channel: &str,
sysroot_kind: SysrootKind,
target_dir: &Path,
cg_clif_build_dir: PathBuf,
cg_clif_build_dir: &Path,
host_triple: &str,
target_triple: &str,
) {
eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
if target_dir.exists() {
fs::remove_dir_all(target_dir).unwrap();
}
@ -35,11 +37,13 @@ pub(crate) fn build_sysroot(
// Build and copy rustc and cargo wrappers
for wrapper in ["rustc-clif", "cargo-clif"] {
let wrapper_name = get_wrapper_file_name(wrapper, "bin");
let mut build_cargo_wrapper_cmd = Command::new("rustc");
build_cargo_wrapper_cmd
.arg(PathBuf::from("scripts").join(format!("{wrapper}.rs")))
.arg("-o")
.arg(target_dir.join(wrapper))
.arg(target_dir.join(wrapper_name))
.arg("-g");
spawn_and_wait(build_cargo_wrapper_cmd);
}

View File

@ -2,11 +2,15 @@ use std::env;
use std::path::PathBuf;
use std::process;
use self::utils::is_ci;
mod abi_checker;
mod build_backend;
mod build_sysroot;
mod config;
mod prepare;
mod rustc_info;
mod tests;
mod utils;
fn usage() {
@ -15,6 +19,9 @@ fn usage() {
eprintln!(
" ./y.rs build [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
);
eprintln!(
" ./y.rs test [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
);
}
macro_rules! arg_error {
@ -25,11 +32,13 @@ macro_rules! arg_error {
}};
}
#[derive(PartialEq, Debug)]
enum Command {
Build,
Test,
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub(crate) enum SysrootKind {
None,
Clif,
@ -42,16 +51,22 @@ pub fn main() {
// The target dir is expected in the default location. Guard against the user changing it.
env::set_var("CARGO_TARGET_DIR", "target");
if is_ci() {
// Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
env::set_var("CARGO_BUILD_INCREMENTAL", "false");
}
let mut args = env::args().skip(1);
let command = match args.next().as_deref() {
Some("prepare") => {
if args.next().is_some() {
arg_error!("./x.rs prepare doesn't expect arguments");
arg_error!("./y.rs prepare doesn't expect arguments");
}
prepare::prepare();
process::exit(0);
}
Some("build") => Command::Build,
Some("test") => Command::Test,
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
Some(command) => arg_error!("Unknown command {}", command),
None => {
@ -117,12 +132,35 @@ pub fn main() {
let cg_clif_build_dir =
build_backend::build_backend(channel, &host_triple, use_unstable_features);
build_sysroot::build_sysroot(
channel,
sysroot_kind,
&target_dir,
cg_clif_build_dir,
&host_triple,
&target_triple,
);
match command {
Command::Test => {
tests::run_tests(
channel,
sysroot_kind,
&target_dir,
&cg_clif_build_dir,
&host_triple,
&target_triple,
);
abi_checker::run(
channel,
sysroot_kind,
&target_dir,
&cg_clif_build_dir,
&host_triple,
&target_triple,
);
}
Command::Build => {
build_sysroot::build_sysroot(
channel,
sysroot_kind,
&target_dir,
&cg_clif_build_dir,
&host_triple,
&target_triple,
);
}
}
}

View File

@ -14,6 +14,14 @@ pub(crate) fn prepare() {
eprintln!("[INSTALL] hyperfine");
Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
clone_repo_shallow_github(
"abi-checker",
"Gankra",
"abi-checker",
"a2232d45f202846f5c02203c9f27355360f9a2ff",
);
apply_patches("abi-checker", Path::new("abi-checker"));
clone_repo_shallow_github(
"rand",
"rust-random",
@ -50,8 +58,7 @@ pub(crate) fn prepare() {
spawn_and_wait(build_cmd);
fs::copy(
Path::new("simple-raytracer/target/debug").join(get_file_name("main", "bin")),
// FIXME use get_file_name here too once testing is migrated to rust
"simple-raytracer/raytracer_cg_llvm",
Path::new("simple-raytracer").join(get_file_name("raytracer_cg_llvm", "bin")),
)
.unwrap();
}

View File

@ -63,3 +63,12 @@ pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String {
assert!(file_name.contains(crate_name));
file_name
}
/// Similar to `get_file_name`, but converts any dashes (`-`) in the `crate_name` to
/// underscores (`_`). This is specially made for the the rustc and cargo wrappers
/// which have a dash in the name, and that is not allowed in a crate name.
pub(crate) fn get_wrapper_file_name(crate_name: &str, crate_type: &str) -> String {
let crate_name = crate_name.replace('-', "_");
let wrapper_name = get_file_name(&crate_name, crate_type);
wrapper_name.replace('_', "-")
}

View File

@ -0,0 +1,619 @@
use super::build_sysroot;
use super::config;
use super::rustc_info::get_wrapper_file_name;
use super::utils::{spawn_and_wait, spawn_and_wait_with_input};
use build_system::SysrootKind;
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
struct TestCase {
config: &'static str,
func: &'static dyn Fn(&TestRunner),
}
impl TestCase {
const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
Self { config, func }
}
}
const NO_SYSROOT_SUITE: &[TestCase] = &[
TestCase::new("build.mini_core", &|runner| {
runner.run_rustc([
"example/mini_core.rs",
"--crate-name",
"mini_core",
"--crate-type",
"lib,dylib",
"--target",
&runner.target_triple,
]);
}),
TestCase::new("build.example", &|runner| {
runner.run_rustc([
"example/example.rs",
"--crate-type",
"lib",
"--target",
&runner.target_triple,
]);
}),
TestCase::new("jit.mini_core_hello_world", &|runner| {
let mut jit_cmd = runner.rustc_command([
"-Zunstable-options",
"-Cllvm-args=mode=jit",
"-Cprefer-dynamic",
"example/mini_core_hello_world.rs",
"--cfg",
"jit",
"--target",
&runner.host_triple,
]);
jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
spawn_and_wait(jit_cmd);
eprintln!("[JIT-lazy] mini_core_hello_world");
let mut jit_cmd = runner.rustc_command([
"-Zunstable-options",
"-Cllvm-args=mode=jit-lazy",
"-Cprefer-dynamic",
"example/mini_core_hello_world.rs",
"--cfg",
"jit",
"--target",
&runner.host_triple,
]);
jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
spawn_and_wait(jit_cmd);
}),
TestCase::new("aot.mini_core_hello_world", &|runner| {
runner.run_rustc([
"example/mini_core_hello_world.rs",
"--crate-name",
"mini_core_hello_world",
"--crate-type",
"bin",
"-g",
"--target",
&runner.target_triple,
]);
runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]);
}),
];
const BASE_SYSROOT_SUITE: &[TestCase] = &[
TestCase::new("aot.arbitrary_self_types_pointers_and_wrappers", &|runner| {
runner.run_rustc([
"example/arbitrary_self_types_pointers_and_wrappers.rs",
"--crate-name",
"arbitrary_self_types_pointers_and_wrappers",
"--crate-type",
"bin",
"--target",
&runner.target_triple,
]);
runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []);
}),
TestCase::new("aot.issue_91827_extern_types", &|runner| {
runner.run_rustc([
"example/issue-91827-extern-types.rs",
"--crate-name",
"issue_91827_extern_types",
"--crate-type",
"bin",
"--target",
&runner.target_triple,
]);
runner.run_out_command("issue_91827_extern_types", []);
}),
TestCase::new("build.alloc_system", &|runner| {
runner.run_rustc([
"example/alloc_system.rs",
"--crate-type",
"lib",
"--target",
&runner.target_triple,
]);
}),
TestCase::new("aot.alloc_example", &|runner| {
runner.run_rustc([
"example/alloc_example.rs",
"--crate-type",
"bin",
"--target",
&runner.target_triple,
]);
runner.run_out_command("alloc_example", []);
}),
TestCase::new("jit.std_example", &|runner| {
runner.run_rustc([
"-Zunstable-options",
"-Cllvm-args=mode=jit",
"-Cprefer-dynamic",
"example/std_example.rs",
"--target",
&runner.host_triple,
]);
eprintln!("[JIT-lazy] std_example");
runner.run_rustc([
"-Zunstable-options",
"-Cllvm-args=mode=jit-lazy",
"-Cprefer-dynamic",
"example/std_example.rs",
"--target",
&runner.host_triple,
]);
}),
TestCase::new("aot.std_example", &|runner| {
runner.run_rustc([
"example/std_example.rs",
"--crate-type",
"bin",
"--target",
&runner.target_triple,
]);
runner.run_out_command("std_example", ["arg"]);
}),
TestCase::new("aot.dst_field_align", &|runner| {
runner.run_rustc([
"example/dst-field-align.rs",
"--crate-name",
"dst_field_align",
"--crate-type",
"bin",
"--target",
&runner.target_triple,
]);
runner.run_out_command("dst_field_align", []);
}),
TestCase::new("aot.subslice-patterns-const-eval", &|runner| {
runner.run_rustc([
"example/subslice-patterns-const-eval.rs",
"--crate-type",
"bin",
"-Cpanic=abort",
"--target",
&runner.target_triple,
]);
runner.run_out_command("subslice-patterns-const-eval", []);
}),
TestCase::new("aot.track-caller-attribute", &|runner| {
runner.run_rustc([
"example/track-caller-attribute.rs",
"--crate-type",
"bin",
"-Cpanic=abort",
"--target",
&runner.target_triple,
]);
runner.run_out_command("track-caller-attribute", []);
}),
TestCase::new("aot.float-minmax-pass", &|runner| {
runner.run_rustc([
"example/float-minmax-pass.rs",
"--crate-type",
"bin",
"-Cpanic=abort",
"--target",
&runner.target_triple,
]);
runner.run_out_command("float-minmax-pass", []);
}),
TestCase::new("aot.mod_bench", &|runner| {
runner.run_rustc([
"example/mod_bench.rs",
"--crate-type",
"bin",
"--target",
&runner.target_triple,
]);
runner.run_out_command("mod_bench", []);
}),
];
const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
TestCase::new("test.rust-random/rand", &|runner| {
runner.in_dir(["rand"], |runner| {
runner.run_cargo(["clean"]);
if runner.host_triple == runner.target_triple {
eprintln!("[TEST] rust-random/rand");
runner.run_cargo(["test", "--workspace"]);
} else {
eprintln!("[AOT] rust-random/rand");
runner.run_cargo([
"build",
"--workspace",
"--target",
&runner.target_triple,
"--tests",
]);
}
});
}),
TestCase::new("bench.simple-raytracer", &|runner| {
runner.in_dir(["simple-raytracer"], |runner| {
let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string());
if runner.host_triple == runner.target_triple {
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
let mut bench_compile = Command::new("hyperfine");
bench_compile.arg("--runs");
bench_compile.arg(&run_runs);
bench_compile.arg("--warmup");
bench_compile.arg("1");
bench_compile.arg("--prepare");
bench_compile.arg(format!("{:?}", runner.cargo_command(["clean"])));
if cfg!(windows) {
bench_compile.arg("cmd /C \"set RUSTFLAGS= && cargo build\"");
} else {
bench_compile.arg("RUSTFLAGS='' cargo build");
}
bench_compile.arg(format!("{:?}", runner.cargo_command(["build"])));
spawn_and_wait(bench_compile);
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif"))
.unwrap();
let mut bench_run = Command::new("hyperfine");
bench_run.arg("--runs");
bench_run.arg(&run_runs);
bench_run.arg(PathBuf::from("./raytracer_cg_llvm"));
bench_run.arg(PathBuf::from("./raytracer_cg_clif"));
spawn_and_wait(bench_run);
} else {
runner.run_cargo(["clean"]);
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
eprintln!("[COMPILE] ebobby/simple-raytracer");
runner.run_cargo(["build", "--target", &runner.target_triple]);
eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
}
});
}),
TestCase::new("test.libcore", &|runner| {
runner.in_dir(["build_sysroot", "sysroot_src", "library", "core", "tests"], |runner| {
runner.run_cargo(["clean"]);
if runner.host_triple == runner.target_triple {
runner.run_cargo(["test"]);
} else {
eprintln!("Cross-Compiling: Not running tests");
runner.run_cargo(["build", "--target", &runner.target_triple, "--tests"]);
}
});
}),
TestCase::new("test.regex-shootout-regex-dna", &|runner| {
runner.in_dir(["regex"], |runner| {
runner.run_cargo(["clean"]);
// newer aho_corasick versions throw a deprecation warning
let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
let mut build_cmd = runner.cargo_command([
"build",
"--example",
"shootout-regex-dna",
"--target",
&runner.target_triple,
]);
build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
spawn_and_wait(build_cmd);
if runner.host_triple == runner.target_triple {
let mut run_cmd = runner.cargo_command([
"run",
"--example",
"shootout-regex-dna",
"--target",
&runner.target_triple,
]);
run_cmd.env("RUSTFLAGS", lint_rust_flags);
let input =
fs::read_to_string(PathBuf::from("examples/regexdna-input.txt")).unwrap();
let expected_path = PathBuf::from("examples/regexdna-output.txt");
let expected = fs::read_to_string(&expected_path).unwrap();
let output = spawn_and_wait_with_input(run_cmd, input);
// Make sure `[codegen mono items] start` doesn't poison the diff
let output = output
.lines()
.filter(|line| !line.contains("codegen mono items"))
.chain(Some("")) // This just adds the trailing newline
.collect::<Vec<&str>>()
.join("\r\n");
let output_matches = expected.lines().eq(output.lines());
if !output_matches {
let res_path = PathBuf::from("res.txt");
fs::write(&res_path, &output).unwrap();
if cfg!(windows) {
println!("Output files don't match!");
println!("Expected Output:\n{}", expected);
println!("Actual Output:\n{}", output);
} else {
let mut diff = Command::new("diff");
diff.arg("-u");
diff.arg(res_path);
diff.arg(expected_path);
spawn_and_wait(diff);
}
std::process::exit(1);
}
}
});
}),
TestCase::new("test.regex", &|runner| {
runner.in_dir(["regex"], |runner| {
runner.run_cargo(["clean"]);
// newer aho_corasick versions throw a deprecation warning
let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
if runner.host_triple == runner.target_triple {
let mut run_cmd = runner.cargo_command([
"test",
"--tests",
"--",
"--exclude-should-panic",
"--test-threads",
"1",
"-Zunstable-options",
"-q",
]);
run_cmd.env("RUSTFLAGS", lint_rust_flags);
spawn_and_wait(run_cmd);
} else {
eprintln!("Cross-Compiling: Not running tests");
let mut build_cmd =
runner.cargo_command(["build", "--tests", "--target", &runner.target_triple]);
build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
spawn_and_wait(build_cmd);
}
});
}),
TestCase::new("test.portable-simd", &|runner| {
runner.in_dir(["portable-simd"], |runner| {
runner.run_cargo(["clean"]);
runner.run_cargo(["build", "--all-targets", "--target", &runner.target_triple]);
if runner.host_triple == runner.target_triple {
runner.run_cargo(["test", "-q"]);
}
});
}),
];
pub(crate) fn run_tests(
channel: &str,
sysroot_kind: SysrootKind,
target_dir: &Path,
cg_clif_build_dir: &Path,
host_triple: &str,
target_triple: &str,
) {
let runner = TestRunner::new(host_triple.to_string(), target_triple.to_string());
if config::get_bool("testsuite.no_sysroot") {
build_sysroot::build_sysroot(
channel,
SysrootKind::None,
&target_dir,
cg_clif_build_dir,
&host_triple,
&target_triple,
);
let _ = fs::remove_dir_all(Path::new("target").join("out"));
runner.run_testsuite(NO_SYSROOT_SUITE);
} else {
eprintln!("[SKIP] no_sysroot tests");
}
let run_base_sysroot = config::get_bool("testsuite.base_sysroot");
let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot");
if run_base_sysroot || run_extended_sysroot {
build_sysroot::build_sysroot(
channel,
sysroot_kind,
&target_dir,
cg_clif_build_dir,
&host_triple,
&target_triple,
);
}
if run_base_sysroot {
runner.run_testsuite(BASE_SYSROOT_SUITE);
} else {
eprintln!("[SKIP] base_sysroot tests");
}
if run_extended_sysroot {
runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
} else {
eprintln!("[SKIP] extended_sysroot tests");
}
}
struct TestRunner {
root_dir: PathBuf,
out_dir: PathBuf,
jit_supported: bool,
rust_flags: String,
run_wrapper: Vec<String>,
host_triple: String,
target_triple: String,
}
impl TestRunner {
pub fn new(host_triple: String, target_triple: String) -> Self {
let root_dir = env::current_dir().unwrap();
let mut out_dir = root_dir.clone();
out_dir.push("target");
out_dir.push("out");
let is_native = host_triple == target_triple;
let jit_supported =
target_triple.contains("x86_64") && is_native && !host_triple.contains("windows");
let mut rust_flags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
let mut run_wrapper = Vec::new();
if !is_native {
match target_triple.as_str() {
"aarch64-unknown-linux-gnu" => {
// We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
rust_flags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rust_flags);
run_wrapper = vec!["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"];
}
"x86_64-pc-windows-gnu" => {
// We are cross-compiling for Windows. Run tests in wine.
run_wrapper = vec!["wine"];
}
_ => {
println!("Unknown non-native platform");
}
}
}
// FIXME fix `#[linkage = "extern_weak"]` without this
if host_triple.contains("darwin") {
rust_flags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rust_flags);
}
Self {
root_dir,
out_dir,
jit_supported,
rust_flags,
run_wrapper: run_wrapper.iter().map(|s| s.to_string()).collect(),
host_triple,
target_triple,
}
}
pub fn run_testsuite(&self, tests: &[TestCase]) {
for &TestCase { config, func } in tests {
let (tag, testname) = config.split_once('.').unwrap();
let tag = tag.to_uppercase();
let is_jit_test = tag == "JIT";
if !config::get_bool(config) || (is_jit_test && !self.jit_supported) {
eprintln!("[{tag}] {testname} (skipped)");
continue;
} else {
eprintln!("[{tag}] {testname}");
}
func(self);
}
}
fn in_dir<'a, I, F>(&self, dir: I, callback: F)
where
I: IntoIterator<Item = &'a str>,
F: FnOnce(&TestRunner),
{
let current = env::current_dir().unwrap();
let mut new = current.clone();
for d in dir {
new.push(d);
}
env::set_current_dir(new).unwrap();
callback(self);
env::set_current_dir(current).unwrap();
}
fn rustc_command<I, S>(&self, args: I) -> Command
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
let mut rustc_clif = self.root_dir.clone();
rustc_clif.push("build");
rustc_clif.push(get_wrapper_file_name("rustc-clif", "bin"));
let mut cmd = Command::new(rustc_clif);
cmd.args(self.rust_flags.split_whitespace());
cmd.arg("-L");
cmd.arg(format!("crate={}", self.out_dir.display()));
cmd.arg("--out-dir");
cmd.arg(format!("{}", self.out_dir.display()));
cmd.arg("-Cdebuginfo=2");
cmd.args(args);
cmd
}
fn run_rustc<I, S>(&self, args: I)
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
spawn_and_wait(self.rustc_command(args));
}
fn run_out_command<'a, I>(&self, name: &str, args: I)
where
I: IntoIterator<Item = &'a str>,
{
let mut full_cmd = vec![];
// Prepend the RUN_WRAPPER's
if !self.run_wrapper.is_empty() {
full_cmd.extend(self.run_wrapper.iter().cloned());
}
full_cmd.push({
let mut out_path = self.out_dir.clone();
out_path.push(name);
out_path.to_str().unwrap().to_string()
});
for arg in args.into_iter() {
full_cmd.push(arg.to_string());
}
let mut cmd_iter = full_cmd.into_iter();
let first = cmd_iter.next().unwrap();
let mut cmd = Command::new(first);
cmd.args(cmd_iter);
spawn_and_wait(cmd);
}
fn cargo_command<I, S>(&self, args: I) -> Command
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
let mut cargo_clif = self.root_dir.clone();
cargo_clif.push("build");
cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin"));
let mut cmd = Command::new(cargo_clif);
cmd.args(args);
cmd.env("RUSTFLAGS", &self.rust_flags);
cmd
}
fn run_cargo<'a, I>(&self, args: I)
where
I: IntoIterator<Item = &'a str>,
{
spawn_and_wait(self.cargo_command(args));
}
}

View File

@ -1,6 +1,8 @@
use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;
use std::process::{self, Command};
use std::process::{self, Command, Stdio};
#[track_caller]
pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
@ -18,6 +20,27 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) {
}
}
#[track_caller]
pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> String {
let mut child = cmd
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("Failed to spawn child process");
let mut stdin = child.stdin.take().expect("Failed to open stdin");
std::thread::spawn(move || {
stdin.write_all(input.as_bytes()).expect("Failed to write to stdin");
});
let output = child.wait_with_output().expect("Failed to read stdout");
if !output.status.success() {
process::exit(1);
}
String::from_utf8(output.stdout).unwrap()
}
pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) {
for entry in fs::read_dir(from).unwrap() {
let entry = entry.unwrap();
@ -33,3 +56,7 @@ pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) {
}
}
}
pub(crate) fn is_ci() -> bool {
env::var("CI").as_ref().map(|val| &**val) == Ok("true")
}

View File

@ -3,4 +3,4 @@ set -e
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
rm -rf target/ build/ perf.data{,.old} y.bin
rm -rf rand/ regex/ simple-raytracer/ portable-simd/
rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/

View File

@ -15,3 +15,38 @@
# This option can be changed while the build system is already running for as long as sysroot
# building hasn't started yet.
#keep_sysroot
# Testsuite
#
# Each test suite item has a corresponding key here. The default is to run all tests.
# Comment any of these lines to skip individual tests.
testsuite.no_sysroot
build.mini_core
build.example
jit.mini_core_hello_world
aot.mini_core_hello_world
testsuite.base_sysroot
aot.arbitrary_self_types_pointers_and_wrappers
aot.issue_91827_extern_types
build.alloc_system
aot.alloc_example
jit.std_example
aot.std_example
aot.dst_field_align
aot.subslice-patterns-const-eval
aot.track-caller-attribute
aot.float-minmax-pass
aot.mod_bench
testsuite.extended_sysroot
test.rust-random/rand
bench.simple-raytracer
test.libcore
test.regex-shootout-regex-dna
test.regex
test.portable-simd
testsuite.abi-checker

View File

@ -535,7 +535,7 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
}
#[lang = "box_free"]
unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, alloc: ()) {
unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, _alloc: ()) {
libc::free(ptr.pointer.0 as *mut u8);
}
@ -575,11 +575,19 @@ pub mod intrinsics {
}
pub mod libc {
// With the new Universal CRT, msvc has switched to all the printf functions being inline wrapper
// functions. legacy_stdio_definitions.lib which provides the printf wrapper functions as normal
// symbols to link against.
#[cfg_attr(unix, link(name = "c"))]
#[cfg_attr(target_env="msvc", link(name="legacy_stdio_definitions"))]
extern "C" {
pub fn printf(format: *const i8, ...) -> i32;
}
#[cfg_attr(unix, link(name = "c"))]
#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
extern "C" {
pub fn puts(s: *const i8) -> i32;
pub fn printf(format: *const i8, ...) -> i32;
pub fn malloc(size: usize) -> *mut u8;
pub fn free(ptr: *mut u8);
pub fn memcpy(dst: *mut u8, src: *const u8, size: usize);

View File

@ -139,7 +139,7 @@ pub struct bool_11 {
field10: bool,
}
extern "C" fn bool_struct_in_11(arg0: bool_11) {}
extern "C" fn bool_struct_in_11(_arg0: bool_11) {}
#[allow(unreachable_code)] // FIXME false positive
fn main() {
@ -321,7 +321,7 @@ fn main() {
#[cfg(not(any(jit, windows)))]
test_tls();
#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
#[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "darwin")))]
unsafe {
global_asm_test();
}
@ -343,7 +343,7 @@ fn main() {
}
}
#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
#[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "darwin")))]
extern "C" {
fn global_asm_test();
}
@ -358,6 +358,16 @@ global_asm! {
"
}
#[cfg(all(not(jit), target_arch = "x86_64", target_os = "darwin"))]
global_asm! {
"
.global _global_asm_test
_global_asm_test:
// comment that would normally be removed by LLVM
ret
"
}
#[repr(C)]
enum c_void {
_1,
@ -375,6 +385,7 @@ struct pthread_attr_t {
}
#[link(name = "pthread")]
#[cfg(unix)]
extern "C" {
fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int;
@ -391,6 +402,91 @@ extern "C" {
) -> c_int;
}
type DWORD = u32;
type LPDWORD = *mut u32;
type LPVOID = *mut c_void;
type HANDLE = *mut c_void;
#[link(name = "msvcrt")]
#[cfg(windows)]
extern "C" {
fn WaitForSingleObject(
hHandle: LPVOID,
dwMilliseconds: DWORD
) -> DWORD;
fn CreateThread(
lpThreadAttributes: LPVOID, // Technically LPSECURITY_ATTRIBUTES, but we don't use it anyway
dwStackSize: usize,
lpStartAddress: extern "C" fn(_: *mut c_void) -> *mut c_void,
lpParameter: LPVOID,
dwCreationFlags: DWORD,
lpThreadId: LPDWORD
) -> HANDLE;
}
struct Thread {
#[cfg(windows)]
handle: HANDLE,
#[cfg(unix)]
handle: pthread_t,
}
impl Thread {
unsafe fn create(f: extern "C" fn(_: *mut c_void) -> *mut c_void) -> Self {
#[cfg(unix)]
{
let mut attr: pthread_attr_t = zeroed();
let mut thread: pthread_t = 0;
if pthread_attr_init(&mut attr) != 0 {
assert!(false);
}
if pthread_create(&mut thread, &attr, f, 0 as *mut c_void) != 0 {
assert!(false);
}
Thread {
handle: thread,
}
}
#[cfg(windows)]
{
let handle = CreateThread(0 as *mut c_void, 0, f, 0 as *mut c_void, 0, 0 as *mut u32);
if (handle as u64) == 0 {
assert!(false);
}
Thread {
handle,
}
}
}
unsafe fn join(self) {
#[cfg(unix)]
{
let mut res = 0 as *mut c_void;
pthread_join(self.handle, &mut res);
}
#[cfg(windows)]
{
// The INFINITE macro is used to signal operations that do not timeout.
let infinite = 0xffffffff;
assert!(WaitForSingleObject(self.handle, infinite) == 0);
}
}
}
#[thread_local]
#[cfg(not(jit))]
static mut TLS: u8 = 42;
@ -404,21 +500,10 @@ extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void {
#[cfg(not(jit))]
fn test_tls() {
unsafe {
let mut attr: pthread_attr_t = zeroed();
let mut thread: pthread_t = 0;
assert_eq!(TLS, 42);
if pthread_attr_init(&mut attr) != 0 {
assert!(false);
}
if pthread_create(&mut thread, &attr, mutate_tls, 0 as *mut c_void) != 0 {
assert!(false);
}
let mut res = 0 as *mut c_void;
pthread_join(thread, &mut res);
let thread = Thread::create(mutate_tls);
thread.join();
// TLS of main thread must not have been changed by the other thread.
assert_eq!(TLS, 42);

View File

@ -0,0 +1,36 @@
From 1a315ba225577dbbd1f449d9609f16f984f68708 Mon Sep 17 00:00:00 2001
From: Afonso Bordado <afonso360@users.noreply.github.com>
Date: Fri, 12 Aug 2022 22:51:58 +0000
Subject: [PATCH] Disable abi-checker tests
---
src/report.rs | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/src/report.rs b/src/report.rs
index 7346f5e..8347762 100644
--- a/src/report.rs
+++ b/src/report.rs
@@ -45,6 +45,20 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl
//
// THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
+ // Currently MSVC has some broken ABI issues. Furthermore, they cause
+ // a STATUS_ACCESS_VIOLATION, so we can't even run them. Ensure that they compile and link.
+ if cfg!(windows) && (test.test_name == "bool" || test.test_name == "ui128") {
+ result.run = Link;
+ result.check = Pass(Link);
+ }
+
+ // structs is broken in the current release of cranelift for aarch64.
+ // It has been fixed for cranelift 0.88: https://github.com/bytecodealliance/wasmtime/pull/4634
+ if cfg!(target_arch = "aarch64") && test.test_name == "structs" {
+ result.run = Link;
+ result.check = Pass(Link);
+ }
+
// END OF VENDOR RESERVED AREA
//
//
--
2.34.1

View File

@ -46,5 +46,17 @@ index 4bc44e9..8e3c7a4 100644
#[test]
fn cell_allows_array_cycle() {
diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
index 13b12db..96fe4b9 100644
--- a/library/core/tests/atomic.rs
+++ b/library/core/tests/atomic.rs
@@ -185,6 +185,7 @@ fn ptr_bitops() {
}
#[test]
+#[cfg_attr(target_arch = "s390x", ignore)] // s390x backend doesn't support stack alignment >8 bytes
#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
fn ptr_bitops_tagging() {
#[repr(align(16))]
--
2.21.0 (Apple Git-122)

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2022-07-25"
channel = "nightly-2022-08-24"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View File

@ -1,203 +0,0 @@
#!/usr/bin/env bash
set -e
export CG_CLIF_DISPLAY_CG_TIME=1
export CG_CLIF_DISABLE_INCR_CACHE=1
export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
export RUN_WRAPPER=''
case "$TARGET_TRIPLE" in
x86_64*)
export JIT_SUPPORTED=1
;;
*)
export JIT_SUPPORTED=0
;;
esac
if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
export JIT_SUPPORTED=0
if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
# We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS
export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
# We are cross-compiling for Windows. Run tests in wine.
export RUN_WRAPPER='wine'
else
echo "Unknown non-native platform"
fi
fi
# FIXME fix `#[linkage = "extern_weak"]` without this
if [[ "$(uname)" == 'Darwin' ]]; then
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
fi
MY_RUSTC="$(pwd)/build/rustc-clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2"
function no_sysroot_tests() {
echo "[BUILD] mini_core"
$MY_RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target "$TARGET_TRIPLE"
echo "[BUILD] example"
$MY_RUSTC example/example.rs --crate-type lib --target "$TARGET_TRIPLE"
if [[ "$JIT_SUPPORTED" = "1" ]]; then
echo "[JIT] mini_core_hello_world"
CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
echo "[JIT-lazy] mini_core_hello_world"
CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
else
echo "[JIT] mini_core_hello_world (skipped)"
fi
echo "[AOT] mini_core_hello_world"
$MY_RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd
# (echo "break set -n main"; echo "run"; sleep 1; echo "si -c 10"; sleep 1; echo "frame variable") | lldb -- ./target/out/mini_core_hello_world abc bcd
}
function base_sysroot_tests() {
echo "[AOT] arbitrary_self_types_pointers_and_wrappers"
$MY_RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers
echo "[AOT] issue_91827_extern_types"
$MY_RUSTC example/issue-91827-extern-types.rs --crate-name issue_91827_extern_types --crate-type bin --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/issue_91827_extern_types
echo "[BUILD] alloc_system"
$MY_RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE"
echo "[AOT] alloc_example"
$MY_RUSTC example/alloc_example.rs --crate-type bin --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/alloc_example
if [[ "$JIT_SUPPORTED" = "1" ]]; then
echo "[JIT] std_example"
$MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
echo "[JIT-lazy] std_example"
$MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
else
echo "[JIT] std_example (skipped)"
fi
echo "[AOT] std_example"
$MY_RUSTC example/std_example.rs --crate-type bin --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/std_example arg
echo "[AOT] dst_field_align"
$MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/dst_field_align
echo "[AOT] subslice-patterns-const-eval"
$MY_RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/subslice-patterns-const-eval
echo "[AOT] track-caller-attribute"
$MY_RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/track-caller-attribute
echo "[AOT] float-minmax-pass"
$MY_RUSTC example/float-minmax-pass.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/float-minmax-pass
echo "[AOT] mod_bench"
$MY_RUSTC example/mod_bench.rs --crate-type bin --target "$TARGET_TRIPLE"
$RUN_WRAPPER ./target/out/mod_bench
}
function extended_sysroot_tests() {
pushd rand
../build/cargo-clif clean
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
echo "[TEST] rust-random/rand"
../build/cargo-clif test --workspace
else
echo "[AOT] rust-random/rand"
../build/cargo-clif build --workspace --target $TARGET_TRIPLE --tests
fi
popd
pushd simple-raytracer
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
echo "[BENCH COMPILE] ebobby/simple-raytracer"
hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo-clif clean" \
"RUSTFLAGS='' cargo build" \
"../build/cargo-clif build"
echo "[BENCH RUN] ebobby/simple-raytracer"
cp ./target/debug/main ./raytracer_cg_clif
hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_clif
else
../build/cargo-clif clean
echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
echo "[COMPILE] ebobby/simple-raytracer"
../build/cargo-clif build --target $TARGET_TRIPLE
echo "[BENCH RUN] ebobby/simple-raytracer (skipped)"
fi
popd
pushd build_sysroot/sysroot_src/library/core/tests
echo "[TEST] libcore"
../../../../../build/cargo-clif clean
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
../../../../../build/cargo-clif test
else
../../../../../build/cargo-clif build --target $TARGET_TRIPLE --tests
fi
popd
pushd regex
echo "[TEST] rust-lang/regex example shootout-regex-dna"
../build/cargo-clif clean
export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning
# Make sure `[codegen mono items] start` doesn't poison the diff
../build/cargo-clif build --example shootout-regex-dna --target $TARGET_TRIPLE
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
cat examples/regexdna-input.txt \
| ../build/cargo-clif run --example shootout-regex-dna --target $TARGET_TRIPLE \
| grep -v "Spawned thread" > res.txt
diff -u res.txt examples/regexdna-output.txt
fi
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
echo "[TEST] rust-lang/regex tests"
../build/cargo-clif test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
else
echo "[AOT] rust-lang/regex tests"
../build/cargo-clif build --tests --target $TARGET_TRIPLE
fi
popd
pushd portable-simd
echo "[TEST] rust-lang/portable-simd"
../build/cargo-clif clean
../build/cargo-clif build --all-targets --target $TARGET_TRIPLE
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
../build/cargo-clif test -q
fi
popd
}
case "$1" in
"no_sysroot")
no_sysroot_tests
;;
"base_sysroot")
base_sysroot_tests
;;
"extended_sysroot")
extended_sysroot_tests
;;
*)
echo "unknown test suite"
;;
esac

View File

@ -23,7 +23,7 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam {
(RegKind::Integer, 9..=16) => types::I128,
(RegKind::Float, 4) => types::F32,
(RegKind::Float, 8) => types::F64,
(RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
(RegKind::Vector, size) => types::I8.by(u32::try_from(size).unwrap()).unwrap(),
_ => unreachable!("{:?}", reg),
};
AbiParam::new(clif_ty)
@ -184,7 +184,7 @@ pub(super) fn from_casted_value<'tcx>(
let abi_params = cast_target_to_abi_params(cast);
let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum();
let layout_size = u32::try_from(layout.size.bytes()).unwrap();
let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
// specify stack slot alignment.
@ -193,7 +193,7 @@ pub(super) fn from_casted_value<'tcx>(
// larger alignment than the integer.
size: (std::cmp::max(abi_param_size, layout_size) + 15) / 16 * 16,
});
let ptr = Pointer::new(fx.bcx.ins().stack_addr(pointer_ty(fx.tcx), stack_slot, 0));
let ptr = Pointer::stack_slot(stack_slot);
let mut offset = 0;
let mut block_params_iter = block_params.iter().copied();
for param in abi_params {

View File

@ -6,21 +6,43 @@ use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use indexmap::IndexSet;
use crate::constant::ConstantCx;
use crate::debuginfo::FunctionDebugContext;
use crate::prelude::*;
use crate::pretty_clif::CommentWriter;
pub(crate) fn codegen_fn<'tcx>(
cx: &mut crate::CodegenCx<'tcx>,
pub(crate) struct CodegenedFunction {
symbol_name: String,
func_id: FuncId,
func: Function,
clif_comments: CommentWriter,
func_debug_cx: Option<FunctionDebugContext>,
}
#[cfg_attr(not(feature = "jit"), allow(dead_code))]
pub(crate) fn codegen_and_compile_fn<'tcx>(
tcx: TyCtxt<'tcx>,
cx: &mut crate::CodegenCx,
cached_context: &mut Context,
module: &mut dyn Module,
instance: Instance<'tcx>,
) {
let tcx = cx.tcx;
let _inst_guard =
crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name));
let cached_func = std::mem::replace(&mut cached_context.func, Function::new());
let codegened_func = codegen_fn(tcx, cx, cached_func, module, instance);
compile_fn(cx, cached_context, module, codegened_func);
}
pub(crate) fn codegen_fn<'tcx>(
tcx: TyCtxt<'tcx>,
cx: &mut crate::CodegenCx,
cached_func: Function,
module: &mut dyn Module,
instance: Instance<'tcx>,
) -> CodegenedFunction {
debug_assert!(!instance.substs.needs_infer());
let mir = tcx.instance_mir(instance.def);
@ -34,15 +56,14 @@ pub(crate) fn codegen_fn<'tcx>(
});
// Declare function
let symbol_name = tcx.symbol_name(instance);
let symbol_name = tcx.symbol_name(instance).name.to_string();
let sig = get_function_sig(tcx, module.isa().triple(), instance);
let func_id = module.declare_function(symbol_name.name, Linkage::Local, &sig).unwrap();
cx.cached_context.clear();
let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap();
// Make the FunctionBuilder
let mut func_ctx = FunctionBuilderContext::new();
let mut func = std::mem::replace(&mut cx.cached_context.func, Function::new());
let mut func = cached_func;
func.clear();
func.name = ExternalName::user(0, func_id.as_u32());
func.signature = sig;
func.collect_debug_info();
@ -59,6 +80,12 @@ pub(crate) fn codegen_fn<'tcx>(
let pointer_type = target_config.pointer_type();
let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
let func_debug_cx = if let Some(debug_context) = &mut cx.debug_context {
Some(debug_context.define_function(tcx, &symbol_name, mir.span))
} else {
None
};
let mut fx = FunctionCx {
cx,
module,
@ -66,6 +93,7 @@ pub(crate) fn codegen_fn<'tcx>(
target_config,
pointer_type,
constants_cx: ConstantCx::new(),
func_debug_cx,
instance,
symbol_name,
@ -78,81 +106,48 @@ pub(crate) fn codegen_fn<'tcx>(
caller_location: None, // set by `codegen_fn_prelude`
clif_comments,
source_info_set: indexmap::IndexSet::new(),
last_source_file: None,
next_ssa_var: 0,
};
let arg_uninhabited = fx
.mir
.args_iter()
.any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
if !crate::constant::check_constants(&mut fx) {
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
crate::trap::trap_unreachable(&mut fx, "compilation should have been aborted");
} else if arg_uninhabited {
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
} else {
tcx.sess.time("codegen clif ir", || {
tcx.sess
.time("codegen prelude", || crate::abi::codegen_fn_prelude(&mut fx, start_block));
codegen_fn_content(&mut fx);
});
}
tcx.sess.time("codegen clif ir", || codegen_fn_body(&mut fx, start_block));
// Recover all necessary data from fx, before accessing func will prevent future access to it.
let instance = fx.instance;
let symbol_name = fx.symbol_name;
let clif_comments = fx.clif_comments;
let source_info_set = fx.source_info_set;
let local_map = fx.local_map;
let func_debug_cx = fx.func_debug_cx;
fx.constants_cx.finalize(fx.tcx, &mut *fx.module);
crate::pretty_clif::write_clif_file(
tcx,
"unopt",
module.isa(),
instance,
&func,
&clif_comments,
);
if cx.should_write_ir {
crate::pretty_clif::write_clif_file(
tcx.output_filenames(()),
&symbol_name,
"unopt",
module.isa(),
&func,
&clif_comments,
);
}
// Verify function
verify_func(tcx, &clif_comments, &func);
compile_fn(
cx,
module,
instance,
symbol_name.name,
func_id,
func,
clif_comments,
source_info_set,
local_map,
);
CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx }
}
fn compile_fn<'tcx>(
cx: &mut crate::CodegenCx<'tcx>,
pub(crate) fn compile_fn(
cx: &mut crate::CodegenCx,
cached_context: &mut Context,
module: &mut dyn Module,
instance: Instance<'tcx>,
symbol_name: &str,
func_id: FuncId,
func: Function,
mut clif_comments: CommentWriter,
source_info_set: IndexSet<SourceInfo>,
local_map: IndexVec<mir::Local, CPlace<'tcx>>,
codegened_func: CodegenedFunction,
) {
let tcx = cx.tcx;
let clif_comments = codegened_func.clif_comments;
// Store function in context
let context = &mut cx.cached_context;
let context = cached_context;
context.clear();
context.func = func;
context.func = codegened_func.func;
// If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
// instruction, which doesn't have an encoding.
@ -164,17 +159,6 @@ fn compile_fn<'tcx>(
// invalidate it when it would change.
context.domtree.clear();
// Perform rust specific optimizations
tcx.sess.time("optimize clif ir", || {
crate::optimize::optimize_function(
tcx,
module.isa(),
instance,
context,
&mut clif_comments,
);
});
#[cfg(any())] // This is never true
let _clif_guard = {
use std::fmt::Write;
@ -203,46 +187,44 @@ fn compile_fn<'tcx>(
};
// Define function
tcx.sess.time("define function", || {
context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
module.define_function(func_id, context).unwrap();
cx.profiler.verbose_generic_activity("define function").run(|| {
context.want_disasm = cx.should_write_ir;
module.define_function(codegened_func.func_id, context).unwrap();
});
// Write optimized function to file for debugging
crate::pretty_clif::write_clif_file(
tcx,
"opt",
module.isa(),
instance,
&context.func,
&clif_comments,
);
if cx.should_write_ir {
// Write optimized function to file for debugging
crate::pretty_clif::write_clif_file(
&cx.output_filenames,
&codegened_func.symbol_name,
"opt",
module.isa(),
&context.func,
&clif_comments,
);
if let Some(disasm) = &context.mach_compile_result.as_ref().unwrap().disasm {
crate::pretty_clif::write_ir_file(
tcx,
|| format!("{}.vcode", tcx.symbol_name(instance).name),
|file| file.write_all(disasm.as_bytes()),
)
if let Some(disasm) = &context.compiled_code().unwrap().disasm {
crate::pretty_clif::write_ir_file(
&cx.output_filenames,
&format!("{}.vcode", codegened_func.symbol_name),
|file| file.write_all(disasm.as_bytes()),
)
}
}
// Define debuginfo for function
let isa = module.isa();
let debug_context = &mut cx.debug_context;
let unwind_context = &mut cx.unwind_context;
tcx.sess.time("generate debug info", || {
cx.profiler.verbose_generic_activity("generate debug info").run(|| {
if let Some(debug_context) = debug_context {
debug_context.define_function(
instance,
func_id,
symbol_name,
isa,
codegened_func.func_debug_cx.unwrap().finalize(
debug_context,
codegened_func.func_id,
context,
&source_info_set,
local_map,
);
}
unwind_context.add_function(func_id, &context, isa);
unwind_context.add_function(codegened_func.func_id, &context, isa);
});
}
@ -268,7 +250,27 @@ pub(crate) fn verify_func(
});
}
fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
if !crate::constant::check_constants(fx) {
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
// compilation should have been aborted
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
return;
}
let arg_uninhabited = fx
.mir
.args_iter()
.any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
if arg_uninhabited {
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
return;
}
fx.tcx.sess.time("codegen prelude", || crate::abi::codegen_fn_prelude(fx, start_block));
for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() {
let block = fx.get_block(bb);
fx.bcx.switch_to_block(block);
@ -457,17 +459,8 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
template,
operands,
*options,
*destination,
);
match *destination {
Some(destination) => {
let destination_block = fx.get_block(destination);
fx.bcx.ins().jump(destination_block, &[]);
}
None => {
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}
}
}
TerminatorKind::Resume | TerminatorKind::Abort => {
// FIXME implement unwinding
@ -711,9 +704,7 @@ fn codegen_stmt<'tcx>(
Rvalue::Discriminant(place) => {
let place = codegen_place(fx, place);
let value = place.to_cvalue(fx);
let discr =
crate::discriminant::codegen_get_discriminant(fx, value, dest_layout);
lval.write_cvalue(fx, discr);
crate::discriminant::codegen_get_discriminant(fx, lval, value, dest_layout);
}
Rvalue::Repeat(ref operand, times) => {
let operand = codegen_operand(fx, operand);

View File

@ -1,14 +1,18 @@
use cranelift_codegen::isa::TargetFrontendConfig;
use gimli::write::FileId;
use rustc_data_structures::sync::Lrc;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
};
use rustc_middle::ty::SymbolName;
use rustc_span::SourceFile;
use rustc_target::abi::call::FnAbi;
use rustc_target::abi::{Integer, Primitive};
use rustc_target::spec::{HasTargetSpec, Target};
use crate::constant::ConstantCx;
use crate::debuginfo::FunctionDebugContext;
use crate::prelude::*;
pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type {
@ -74,7 +78,7 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Typ
_ => unreachable!(),
};
match scalar_to_clif_type(tcx, element).by(u16::try_from(count).unwrap()) {
match scalar_to_clif_type(tcx, element).by(u32::try_from(count).unwrap()) {
// Cranelift currently only implements icmp for 128bit vectors.
Some(vector_ty) if vector_ty.bits() == 128 => vector_ty,
_ => return None,
@ -232,15 +236,16 @@ pub(crate) fn type_sign(ty: Ty<'_>) -> bool {
}
pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
pub(crate) cx: &'clif mut crate::CodegenCx<'tcx>,
pub(crate) cx: &'clif mut crate::CodegenCx,
pub(crate) module: &'m mut dyn Module,
pub(crate) tcx: TyCtxt<'tcx>,
pub(crate) target_config: TargetFrontendConfig, // Cached from module
pub(crate) pointer_type: Type, // Cached from module
pub(crate) constants_cx: ConstantCx,
pub(crate) func_debug_cx: Option<FunctionDebugContext>,
pub(crate) instance: Instance<'tcx>,
pub(crate) symbol_name: SymbolName<'tcx>,
pub(crate) symbol_name: String,
pub(crate) mir: &'tcx Body<'tcx>,
pub(crate) fn_abi: Option<&'tcx FnAbi<'tcx, Ty<'tcx>>>,
@ -252,7 +257,11 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
pub(crate) caller_location: Option<CValue<'tcx>>,
pub(crate) clif_comments: crate::pretty_clif::CommentWriter,
pub(crate) source_info_set: indexmap::IndexSet<SourceInfo>,
/// Last accessed source file and it's debuginfo file id.
///
/// For optimization purposes only
pub(crate) last_source_file: Option<(Lrc<SourceFile>, FileId)>,
/// This should only be accessed by `CPlace::new_var`.
pub(crate) next_ssa_var: u32,
@ -336,8 +345,31 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
}
pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) {
let (index, _) = self.source_info_set.insert_full(source_info);
self.bcx.set_srcloc(SourceLoc::new(index as u32));
if let Some(debug_context) = &mut self.cx.debug_context {
let (file, line, column) =
DebugContext::get_span_loc(self.tcx, self.mir.span, source_info.span);
// add_source_file is very slow.
// Optimize for the common case of the current file not being changed.
let mut cached_file_id = None;
if let Some((ref last_source_file, last_file_id)) = self.last_source_file {
// If the allocations are not equal, the files may still be equal, but that
// doesn't matter, as this is just an optimization.
if rustc_data_structures::sync::Lrc::ptr_eq(last_source_file, &file) {
cached_file_id = Some(last_file_id);
}
}
let file_id = if let Some(file_id) = cached_file_id {
file_id
} else {
debug_context.add_source_file(&file)
};
let source_loc =
self.func_debug_cx.as_mut().unwrap().add_dbg_loc(file_id, line, column);
self.bcx.set_srcloc(source_loc);
}
}
// Note: must be kept in sync with get_caller_location from cg_ssa

View File

@ -0,0 +1,168 @@
use std::sync::{Arc, Condvar, Mutex};
use rustc_session::Session;
use jobserver::HelperThread;
// FIXME don't panic when a worker thread panics
pub(super) struct ConcurrencyLimiter {
helper_thread: Option<HelperThread>,
state: Arc<Mutex<state::ConcurrencyLimiterState>>,
available_token_condvar: Arc<Condvar>,
}
impl ConcurrencyLimiter {
pub(super) fn new(sess: &Session, pending_jobs: usize) -> Self {
let state = Arc::new(Mutex::new(state::ConcurrencyLimiterState::new(pending_jobs)));
let available_token_condvar = Arc::new(Condvar::new());
let state_helper = state.clone();
let available_token_condvar_helper = available_token_condvar.clone();
let helper_thread = sess
.jobserver
.clone()
.into_helper_thread(move |token| {
let mut state = state_helper.lock().unwrap();
state.add_new_token(token.unwrap());
available_token_condvar_helper.notify_one();
})
.unwrap();
ConcurrencyLimiter {
helper_thread: Some(helper_thread),
state,
available_token_condvar: Arc::new(Condvar::new()),
}
}
pub(super) fn acquire(&mut self) -> ConcurrencyLimiterToken {
let mut state = self.state.lock().unwrap();
loop {
state.assert_invariants();
if state.try_start_job() {
return ConcurrencyLimiterToken {
state: self.state.clone(),
available_token_condvar: self.available_token_condvar.clone(),
};
}
self.helper_thread.as_mut().unwrap().request_token();
state = self.available_token_condvar.wait(state).unwrap();
}
}
pub(super) fn job_already_done(&mut self) {
let mut state = self.state.lock().unwrap();
state.job_already_done();
}
}
impl Drop for ConcurrencyLimiter {
fn drop(&mut self) {
//
self.helper_thread.take();
// Assert that all jobs have finished
let state = Mutex::get_mut(Arc::get_mut(&mut self.state).unwrap()).unwrap();
state.assert_done();
}
}
#[derive(Debug)]
pub(super) struct ConcurrencyLimiterToken {
state: Arc<Mutex<state::ConcurrencyLimiterState>>,
available_token_condvar: Arc<Condvar>,
}
impl Drop for ConcurrencyLimiterToken {
fn drop(&mut self) {
let mut state = self.state.lock().unwrap();
state.job_finished();
self.available_token_condvar.notify_one();
}
}
mod state {
use jobserver::Acquired;
#[derive(Debug)]
pub(super) struct ConcurrencyLimiterState {
pending_jobs: usize,
active_jobs: usize,
// None is used to represent the implicit token, Some to represent explicit tokens
tokens: Vec<Option<Acquired>>,
}
impl ConcurrencyLimiterState {
pub(super) fn new(pending_jobs: usize) -> Self {
ConcurrencyLimiterState { pending_jobs, active_jobs: 0, tokens: vec![None] }
}
pub(super) fn assert_invariants(&self) {
// There must be no excess active jobs
assert!(self.active_jobs <= self.pending_jobs);
// There may not be more active jobs than there are tokens
assert!(self.active_jobs <= self.tokens.len());
}
pub(super) fn assert_done(&self) {
assert_eq!(self.pending_jobs, 0);
assert_eq!(self.active_jobs, 0);
}
pub(super) fn add_new_token(&mut self, token: Acquired) {
self.tokens.push(Some(token));
self.drop_excess_capacity();
}
pub(super) fn try_start_job(&mut self) -> bool {
if self.active_jobs < self.tokens.len() {
// Using existing token
self.job_started();
return true;
}
false
}
pub(super) fn job_started(&mut self) {
self.assert_invariants();
self.active_jobs += 1;
self.drop_excess_capacity();
self.assert_invariants();
}
pub(super) fn job_finished(&mut self) {
self.assert_invariants();
self.pending_jobs -= 1;
self.active_jobs -= 1;
self.assert_invariants();
self.drop_excess_capacity();
self.assert_invariants();
}
pub(super) fn job_already_done(&mut self) {
self.assert_invariants();
self.pending_jobs -= 1;
self.assert_invariants();
self.drop_excess_capacity();
self.assert_invariants();
}
fn drop_excess_capacity(&mut self) {
self.assert_invariants();
// Drop all tokens that can never be used anymore
self.tokens.truncate(std::cmp::max(self.pending_jobs, 1));
// Keep some excess tokens to satisfy requests faster
const MAX_EXTRA_CAPACITY: usize = 2;
self.tokens.truncate(std::cmp::max(self.active_jobs + MAX_EXTRA_CAPACITY, 1));
self.assert_invariants();
}
}
}

View File

@ -9,7 +9,7 @@ use gimli::{RunTimeEndian, SectionId};
use super::object::WriteDebugInfo;
use super::DebugContext;
impl DebugContext<'_> {
impl DebugContext {
pub(crate) fn emit(&mut self, product: &mut ObjectProduct) {
let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone());
let root = self.dwarf.unit.root();

View File

@ -3,8 +3,10 @@
use std::ffi::OsStr;
use std::path::{Component, Path};
use crate::debuginfo::FunctionDebugContext;
use crate::prelude::*;
use rustc_data_structures::sync::Lrc;
use rustc_span::{
FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm,
};
@ -14,7 +16,6 @@ use cranelift_codegen::MachSrcLoc;
use gimli::write::{
Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable,
UnitEntryId,
};
// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
@ -47,9 +48,9 @@ fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
}
}
pub(crate) const MD5_LEN: usize = 16;
const MD5_LEN: usize = 16;
pub(crate) fn make_file_info(hash: SourceFileHash) -> Option<FileInfo> {
fn make_file_info(hash: SourceFileHash) -> Option<FileInfo> {
if hash.kind == SourceFileHashAlgorithm::Md5 {
let mut buf = [0u8; MD5_LEN];
buf.copy_from_slice(hash.hash_bytes());
@ -59,160 +60,132 @@ pub(crate) fn make_file_info(hash: SourceFileHash) -> Option<FileInfo> {
}
}
fn line_program_add_file(
line_program: &mut LineProgram,
line_strings: &mut LineStringTable,
file: &SourceFile,
) -> FileId {
match &file.name {
FileName::Real(path) => {
let (dir_path, file_name) = split_path_dir_and_file(path.remapped_path_if_available());
let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
let file_name = osstr_as_utf8_bytes(file_name);
impl DebugContext {
pub(crate) fn get_span_loc(
tcx: TyCtxt<'_>,
function_span: Span,
span: Span,
) -> (Lrc<SourceFile>, u64, u64) {
// Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
// In order to have a good line stepping behavior in debugger, we overwrite debug
// locations of macro expansions with that of the outermost expansion site
// (unless the crate is being compiled with `-Z debug-macros`).
let span = if !span.from_expansion() || tcx.sess.opts.unstable_opts.debug_macros {
span
} else {
// Walk up the macro expansion chain until we reach a non-expanded span.
// We also stop at the function body level because no line stepping can occur
// at the level above that.
rustc_span::hygiene::walk_chain(span, function_span.ctxt())
};
let dir_id = if !dir_name.is_empty() {
let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
line_program.add_directory(dir_name)
} else {
line_program.default_directory()
};
let file_name = LineString::new(file_name, line_program.encoding(), line_strings);
match tcx.sess.source_map().lookup_line(span.lo()) {
Ok(SourceFileAndLine { sf: file, line }) => {
let line_pos = file.line_begin_pos(span.lo());
let info = make_file_info(file.src_hash);
line_program.file_has_md5 &= info.is_some();
line_program.add_file(file_name, dir_id, info)
(
file,
u64::try_from(line).unwrap() + 1,
u64::from((span.lo() - line_pos).to_u32()) + 1,
)
}
Err(file) => (file, 0, 0),
}
// FIXME give more appropriate file names
filename => {
let dir_id = line_program.default_directory();
let dummy_file_name = LineString::new(
filename.prefer_remapped().to_string().into_bytes(),
line_program.encoding(),
line_strings,
);
line_program.add_file(dummy_file_name, dir_id, None)
}
pub(crate) fn add_source_file(&mut self, source_file: &SourceFile) -> FileId {
let line_program: &mut LineProgram = &mut self.dwarf.unit.line_program;
let line_strings: &mut LineStringTable = &mut self.dwarf.line_strings;
match &source_file.name {
FileName::Real(path) => {
let (dir_path, file_name) =
split_path_dir_and_file(path.remapped_path_if_available());
let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
let file_name = osstr_as_utf8_bytes(file_name);
let dir_id = if !dir_name.is_empty() {
let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
line_program.add_directory(dir_name)
} else {
line_program.default_directory()
};
let file_name = LineString::new(file_name, line_program.encoding(), line_strings);
let info = make_file_info(source_file.src_hash);
line_program.file_has_md5 &= info.is_some();
line_program.add_file(file_name, dir_id, info)
}
// FIXME give more appropriate file names
filename => {
let dir_id = line_program.default_directory();
let dummy_file_name = LineString::new(
filename.prefer_remapped().to_string().into_bytes(),
line_program.encoding(),
line_strings,
);
line_program.add_file(dummy_file_name, dir_id, None)
}
}
}
}
impl<'tcx> DebugContext<'tcx> {
pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());
let file_id = line_program_add_file(
&mut self.dwarf.unit.line_program,
&mut self.dwarf.line_strings,
&loc.file,
);
let entry = self.dwarf.unit.get_mut(entry_id);
entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id)));
entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(loc.line as u64));
entry.set(gimli::DW_AT_decl_column, AttributeValue::Udata(loc.col.to_usize() as u64));
impl FunctionDebugContext {
pub(crate) fn add_dbg_loc(&mut self, file_id: FileId, line: u64, column: u64) -> SourceLoc {
let (index, _) = self.source_loc_set.insert_full((file_id, line, column));
SourceLoc::new(u32::try_from(index).unwrap())
}
pub(super) fn create_debug_lines(
&mut self,
debug_context: &mut DebugContext,
symbol: usize,
entry_id: UnitEntryId,
context: &Context,
function_span: Span,
source_info_set: &indexmap::IndexSet<SourceInfo>,
) -> CodeOffset {
let tcx = self.tcx;
let line_program = &mut self.dwarf.unit.line_program;
let create_row_for_span =
|debug_context: &mut DebugContext, source_loc: (FileId, u64, u64)| {
let (file_id, line, col) = source_loc;
let line_strings = &mut self.dwarf.line_strings;
let mut last_span = None;
let mut last_file = None;
let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
if let Some(last_span) = last_span {
if span == last_span {
line_program.generate_row();
return;
}
}
last_span = Some(span);
// Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
// In order to have a good line stepping behavior in debugger, we overwrite debug
// locations of macro expansions with that of the outermost expansion site
// (unless the crate is being compiled with `-Z debug-macros`).
let span = if !span.from_expansion() || tcx.sess.opts.unstable_opts.debug_macros {
span
} else {
// Walk up the macro expansion chain until we reach a non-expanded span.
// We also stop at the function body level because no line stepping can occur
// at the level above that.
rustc_span::hygiene::walk_chain(span, function_span.ctxt())
debug_context.dwarf.unit.line_program.row().file = file_id;
debug_context.dwarf.unit.line_program.row().line = line;
debug_context.dwarf.unit.line_program.row().column = col;
debug_context.dwarf.unit.line_program.generate_row();
};
let (file, line, col) = match tcx.sess.source_map().lookup_line(span.lo()) {
Ok(SourceFileAndLine { sf: file, line }) => {
let line_pos = file.line_begin_pos(span.lo());
(
file,
u64::try_from(line).unwrap() + 1,
u64::from((span.lo() - line_pos).to_u32()) + 1,
)
}
Err(file) => (file, 0, 0),
};
// line_program_add_file is very slow.
// Optimize for the common case of the current file not being changed.
let current_file_changed = if let Some(last_file) = &last_file {
// If the allocations are not equal, then the files may still be equal, but that
// is not a problem, as this is just an optimization.
!rustc_data_structures::sync::Lrc::ptr_eq(last_file, &file)
} else {
true
};
if current_file_changed {
let file_id = line_program_add_file(line_program, line_strings, &file);
line_program.row().file = file_id;
last_file = Some(file);
}
line_program.row().line = line;
line_program.row().column = col;
line_program.generate_row();
};
line_program.begin_sequence(Some(Address::Symbol { symbol, addend: 0 }));
debug_context
.dwarf
.unit
.line_program
.begin_sequence(Some(Address::Symbol { symbol, addend: 0 }));
let mut func_end = 0;
let mcr = context.mach_compile_result.as_ref().unwrap();
let mcr = context.compiled_code().unwrap();
for &MachSrcLoc { start, end, loc } in mcr.buffer.get_srclocs_sorted() {
line_program.row().address_offset = u64::from(start);
debug_context.dwarf.unit.line_program.row().address_offset = u64::from(start);
if !loc.is_default() {
let source_info = *source_info_set.get_index(loc.bits() as usize).unwrap();
create_row_for_span(line_program, source_info.span);
let source_loc = *self.source_loc_set.get_index(loc.bits() as usize).unwrap();
create_row_for_span(debug_context, source_loc);
} else {
create_row_for_span(line_program, function_span);
create_row_for_span(debug_context, self.function_source_loc);
}
func_end = end;
}
line_program.end_sequence(u64::from(func_end));
debug_context.dwarf.unit.line_program.end_sequence(u64::from(func_end));
let func_end = mcr.buffer.total_size();
assert_ne!(func_end, 0);
let entry = self.dwarf.unit.get_mut(entry_id);
let entry = debug_context.dwarf.unit.get_mut(self.entry_id);
entry.set(
gimli::DW_AT_low_pc,
AttributeValue::Address(Address::Symbol { symbol, addend: 0 }),
);
entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(func_end)));
self.emit_location(entry_id, function_span);
func_end
}
}

View File

@ -7,35 +7,34 @@ mod unwind;
use crate::prelude::*;
use rustc_index::vec::IndexVec;
use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::{Endianness, LabelValueLoc, ValueLabel};
use cranelift_codegen::ir::Endianness;
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::ValueLocRange;
use gimli::write::{
Address, AttributeValue, DwarfUnit, Expression, LineProgram, LineString, Location,
LocationList, Range, RangeList, UnitEntryId,
Address, AttributeValue, DwarfUnit, FileId, LineProgram, LineString, Range, RangeList,
UnitEntryId,
};
use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, X86_64};
use gimli::{Encoding, Format, LineEncoding, RunTimeEndian};
use indexmap::IndexSet;
pub(crate) use emit::{DebugReloc, DebugRelocName};
pub(crate) use unwind::UnwindContext;
pub(crate) struct DebugContext<'tcx> {
tcx: TyCtxt<'tcx>,
pub(crate) struct DebugContext {
endian: RunTimeEndian,
dwarf: DwarfUnit,
unit_range_list: RangeList,
types: FxHashMap<Ty<'tcx>, UnitEntryId>,
}
impl<'tcx> DebugContext<'tcx> {
pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa) -> Self {
pub(crate) struct FunctionDebugContext {
entry_id: UnitEntryId,
function_source_loc: (FileId, u64, u64),
source_loc_set: indexmap::IndexSet<(FileId, u64, u64)>,
}
impl DebugContext {
pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self {
let encoding = Encoding {
format: Format::Dwarf32,
// FIXME this should be configurable
@ -101,127 +100,18 @@ impl<'tcx> DebugContext<'tcx> {
root.set(gimli::DW_AT_low_pc, AttributeValue::Address(Address::Constant(0)));
}
DebugContext {
tcx,
endian,
dwarf,
unit_range_list: RangeList(Vec::new()),
types: FxHashMap::default(),
}
}
fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
if let Some(type_id) = self.types.get(&ty) {
return *type_id;
}
let new_entry = |dwarf: &mut DwarfUnit, tag| dwarf.unit.add(dwarf.unit.root(), tag);
let primitive = |dwarf: &mut DwarfUnit, ate| {
let type_id = new_entry(dwarf, gimli::DW_TAG_base_type);
let type_entry = dwarf.unit.get_mut(type_id);
type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(ate));
type_id
};
let name = format!("{}", ty);
let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap();
let type_id = match ty.kind() {
ty::Bool => primitive(&mut self.dwarf, gimli::DW_ATE_boolean),
ty::Char => primitive(&mut self.dwarf, gimli::DW_ATE_UTF),
ty::Uint(_) => primitive(&mut self.dwarf, gimli::DW_ATE_unsigned),
ty::Int(_) => primitive(&mut self.dwarf, gimli::DW_ATE_signed),
ty::Float(_) => primitive(&mut self.dwarf, gimli::DW_ATE_float),
ty::Ref(_, pointee_ty, _mutbl)
| ty::RawPtr(ty::TypeAndMut { ty: pointee_ty, mutbl: _mutbl }) => {
let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_pointer_type);
// Ensure that type is inserted before recursing to avoid duplicates
self.types.insert(ty, type_id);
let pointee = self.dwarf_ty(*pointee_ty);
let type_entry = self.dwarf.unit.get_mut(type_id);
//type_entry.set(gimli::DW_AT_mutable, AttributeValue::Flag(mutbl == rustc_hir::Mutability::Mut));
type_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(pointee));
type_id
}
ty::Adt(adt_def, _substs) if adt_def.is_struct() && !layout.is_unsized() => {
let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type);
// Ensure that type is inserted before recursing to avoid duplicates
self.types.insert(ty, type_id);
let variant = adt_def.non_enum_variant();
for (field_idx, field_def) in variant.fields.iter().enumerate() {
let field_offset = layout.fields.offset(field_idx);
let field_layout = layout.field(
&layout::LayoutCx { tcx: self.tcx, param_env: ParamEnv::reveal_all() },
field_idx,
);
let field_type = self.dwarf_ty(field_layout.ty);
let field_id = self.dwarf.unit.add(type_id, gimli::DW_TAG_member);
let field_entry = self.dwarf.unit.get_mut(field_id);
field_entry.set(
gimli::DW_AT_name,
AttributeValue::String(field_def.name.as_str().to_string().into_bytes()),
);
field_entry.set(
gimli::DW_AT_data_member_location,
AttributeValue::Udata(field_offset.bytes()),
);
field_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(field_type));
}
type_id
}
_ => new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type),
};
let type_entry = self.dwarf.unit.get_mut(type_id);
type_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
type_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes()));
self.types.insert(ty, type_id);
type_id
}
fn define_local(&mut self, scope: UnitEntryId, name: String, ty: Ty<'tcx>) -> UnitEntryId {
let dw_ty = self.dwarf_ty(ty);
let var_id = self.dwarf.unit.add(scope, gimli::DW_TAG_variable);
let var_entry = self.dwarf.unit.get_mut(var_id);
var_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
var_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty));
var_id
DebugContext { endian, dwarf, unit_range_list: RangeList(Vec::new()) }
}
pub(crate) fn define_function(
&mut self,
instance: Instance<'tcx>,
func_id: FuncId,
tcx: TyCtxt<'_>,
name: &str,
isa: &dyn TargetIsa,
context: &Context,
source_info_set: &indexmap::IndexSet<SourceInfo>,
local_map: IndexVec<mir::Local, CPlace<'tcx>>,
) {
let symbol = func_id.as_u32() as usize;
let mir = self.tcx.instance_mir(instance.def);
function_span: Span,
) -> FunctionDebugContext {
let (file, line, column) = DebugContext::get_span_loc(tcx, function_span, function_span);
let file_id = self.add_source_file(&file);
// FIXME: add to appropriate scope instead of root
let scope = self.dwarf.unit.root();
@ -233,14 +123,35 @@ impl<'tcx> DebugContext<'tcx> {
entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id));
entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(name_id));
let end = self.create_debug_lines(symbol, entry_id, context, mir.span, source_info_set);
entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id)));
entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line));
entry.set(gimli::DW_AT_decl_column, AttributeValue::Udata(column));
self.unit_range_list.0.push(Range::StartLength {
FunctionDebugContext {
entry_id,
function_source_loc: (file_id, line, column),
source_loc_set: IndexSet::new(),
}
}
}
impl FunctionDebugContext {
pub(crate) fn finalize(
mut self,
debug_context: &mut DebugContext,
func_id: FuncId,
context: &Context,
) {
let symbol = func_id.as_u32() as usize;
let end = self.create_debug_lines(debug_context, symbol, context);
debug_context.unit_range_list.0.push(Range::StartLength {
begin: Address::Symbol { symbol, addend: 0 },
length: u64::from(end),
});
let func_entry = self.dwarf.unit.get_mut(entry_id);
let func_entry = debug_context.dwarf.unit.get_mut(self.entry_id);
// Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped.
func_entry.set(
gimli::DW_AT_low_pc,
@ -248,110 +159,5 @@ impl<'tcx> DebugContext<'tcx> {
);
// Using Udata for DW_AT_high_pc requires at least DWARF4
func_entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(end)));
// FIXME make it more reliable and implement scopes before re-enabling this.
if false {
let value_labels_ranges = std::collections::HashMap::new(); // FIXME
for (local, _local_decl) in mir.local_decls.iter_enumerated() {
let ty = self.tcx.subst_and_normalize_erasing_regions(
instance.substs,
ty::ParamEnv::reveal_all(),
mir.local_decls[local].ty,
);
let var_id = self.define_local(entry_id, format!("{:?}", local), ty);
let location = place_location(
self,
isa,
symbol,
&local_map,
&value_labels_ranges,
Place { local, projection: ty::List::empty() },
);
let var_entry = self.dwarf.unit.get_mut(var_id);
var_entry.set(gimli::DW_AT_location, location);
}
}
// FIXME create locals for all entries in mir.var_debug_info
}
}
fn place_location<'tcx>(
debug_context: &mut DebugContext<'tcx>,
isa: &dyn TargetIsa,
symbol: usize,
local_map: &IndexVec<mir::Local, CPlace<'tcx>>,
#[allow(rustc::default_hash_types)] value_labels_ranges: &std::collections::HashMap<
ValueLabel,
Vec<ValueLocRange>,
>,
place: Place<'tcx>,
) -> AttributeValue {
assert!(place.projection.is_empty()); // FIXME implement them
match local_map[place.local].inner() {
CPlaceInner::Var(_local, var) => {
let value_label = cranelift_codegen::ir::ValueLabel::new(var.index());
if let Some(value_loc_ranges) = value_labels_ranges.get(&value_label) {
let loc_list = LocationList(
value_loc_ranges
.iter()
.map(|value_loc_range| Location::StartEnd {
begin: Address::Symbol {
symbol,
addend: i64::from(value_loc_range.start),
},
end: Address::Symbol { symbol, addend: i64::from(value_loc_range.end) },
data: translate_loc(isa, value_loc_range.loc).unwrap(),
})
.collect(),
);
let loc_list_id = debug_context.dwarf.unit.locations.add(loc_list);
AttributeValue::LocationListRef(loc_list_id)
} else {
// FIXME set value labels for unused locals
AttributeValue::Exprloc(Expression::new())
}
}
CPlaceInner::VarPair(_, _, _) => {
// FIXME implement this
AttributeValue::Exprloc(Expression::new())
}
CPlaceInner::VarLane(_, _, _) => {
// FIXME implement this
AttributeValue::Exprloc(Expression::new())
}
CPlaceInner::Addr(_, _) => {
// FIXME implement this (used by arguments and returns)
AttributeValue::Exprloc(Expression::new())
// For PointerBase::Stack:
//AttributeValue::Exprloc(translate_loc(ValueLoc::Stack(*stack_slot)).unwrap())
}
}
}
// Adapted from https://github.com/CraneStation/wasmtime/blob/5a1845b4caf7a5dba8eda1fef05213a532ed4259/crates/debug/src/transform/expression.rs#L59-L137
fn translate_loc(isa: &dyn TargetIsa, loc: LabelValueLoc) -> Option<Expression> {
match loc {
LabelValueLoc::Reg(reg) => {
let machine_reg = isa.map_regalloc_reg_to_dwarf(reg).unwrap();
let mut expr = Expression::new();
expr.op_reg(gimli::Register(machine_reg));
Some(expr)
}
LabelValueLoc::SPOffset(offset) => {
let mut expr = Expression::new();
expr.op_breg(X86_64::RSP, offset);
Some(expr)
}
}
}

View File

@ -62,16 +62,14 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
pub(crate) fn codegen_get_discriminant<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
dest: CPlace<'tcx>,
value: CValue<'tcx>,
dest_layout: TyAndLayout<'tcx>,
) -> CValue<'tcx> {
) {
let layout = value.layout();
if layout.abi == Abi::Uninhabited {
let true_ = fx.bcx.ins().iconst(types::I32, 1);
fx.bcx.ins().trapnz(true_, TrapCode::UnreachableCodeReached);
// Return a dummy value
return CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout);
if layout.abi.is_uninhabited() {
return;
}
let (tag_scalar, tag_field, tag_encoding) = match &layout.variants {
@ -89,7 +87,9 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
} else {
ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap()
};
return CValue::const_val(fx, dest_layout, discr_val);
let res = CValue::const_val(fx, dest_layout, discr_val);
dest.write_cvalue(fx, res);
return;
}
Variants::Multiple { tag, tag_field, tag_encoding, variants: _ } => {
(tag, *tag_field, tag_encoding)
@ -110,7 +110,8 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
_ => false,
};
let val = clif_intcast(fx, tag, cast_to, signed);
CValue::by_val(val, dest_layout)
let res = CValue::by_val(val, dest_layout);
dest.write_cvalue(fx, res);
}
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
// Rebase from niche values to discriminants, and check
@ -170,7 +171,8 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
let dataful_variant = fx.bcx.ins().iconst(cast_to, i64::from(dataful_variant.as_u32()));
let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant);
CValue::by_val(discr, dest_layout)
let res = CValue::by_val(discr, dest_layout);
dest.write_cvalue(fx, res);
}
}
}

View File

@ -1,33 +1,129 @@
//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
//! standalone executable.
use std::fs::File;
use std::path::PathBuf;
use std::sync::Arc;
use std::thread::JoinHandle;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file;
use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{DebugInfo, OutputType};
use rustc_session::config::{DebugInfo, OutputFilenames, OutputType};
use rustc_session::Session;
use cranelift_codegen::isa::TargetIsa;
use cranelift_object::{ObjectBuilder, ObjectModule};
use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken};
use crate::global_asm::GlobalAsmConfig;
use crate::{prelude::*, BackendConfig};
struct ModuleCodegenResult(CompiledModule, Option<(WorkProductId, WorkProduct)>);
struct ModuleCodegenResult {
module_regular: CompiledModule,
module_global_asm: Option<CompiledModule>,
existing_work_product: Option<(WorkProductId, WorkProduct)>,
}
impl<HCX> HashStable<HCX> for ModuleCodegenResult {
enum OngoingModuleCodegen {
Sync(Result<ModuleCodegenResult, String>),
Async(JoinHandle<Result<ModuleCodegenResult, String>>),
}
impl<HCX> HashStable<HCX> for OngoingModuleCodegen {
fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) {
// do nothing
}
}
fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
pub(crate) struct OngoingCodegen {
modules: Vec<OngoingModuleCodegen>,
allocator_module: Option<CompiledModule>,
metadata_module: Option<CompiledModule>,
metadata: EncodedMetadata,
crate_info: CrateInfo,
concurrency_limiter: ConcurrencyLimiter,
}
impl OngoingCodegen {
pub(crate) fn join(
self,
sess: &Session,
backend_config: &BackendConfig,
) -> (CodegenResults, FxHashMap<WorkProductId, WorkProduct>) {
let mut work_products = FxHashMap::default();
let mut modules = vec![];
for module_codegen in self.modules {
let module_codegen_result = match module_codegen {
OngoingModuleCodegen::Sync(module_codegen_result) => module_codegen_result,
OngoingModuleCodegen::Async(join_handle) => match join_handle.join() {
Ok(module_codegen_result) => module_codegen_result,
Err(panic) => std::panic::resume_unwind(panic),
},
};
let module_codegen_result = match module_codegen_result {
Ok(module_codegen_result) => module_codegen_result,
Err(err) => sess.fatal(&err),
};
let ModuleCodegenResult { module_regular, module_global_asm, existing_work_product } =
module_codegen_result;
if let Some((work_product_id, work_product)) = existing_work_product {
work_products.insert(work_product_id, work_product);
} else {
let work_product = if backend_config.disable_incr_cache {
None
} else if let Some(module_global_asm) = &module_global_asm {
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
sess,
&module_regular.name,
&[
("o", &module_regular.object.as_ref().unwrap()),
("asm.o", &module_global_asm.object.as_ref().unwrap()),
],
)
} else {
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
sess,
&module_regular.name,
&[("o", &module_regular.object.as_ref().unwrap())],
)
};
if let Some((work_product_id, work_product)) = work_product {
work_products.insert(work_product_id, work_product);
}
}
modules.push(module_regular);
if let Some(module_global_asm) = module_global_asm {
modules.push(module_global_asm);
}
}
drop(self.concurrency_limiter);
(
CodegenResults {
modules,
allocator_module: self.allocator_module,
metadata_module: self.metadata_module,
metadata: self.metadata,
crate_info: self.crate_info,
},
work_products,
)
}
}
fn make_module(sess: &Session, backend_config: &BackendConfig, name: String) -> ObjectModule {
let isa = crate::build_isa(sess, backend_config);
let mut builder =
ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
// Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
@ -37,15 +133,15 @@ fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectM
ObjectModule::new(builder)
}
fn emit_module(
tcx: TyCtxt<'_>,
backend_config: &BackendConfig,
fn emit_cgu(
output_filenames: &OutputFilenames,
prof: &SelfProfilerRef,
name: String,
kind: ModuleKind,
module: ObjectModule,
debug: Option<DebugContext<'_>>,
debug: Option<DebugContext>,
unwind_context: UnwindContext,
) -> ModuleCodegenResult {
global_asm_object_file: Option<PathBuf>,
) -> Result<ModuleCodegenResult, String> {
let mut product = module.finish();
if let Some(mut debug) = debug {
@ -54,134 +150,191 @@ fn emit_module(
unwind_context.emit(&mut product);
let tmp_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(&name));
let obj = product.object.write().unwrap();
let module_regular =
emit_module(output_filenames, prof, product.object, ModuleKind::Regular, name.clone())?;
tcx.sess.prof.artifact_size("object_file", name.clone(), obj.len().try_into().unwrap());
Ok(ModuleCodegenResult {
module_regular,
module_global_asm: global_asm_object_file.map(|global_asm_object_file| CompiledModule {
name: format!("{name}.asm"),
kind: ModuleKind::Regular,
object: Some(global_asm_object_file),
dwarf_object: None,
bytecode: None,
}),
existing_work_product: None,
})
}
if let Err(err) = std::fs::write(&tmp_file, obj) {
tcx.sess.fatal(&format!("error writing object file: {}", err));
}
let work_product = if backend_config.disable_incr_cache {
None
} else {
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
tcx.sess,
&name,
&[("o", &tmp_file)],
)
fn emit_module(
output_filenames: &OutputFilenames,
prof: &SelfProfilerRef,
object: cranelift_object::object::write::Object<'_>,
kind: ModuleKind,
name: String,
) -> Result<CompiledModule, String> {
let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name));
let mut file = match File::create(&tmp_file) {
Ok(file) => file,
Err(err) => return Err(format!("error creating object file: {}", err)),
};
ModuleCodegenResult(
CompiledModule { name, kind, object: Some(tmp_file), dwarf_object: None, bytecode: None },
work_product,
)
if let Err(err) = object.write_stream(&mut file) {
return Err(format!("error writing object file: {}", err));
}
prof.artifact_size("object_file", &*name, file.metadata().unwrap().len());
Ok(CompiledModule { name, kind, object: Some(tmp_file), dwarf_object: None, bytecode: None })
}
fn reuse_workproduct_for_cgu(
tcx: TyCtxt<'_>,
cgu: &CodegenUnit<'_>,
work_products: &mut FxHashMap<WorkProductId, WorkProduct>,
) -> CompiledModule {
) -> Result<ModuleCodegenResult, String> {
let work_product = cgu.previous_work_product(tcx);
let obj_out = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str()));
let source_file = rustc_incremental::in_incr_comp_dir_sess(
let obj_out_regular =
tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str()));
let source_file_regular = rustc_incremental::in_incr_comp_dir_sess(
&tcx.sess,
&work_product.saved_files.get("o").expect("no saved object file in work product"),
);
if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
tcx.sess.err(&format!(
if let Err(err) = rustc_fs_util::link_or_copy(&source_file_regular, &obj_out_regular) {
return Err(format!(
"unable to copy {} to {}: {}",
source_file.display(),
obj_out.display(),
source_file_regular.display(),
obj_out_regular.display(),
err
));
}
let obj_out_global_asm =
crate::global_asm::add_file_stem_postfix(obj_out_regular.clone(), ".asm");
let has_global_asm = if let Some(asm_o) = work_product.saved_files.get("asm.o") {
let source_file_global_asm = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, asm_o);
if let Err(err) = rustc_fs_util::link_or_copy(&source_file_global_asm, &obj_out_global_asm)
{
return Err(format!(
"unable to copy {} to {}: {}",
source_file_regular.display(),
obj_out_regular.display(),
err
));
}
true
} else {
false
};
work_products.insert(cgu.work_product_id(), work_product);
CompiledModule {
name: cgu.name().to_string(),
kind: ModuleKind::Regular,
object: Some(obj_out),
dwarf_object: None,
bytecode: None,
}
Ok(ModuleCodegenResult {
module_regular: CompiledModule {
name: cgu.name().to_string(),
kind: ModuleKind::Regular,
object: Some(obj_out_regular),
dwarf_object: None,
bytecode: None,
},
module_global_asm: if has_global_asm {
Some(CompiledModule {
name: cgu.name().to_string(),
kind: ModuleKind::Regular,
object: Some(obj_out_global_asm),
dwarf_object: None,
bytecode: None,
})
} else {
None
},
existing_work_product: Some((cgu.work_product_id(), work_product)),
})
}
fn module_codegen(
tcx: TyCtxt<'_>,
(backend_config, cgu_name): (BackendConfig, rustc_span::Symbol),
) -> ModuleCodegenResult {
let cgu = tcx.codegen_unit(cgu_name);
let mono_items = cgu.items_in_deterministic_order(tcx);
(backend_config, global_asm_config, cgu_name, token): (
BackendConfig,
Arc<GlobalAsmConfig>,
rustc_span::Symbol,
ConcurrencyLimiterToken,
),
) -> OngoingModuleCodegen {
let (cgu_name, mut cx, mut module, codegened_functions) = tcx.sess.time("codegen cgu", || {
let cgu = tcx.codegen_unit(cgu_name);
let mono_items = cgu.items_in_deterministic_order(tcx);
let isa = crate::build_isa(tcx.sess, &backend_config);
let mut module = make_module(tcx.sess, isa, cgu_name.as_str().to_string());
let mut module = make_module(tcx.sess, &backend_config, cgu_name.as_str().to_string());
let mut cx = crate::CodegenCx::new(
tcx,
backend_config.clone(),
module.isa(),
tcx.sess.opts.debuginfo != DebugInfo::None,
cgu_name,
);
super::predefine_mono_items(tcx, &mut module, &mono_items);
for (mono_item, _) in mono_items {
match mono_item {
MonoItem::Fn(inst) => {
cx.tcx
.sess
.time("codegen fn", || crate::base::codegen_fn(&mut cx, &mut module, inst));
}
MonoItem::Static(def_id) => crate::constant::codegen_static(tcx, &mut module, def_id),
MonoItem::GlobalAsm(item_id) => {
let item = cx.tcx.hir().item(item_id);
if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind {
if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
cx.global_asm.push_str("\n.intel_syntax noprefix\n");
} else {
cx.global_asm.push_str("\n.att_syntax\n");
}
for piece in asm.template {
match *piece {
InlineAsmTemplatePiece::String(ref s) => cx.global_asm.push_str(s),
InlineAsmTemplatePiece::Placeholder { .. } => todo!(),
}
}
cx.global_asm.push_str("\n.att_syntax\n\n");
} else {
bug!("Expected GlobalAsm found {:?}", item);
let mut cx = crate::CodegenCx::new(
tcx,
backend_config.clone(),
module.isa(),
tcx.sess.opts.debuginfo != DebugInfo::None,
cgu_name,
);
super::predefine_mono_items(tcx, &mut module, &mono_items);
let mut codegened_functions = vec![];
for (mono_item, _) in mono_items {
match mono_item {
MonoItem::Fn(inst) => {
tcx.sess.time("codegen fn", || {
let codegened_function = crate::base::codegen_fn(
tcx,
&mut cx,
Function::new(),
&mut module,
inst,
);
codegened_functions.push(codegened_function);
});
}
MonoItem::Static(def_id) => {
crate::constant::codegen_static(tcx, &mut module, def_id)
}
MonoItem::GlobalAsm(item_id) => {
crate::global_asm::codegen_global_asm_item(tcx, &mut cx.global_asm, item_id);
}
}
}
}
crate::main_shim::maybe_create_entry_wrapper(
tcx,
&mut module,
&mut cx.unwind_context,
false,
cgu.is_primary(),
);
let debug_context = cx.debug_context;
let unwind_context = cx.unwind_context;
let codegen_result = tcx.sess.time("write object file", || {
emit_module(
crate::main_shim::maybe_create_entry_wrapper(
tcx,
&backend_config,
cgu.name().as_str().to_string(),
ModuleKind::Regular,
module,
debug_context,
unwind_context,
)
&mut module,
&mut cx.unwind_context,
false,
cgu.is_primary(),
);
let cgu_name = cgu.name().as_str().to_owned();
(cgu_name, cx, module, codegened_functions)
});
codegen_global_asm(tcx, cgu.name().as_str(), &cx.global_asm);
OngoingModuleCodegen::Async(std::thread::spawn(move || {
cx.profiler.clone().verbose_generic_activity("compile functions").run(|| {
let mut cached_context = Context::new();
for codegened_func in codegened_functions {
crate::base::compile_fn(&mut cx, &mut cached_context, &mut module, codegened_func);
}
});
codegen_result
let global_asm_object_file =
cx.profiler.verbose_generic_activity("compile assembly").run(|| {
crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, &cx.global_asm)
})?;
let codegen_result = cx.profiler.verbose_generic_activity("write object file").run(|| {
emit_cgu(
&global_asm_config.output_filenames,
&cx.profiler,
cgu_name,
module,
cx.debug_context,
cx.unwind_context,
global_asm_object_file,
)
});
std::mem::drop(token);
codegen_result
}))
}
pub(crate) fn run_aot(
@ -189,9 +342,7 @@ pub(crate) fn run_aot(
backend_config: BackendConfig,
metadata: EncodedMetadata,
need_metadata_module: bool,
) -> Box<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)> {
let mut work_products = FxHashMap::default();
) -> Box<OngoingCodegen> {
let cgus = if tcx.sess.opts.output_types.should_codegen() {
tcx.collect_and_partition_mono_items(()).1
} else {
@ -206,62 +357,69 @@ pub(crate) fn run_aot(
}
}
let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx));
let mut concurrency_limiter = ConcurrencyLimiter::new(tcx.sess, cgus.len());
let modules = super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
cgus.iter()
.map(|cgu| {
let cgu_reuse = determine_cgu_reuse(tcx, cgu);
let cgu_reuse = if backend_config.disable_incr_cache {
CguReuse::No
} else {
determine_cgu_reuse(tcx, cgu)
};
tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);
match cgu_reuse {
_ if backend_config.disable_incr_cache => {}
CguReuse::No => {}
CguReuse::PreLto => {
return reuse_workproduct_for_cgu(tcx, &*cgu, &mut work_products);
CguReuse::No => {
let dep_node = cgu.codegen_dep_node(tcx);
tcx.dep_graph
.with_task(
dep_node,
tcx,
(
backend_config.clone(),
global_asm_config.clone(),
cgu.name(),
concurrency_limiter.acquire(),
),
module_codegen,
Some(rustc_middle::dep_graph::hash_result),
)
.0
}
CguReuse::PreLto => unreachable!(),
CguReuse::PostLto => {
concurrency_limiter.job_already_done();
OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, &*cgu))
}
CguReuse::PostLto => unreachable!(),
}
let dep_node = cgu.codegen_dep_node(tcx);
let (ModuleCodegenResult(module, work_product), _) = tcx.dep_graph.with_task(
dep_node,
tcx,
(backend_config.clone(), cgu.name()),
module_codegen,
Some(rustc_middle::dep_graph::hash_result),
);
if let Some((id, product)) = work_product {
work_products.insert(id, product);
}
module
})
.collect::<Vec<_>>()
});
tcx.sess.abort_if_errors();
let isa = crate::build_isa(tcx.sess, &backend_config);
let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string());
assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type());
let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string());
let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true);
let created_alloc_shim =
crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
let allocator_module = if created_alloc_shim {
let ModuleCodegenResult(module, work_product) = emit_module(
tcx,
&backend_config,
"allocator_shim".to_string(),
let mut product = allocator_module.finish();
allocator_unwind_context.emit(&mut product);
match emit_module(
tcx.output_filenames(()),
&tcx.sess.prof,
product.object,
ModuleKind::Allocator,
allocator_module,
None,
allocator_unwind_context,
);
if let Some((id, product)) = work_product {
work_products.insert(id, product);
"allocator_shim".to_owned(),
) {
Ok(allocator_module) => Some(allocator_module),
Err(err) => tcx.sess.fatal(err),
}
Some(module)
} else {
None
};
@ -308,102 +466,14 @@ pub(crate) fn run_aot(
}
.to_owned();
Box::new((
CodegenResults {
modules,
allocator_module,
metadata_module,
metadata,
crate_info: CrateInfo::new(tcx, target_cpu),
},
work_products,
))
}
fn codegen_global_asm(tcx: TyCtxt<'_>, cgu_name: &str, global_asm: &str) {
use std::io::Write;
use std::process::{Command, Stdio};
if global_asm.is_empty() {
return;
}
if cfg!(not(feature = "inline_asm"))
|| tcx.sess.target.is_like_osx
|| tcx.sess.target.is_like_windows
{
if global_asm.contains("__rust_probestack") {
return;
}
// FIXME fix linker error on macOS
if cfg!(not(feature = "inline_asm")) {
tcx.sess.fatal(
"asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift",
);
} else {
tcx.sess.fatal("asm! and global_asm! are not yet supported on macOS and Windows");
}
}
let assembler = crate::toolchain::get_toolchain_binary(tcx.sess, "as");
let linker = crate::toolchain::get_toolchain_binary(tcx.sess, "ld");
// Remove all LLVM style comments
let global_asm = global_asm
.lines()
.map(|line| if let Some(index) = line.find("//") { &line[0..index] } else { line })
.collect::<Vec<_>>()
.join("\n");
let output_object_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name));
// Assemble `global_asm`
let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm");
let mut child = Command::new(assembler)
.arg("-o")
.arg(&global_asm_object_file)
.stdin(Stdio::piped())
.spawn()
.expect("Failed to spawn `as`.");
child.stdin.take().unwrap().write_all(global_asm.as_bytes()).unwrap();
let status = child.wait().expect("Failed to wait for `as`.");
if !status.success() {
tcx.sess.fatal(&format!("Failed to assemble `{}`", global_asm));
}
// Link the global asm and main object file together
let main_object_file = add_file_stem_postfix(output_object_file.clone(), ".main");
std::fs::rename(&output_object_file, &main_object_file).unwrap();
let status = Command::new(linker)
.arg("-r") // Create a new object file
.arg("-o")
.arg(output_object_file)
.arg(&main_object_file)
.arg(&global_asm_object_file)
.status()
.unwrap();
if !status.success() {
tcx.sess.fatal(&format!(
"Failed to link `{}` and `{}` together",
main_object_file.display(),
global_asm_object_file.display(),
));
}
std::fs::remove_file(global_asm_object_file).unwrap();
std::fs::remove_file(main_object_file).unwrap();
}
fn add_file_stem_postfix(mut path: PathBuf, postfix: &str) -> PathBuf {
let mut new_filename = path.file_stem().unwrap().to_owned();
new_filename.push(postfix);
if let Some(extension) = path.extension() {
new_filename.push(".");
new_filename.push(extension);
}
path.set_file_name(new_filename);
path
Box::new(OngoingCodegen {
modules,
allocator_module,
metadata_module,
metadata,
crate_info: CrateInfo::new(tcx, target_cpu),
concurrency_limiter,
})
}
// Adapted from https://github.com/rust-lang/rust/blob/303d8aff6092709edd4dbd35b1c88e9aa40bf6d8/src/librustc_codegen_ssa/base.rs#L922-L953
@ -432,5 +502,5 @@ fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguR
cgu.name()
);
if tcx.try_mark_green(&dep_node) { CguReuse::PreLto } else { CguReuse::No }
if tcx.try_mark_green(&dep_node) { CguReuse::PostLto } else { CguReuse::No }
}

View File

@ -61,11 +61,11 @@ impl UnsafeMessage {
}
}
fn create_jit_module<'tcx>(
tcx: TyCtxt<'tcx>,
fn create_jit_module(
tcx: TyCtxt<'_>,
backend_config: &BackendConfig,
hotswap: bool,
) -> (JITModule, CodegenCx<'tcx>) {
) -> (JITModule, CodegenCx) {
let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string());
let imported_symbols = load_imported_symbols_for_jit(tcx.sess, crate_info);
@ -111,6 +111,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
&backend_config,
matches!(backend_config.codegen_mode, CodegenMode::JitLazy),
);
let mut cached_context = Context::new();
let (_, cgus) = tcx.collect_and_partition_mono_items(());
let mono_items = cgus
@ -128,11 +129,19 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
MonoItem::Fn(inst) => match backend_config.codegen_mode {
CodegenMode::Aot => unreachable!(),
CodegenMode::Jit => {
cx.tcx.sess.time("codegen fn", || {
crate::base::codegen_fn(&mut cx, &mut jit_module, inst)
tcx.sess.time("codegen fn", || {
crate::base::codegen_and_compile_fn(
tcx,
&mut cx,
&mut cached_context,
&mut jit_module,
inst,
)
});
}
CodegenMode::JitLazy => codegen_shim(&mut cx, &mut jit_module, inst),
CodegenMode::JitLazy => {
codegen_shim(tcx, &mut cx, &mut cached_context, &mut jit_module, inst)
}
},
MonoItem::Static(def_id) => {
crate::constant::codegen_static(tcx, &mut jit_module, def_id);
@ -259,7 +268,15 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
false,
Symbol::intern("dummy_cgu_name"),
);
tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, jit_module, instance));
tcx.sess.time("codegen fn", || {
crate::base::codegen_and_compile_fn(
tcx,
&mut cx,
&mut Context::new(),
jit_module,
instance,
)
});
assert!(cx.global_asm.is_empty());
jit_module.finalize_definitions();
@ -334,9 +351,13 @@ fn load_imported_symbols_for_jit(
imported_symbols
}
fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: Instance<'tcx>) {
let tcx = cx.tcx;
fn codegen_shim<'tcx>(
tcx: TyCtxt<'tcx>,
cx: &mut CodegenCx,
cached_context: &mut Context,
module: &mut JITModule,
inst: Instance<'tcx>,
) {
let pointer_type = module.target_config().pointer_type();
let name = tcx.symbol_name(inst).name;
@ -357,8 +378,9 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In
)
.unwrap();
cx.cached_context.clear();
let trampoline = &mut cx.cached_context.func;
let context = cached_context;
context.clear();
let trampoline = &mut context.func;
trampoline.signature = sig.clone();
let mut builder_ctx = FunctionBuilderContext::new();
@ -381,5 +403,6 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In
let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();
trampoline_builder.ins().return_(&ret_vals);
module.define_function(func_id, &mut cx.cached_context).unwrap();
module.define_function(func_id, context).unwrap();
cx.unwind_context.add_function(func_id, context, module.isa());
}

View File

@ -0,0 +1,114 @@
//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
//! standalone executable.
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::sync::Arc;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::ItemId;
use rustc_session::config::{OutputFilenames, OutputType};
use crate::prelude::*;
pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
let item = tcx.hir().item(item_id);
if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind {
if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
global_asm.push_str("\n.intel_syntax noprefix\n");
} else {
global_asm.push_str("\n.att_syntax\n");
}
for piece in asm.template {
match *piece {
InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s),
InlineAsmTemplatePiece::Placeholder { .. } => todo!(),
}
}
global_asm.push_str("\n.att_syntax\n\n");
} else {
bug!("Expected GlobalAsm found {:?}", item);
}
}
#[derive(Debug)]
pub(crate) struct GlobalAsmConfig {
asm_enabled: bool,
assembler: PathBuf,
pub(crate) output_filenames: Arc<OutputFilenames>,
}
impl GlobalAsmConfig {
pub(crate) fn new(tcx: TyCtxt<'_>) -> Self {
let asm_enabled = cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows;
GlobalAsmConfig {
asm_enabled,
assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"),
output_filenames: tcx.output_filenames(()).clone(),
}
}
}
pub(crate) fn compile_global_asm(
config: &GlobalAsmConfig,
cgu_name: &str,
global_asm: &str,
) -> Result<Option<PathBuf>, String> {
if global_asm.is_empty() {
return Ok(None);
}
if !config.asm_enabled {
if global_asm.contains("__rust_probestack") {
return Ok(None);
}
// FIXME fix linker error on macOS
if cfg!(not(feature = "inline_asm")) {
return Err(
"asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift"
.to_owned(),
);
} else {
return Err("asm! and global_asm! are not yet supported on Windows".to_owned());
}
}
// Remove all LLVM style comments
let global_asm = global_asm
.lines()
.map(|line| if let Some(index) = line.find("//") { &line[0..index] } else { line })
.collect::<Vec<_>>()
.join("\n");
let output_object_file = config.output_filenames.temp_path(OutputType::Object, Some(cgu_name));
// Assemble `global_asm`
let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm");
let mut child = Command::new(&config.assembler)
.arg("-o")
.arg(&global_asm_object_file)
.stdin(Stdio::piped())
.spawn()
.expect("Failed to spawn `as`.");
child.stdin.take().unwrap().write_all(global_asm.as_bytes()).unwrap();
let status = child.wait().expect("Failed to wait for `as`.");
if !status.success() {
return Err(format!("Failed to assemble `{}`", global_asm));
}
Ok(Some(global_asm_object_file))
}
pub(crate) fn add_file_stem_postfix(mut path: PathBuf, postfix: &str) -> PathBuf {
let mut new_filename = path.file_stem().unwrap().to_owned();
new_filename.push(postfix);
if let Some(extension) = path.extension() {
new_filename.push(".");
new_filename.push(extension);
}
path.set_file_name(new_filename);
path
}

View File

@ -15,15 +15,19 @@ pub(crate) fn codegen_inline_asm<'tcx>(
template: &[InlineAsmTemplatePiece],
operands: &[InlineAsmOperand<'tcx>],
options: InlineAsmOptions,
destination: Option<mir::BasicBlock>,
) {
// FIXME add .eh_frame unwind info directives
if !template.is_empty() {
// Used by panic_abort
if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
let true_ = fx.bcx.ins().iconst(types::I32, 1);
fx.bcx.ins().trapnz(true_, TrapCode::User(1));
fx.bcx.ins().trap(TrapCode::User(1));
return;
} else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
}
// Used by stdarch
if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
&& matches!(
template[1],
InlineAsmTemplatePiece::Placeholder {
@ -47,51 +51,46 @@ pub(crate) fn codegen_inline_asm<'tcx>(
{
assert_eq!(operands.len(), 4);
let (leaf, eax_place) = match operands[1] {
InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
assert_eq!(
reg,
InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax))
);
(
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
crate::base::codegen_place(fx, out_place.unwrap()),
)
}
InlineAsmOperand::InOut {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
late: true,
ref in_value,
out_place: Some(out_place),
} => (
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
crate::base::codegen_place(fx, out_place),
),
_ => unreachable!(),
};
let ebx_place = match operands[0] {
InlineAsmOperand::Out { reg, late: true, place } => {
assert_eq!(
reg,
InlineAsmOperand::Out {
reg:
InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
X86InlineAsmRegClass::reg
))
);
crate::base::codegen_place(fx, place.unwrap())
}
X86InlineAsmRegClass::reg,
)),
late: true,
place: Some(place),
} => crate::base::codegen_place(fx, place),
_ => unreachable!(),
};
let (sub_leaf, ecx_place) = match operands[2] {
InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
assert_eq!(
reg,
InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx))
);
(
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
crate::base::codegen_place(fx, out_place.unwrap()),
)
}
InlineAsmOperand::InOut {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)),
late: true,
ref in_value,
out_place: Some(out_place),
} => (
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
crate::base::codegen_place(fx, out_place),
),
_ => unreachable!(),
};
let edx_place = match operands[3] {
InlineAsmOperand::Out { reg, late: true, place } => {
assert_eq!(
reg,
InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx))
);
crate::base::codegen_place(fx, place.unwrap())
}
InlineAsmOperand::Out {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
late: true,
place: Some(place),
} => crate::base::codegen_place(fx, place),
_ => unreachable!(),
};
@ -101,12 +100,99 @@ pub(crate) fn codegen_inline_asm<'tcx>(
ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
let destination_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(destination_block, &[]);
return;
} else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
}
// Used by compiler-builtins
if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
// ___chkstk, ___chkstk_ms and __alloca are only used on Windows
crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
return;
} else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
crate::trap::trap_unimplemented(fx, "Alloca is not supported");
return;
}
// Used by measureme
if template[0] == InlineAsmTemplatePiece::String("xor %eax, %eax".to_string())
&& template[1] == InlineAsmTemplatePiece::String("\n".to_string())
&& template[2] == InlineAsmTemplatePiece::String("mov %rbx, ".to_string())
&& matches!(
template[3],
InlineAsmTemplatePiece::Placeholder {
operand_idx: 0,
modifier: Some('r'),
span: _
}
)
&& template[4] == InlineAsmTemplatePiece::String("\n".to_string())
&& template[5] == InlineAsmTemplatePiece::String("cpuid".to_string())
&& template[6] == InlineAsmTemplatePiece::String("\n".to_string())
&& template[7] == InlineAsmTemplatePiece::String("mov ".to_string())
&& matches!(
template[8],
InlineAsmTemplatePiece::Placeholder {
operand_idx: 0,
modifier: Some('r'),
span: _
}
)
&& template[9] == InlineAsmTemplatePiece::String(", %rbx".to_string())
{
let destination_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(destination_block, &[]);
return;
} else if template[0] == InlineAsmTemplatePiece::String("rdpmc".to_string()) {
// Return zero dummy values for all performance counters
match operands[0] {
InlineAsmOperand::In {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)),
value: _,
} => {}
_ => unreachable!(),
};
let lo = match operands[1] {
InlineAsmOperand::Out {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
late: true,
place: Some(place),
} => crate::base::codegen_place(fx, place),
_ => unreachable!(),
};
let hi = match operands[2] {
InlineAsmOperand::Out {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
late: true,
place: Some(place),
} => crate::base::codegen_place(fx, place),
_ => unreachable!(),
};
let u32_layout = fx.layout_of(fx.tcx.types.u32);
let zero = fx.bcx.ins().iconst(types::I32, 0);
lo.write_cvalue(fx, CValue::by_val(zero, u32_layout));
hi.write_cvalue(fx, CValue::by_val(zero, u32_layout));
let destination_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(destination_block, &[]);
return;
} else if template[0] == InlineAsmTemplatePiece::String("lock xadd ".to_string())
&& matches!(
template[1],
InlineAsmTemplatePiece::Placeholder { operand_idx: 1, modifier: None, span: _ }
)
&& template[2] == InlineAsmTemplatePiece::String(", (".to_string())
&& matches!(
template[3],
InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: None, span: _ }
)
&& template[4] == InlineAsmTemplatePiece::String(")".to_string())
{
let destination_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(destination_block, &[]);
return;
}
}
@ -175,6 +261,16 @@ pub(crate) fn codegen_inline_asm<'tcx>(
}
call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs);
match destination {
Some(destination) => {
let destination_block = fx.get_block(destination);
fx.bcx.ins().jump(destination_block, &[]);
}
None => {
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}
}
}
struct InlineAssemblyGenerator<'a, 'tcx> {
@ -637,7 +733,7 @@ fn call_inline_asm<'tcx>(
inputs: Vec<(Size, Value)>,
outputs: Vec<(Size, CPlace<'tcx>)>,
) {
let stack_slot = fx.bcx.func.create_stack_slot(StackSlotData {
let stack_slot = fx.bcx.func.create_sized_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
size: u32::try_from(slot_size.bytes()).unwrap(),
});

View File

@ -62,7 +62,7 @@ pub(crate) fn codegen_cpuid_call<'tcx>(
fx.bcx.ins().jump(dest, &[zero, zero, proc_info_ecx, proc_info_edx]);
fx.bcx.switch_to_block(unsupported_leaf);
crate::trap::trap_unreachable(
crate::trap::trap_unimplemented(
fx,
"__cpuid_count arch intrinsic doesn't yet support specified leaf",
);

View File

@ -139,6 +139,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
.sess
.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
crate::trap::trap_unimplemented(fx, intrinsic);
return;
}
}

View File

@ -44,7 +44,7 @@ fn report_atomic_type_validation_error<'tcx>(
),
);
// Prevent verifier error
crate::trap::trap_unreachable(fx, "compilation should not have succeeded");
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}
pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option<Type> {
@ -53,7 +53,7 @@ pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx
_ => unreachable!(),
};
match scalar_to_clif_type(tcx, element).by(u16::try_from(count).unwrap()) {
match scalar_to_clif_type(tcx, element).by(u32::try_from(count).unwrap()) {
// Cranelift currently only implements icmp for 128bit vectors.
Some(vector_ty) if vector_ty.bits() == 128 => Some(vector_ty),
_ => None,
@ -301,7 +301,44 @@ fn codegen_float_intrinsic_call<'tcx>(
_ => unreachable!(),
};
let res = fx.easy_call(name, &args, ty);
let layout = fx.layout_of(ty);
let res = match intrinsic {
sym::fmaf32 | sym::fmaf64 => {
let a = args[0].load_scalar(fx);
let b = args[1].load_scalar(fx);
let c = args[2].load_scalar(fx);
CValue::by_val(fx.bcx.ins().fma(a, b, c), layout)
}
sym::copysignf32 | sym::copysignf64 => {
let a = args[0].load_scalar(fx);
let b = args[1].load_scalar(fx);
CValue::by_val(fx.bcx.ins().fcopysign(a, b), layout)
}
sym::fabsf32
| sym::fabsf64
| sym::floorf32
| sym::floorf64
| sym::ceilf32
| sym::ceilf64
| sym::truncf32
| sym::truncf64 => {
let a = args[0].load_scalar(fx);
let val = match intrinsic {
sym::fabsf32 | sym::fabsf64 => fx.bcx.ins().fabs(a),
sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(a),
sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(a),
sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(a),
_ => unreachable!(),
};
CValue::by_val(val, layout)
}
// These intrinsics aren't supported natively by Cranelift.
// Lower them to a libcall.
_ => fx.easy_call(name, &args, ty),
};
ret.write_cvalue(fx, res);
true
@ -818,8 +855,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
if fx.tcx.is_compiler_builtins(LOCAL_CRATE) {
// special case for compiler-builtins to avoid having to patch it
crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported");
let ret_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(ret_block, &[]);
return;
} else {
fx.tcx
@ -851,8 +886,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
if fx.tcx.is_compiler_builtins(LOCAL_CRATE) {
// special case for compiler-builtins to avoid having to patch it
crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported");
let ret_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(ret_block, &[]);
return;
} else {
fx.tcx

View File

@ -14,7 +14,7 @@ fn report_simd_type_validation_error(
) {
fx.tcx.sess.span_err(span, &format!("invalid monomorphization of `{}` intrinsic: expected SIMD input type, found non-SIMD `{}`", intrinsic, ty));
// Prevent verifier error
crate::trap::trap_unreachable(fx, "compilation should not have succeeded");
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}
pub(super) fn codegen_simd_intrinsic_call<'tcx>(
@ -157,7 +157,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
),
);
// Prevent verifier error
crate::trap::trap_unreachable(fx, "compilation should not have succeeded");
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
return;
}
}
@ -274,12 +274,17 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
idx_const
} else {
fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant");
let res = crate::trap::trap_unimplemented_ret_value(
let trap_block = fx.bcx.create_block();
let dummy_block = fx.bcx.create_block();
let true_ = fx.bcx.ins().iconst(types::I8, 1);
fx.bcx.ins().brnz(true_, trap_block, &[]);
fx.bcx.ins().jump(dummy_block, &[]);
fx.bcx.switch_to_block(trap_block);
crate::trap::trap_unimplemented(
fx,
ret.layout(),
"Index argument for `simd_extract` is not a constant",
);
ret.write_cvalue(fx, res);
fx.bcx.switch_to_block(dummy_block);
return;
};
@ -392,21 +397,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
let layout = a.layout();
let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
let res_lane_layout = fx.layout_of(lane_ty);
for lane in 0..lane_count {
let a_lane = a.value_lane(fx, lane);
let b_lane = b.value_lane(fx, lane);
let c_lane = c.value_lane(fx, lane);
let a_lane = a.value_lane(fx, lane).load_scalar(fx);
let b_lane = b.value_lane(fx, lane).load_scalar(fx);
let c_lane = c.value_lane(fx, lane).load_scalar(fx);
let res_lane = match lane_ty.kind() {
ty::Float(FloatTy::F32) => {
fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty)
}
ty::Float(FloatTy::F64) => {
fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty)
}
_ => unreachable!(),
};
let res_lane = fx.bcx.ins().fma(a_lane, b_lane, c_lane);
let res_lane = CValue::by_val(res_lane, res_lane_layout);
ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
}

View File

@ -4,6 +4,7 @@
#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]
extern crate jobserver;
#[macro_use]
extern crate rustc_middle;
extern crate rustc_ast;
@ -25,10 +26,12 @@ extern crate rustc_target;
extern crate rustc_driver;
use std::any::Any;
use std::cell::Cell;
use std::cell::{Cell, RefCell};
use std::sync::Arc;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_errors::ErrorGuaranteed;
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
@ -51,11 +54,13 @@ mod cast;
mod codegen_i128;
mod common;
mod compiler_builtins;
mod concurrency_limiter;
mod config;
mod constant;
mod debuginfo;
mod discriminant;
mod driver;
mod global_asm;
mod inline_asm;
mod intrinsics;
mod linkage;
@ -119,19 +124,20 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
/// The codegen context holds any information shared between the codegen of individual functions
/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
struct CodegenCx<'tcx> {
tcx: TyCtxt<'tcx>,
struct CodegenCx {
profiler: SelfProfilerRef,
output_filenames: Arc<OutputFilenames>,
should_write_ir: bool,
global_asm: String,
inline_asm_index: Cell<usize>,
cached_context: Context,
debug_context: Option<DebugContext<'tcx>>,
debug_context: Option<DebugContext>,
unwind_context: UnwindContext,
cgu_name: Symbol,
}
impl<'tcx> CodegenCx<'tcx> {
impl CodegenCx {
fn new(
tcx: TyCtxt<'tcx>,
tcx: TyCtxt<'_>,
backend_config: BackendConfig,
isa: &dyn TargetIsa,
debug_info: bool,
@ -147,10 +153,11 @@ impl<'tcx> CodegenCx<'tcx> {
None
};
CodegenCx {
tcx,
profiler: tcx.prof.clone(),
output_filenames: tcx.output_filenames(()).clone(),
should_write_ir: crate::pretty_clif::should_write_ir(tcx),
global_asm: String::new(),
inline_asm_index: Cell::new(0),
cached_context: Context::new(),
debug_context,
unwind_context,
cgu_name,
@ -159,7 +166,7 @@ impl<'tcx> CodegenCx<'tcx> {
}
pub struct CraneliftCodegenBackend {
pub config: Option<BackendConfig>,
pub config: RefCell<Option<BackendConfig>>,
}
impl CodegenBackend for CraneliftCodegenBackend {
@ -169,6 +176,13 @@ impl CodegenBackend for CraneliftCodegenBackend {
Lto::No | Lto::ThinLocal => {}
Lto::Thin | Lto::Fat => sess.warn("LTO is not supported. You may get a linker error."),
}
let mut config = self.config.borrow_mut();
if config.is_none() {
let new_config = BackendConfig::from_opts(&sess.opts.cg.llvm_args)
.unwrap_or_else(|err| sess.fatal(&err));
*config = Some(new_config);
}
}
fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<rustc_span::Symbol> {
@ -186,15 +200,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
need_metadata_module: bool,
) -> Box<dyn Any> {
tcx.sess.abort_if_errors();
let config = if let Some(config) = self.config.clone() {
config
} else {
if !tcx.sess.unstable_options() && !tcx.sess.opts.cg.llvm_args.is_empty() {
tcx.sess.fatal("`-Z unstable-options` must be passed to allow configuring cg_clif");
}
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
.unwrap_or_else(|err| tcx.sess.fatal(&err))
};
let config = self.config.borrow().clone().unwrap();
match config.codegen_mode {
CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
CodegenMode::Jit | CodegenMode::JitLazy => {
@ -210,12 +216,13 @@ impl CodegenBackend for CraneliftCodegenBackend {
fn join_codegen(
&self,
ongoing_codegen: Box<dyn Any>,
_sess: &Session,
sess: &Session,
_outputs: &OutputFilenames,
) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
Ok(*ongoing_codegen
.downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
.unwrap())
Ok(ongoing_codegen
.downcast::<driver::aot::OngoingCodegen>()
.unwrap()
.join(sess, self.config.borrow().as_ref().unwrap()))
}
fn link(
@ -312,5 +319,5 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
Box::new(CraneliftCodegenBackend { config: None })
Box::new(CraneliftCodegenBackend { config: RefCell::new(None) })
}

View File

@ -1,20 +1,3 @@
//! Various optimizations specific to cg_clif
use cranelift_codegen::isa::TargetIsa;
use crate::prelude::*;
pub(crate) mod peephole;
pub(crate) fn optimize_function<'tcx>(
tcx: TyCtxt<'tcx>,
isa: &dyn TargetIsa,
instance: Instance<'tcx>,
ctx: &mut Context,
clif_comments: &mut crate::pretty_clif::CommentWriter,
) {
// FIXME classify optimizations over opt levels once we have more
crate::pretty_clif::write_clif_file(tcx, "preopt", isa, instance, &ctx.func, &*clif_comments);
crate::base::verify_func(tcx, &*clif_comments, &ctx.func);
}

View File

@ -62,7 +62,7 @@ use cranelift_codegen::{
};
use rustc_middle::ty::layout::FnAbiOf;
use rustc_session::config::OutputType;
use rustc_session::config::{OutputFilenames, OutputType};
use crate::prelude::*;
@ -205,15 +205,11 @@ pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
}
pub(crate) fn write_ir_file(
tcx: TyCtxt<'_>,
name: impl FnOnce() -> String,
output_filenames: &OutputFilenames,
name: &str,
write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
) {
if !should_write_ir(tcx) {
return;
}
let clif_output_dir = tcx.output_filenames(()).with_extension("clif");
let clif_output_dir = output_filenames.with_extension("clif");
match std::fs::create_dir(&clif_output_dir) {
Ok(()) => {}
@ -221,44 +217,43 @@ pub(crate) fn write_ir_file(
res @ Err(_) => res.unwrap(),
}
let clif_file_name = clif_output_dir.join(name());
let clif_file_name = clif_output_dir.join(name);
let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file));
if let Err(err) = res {
tcx.sess.warn(&format!("error writing ir file: {}", err));
// Using early_warn as no Session is available here
rustc_session::early_warn(
rustc_session::config::ErrorOutputType::default(),
&format!("error writing ir file: {}", err),
);
}
}
pub(crate) fn write_clif_file<'tcx>(
tcx: TyCtxt<'tcx>,
pub(crate) fn write_clif_file(
output_filenames: &OutputFilenames,
symbol_name: &str,
postfix: &str,
isa: &dyn cranelift_codegen::isa::TargetIsa,
instance: Instance<'tcx>,
func: &cranelift_codegen::ir::Function,
mut clif_comments: &CommentWriter,
) {
// FIXME work around filename too long errors
write_ir_file(
tcx,
|| format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
|file| {
let mut clif = String::new();
cranelift_codegen::write::decorate_function(&mut clif_comments, &mut clif, func)
.unwrap();
write_ir_file(output_filenames, &format!("{}.{}.clif", symbol_name, postfix), |file| {
let mut clif = String::new();
cranelift_codegen::write::decorate_function(&mut clif_comments, &mut clif, func).unwrap();
for flag in isa.flags().iter() {
writeln!(file, "set {}", flag)?;
}
write!(file, "target {}", isa.triple().architecture.to_string())?;
for isa_flag in isa.isa_flags().iter() {
write!(file, " {}", isa_flag)?;
}
writeln!(file, "\n")?;
writeln!(file)?;
file.write_all(clif.as_bytes())?;
Ok(())
},
);
for flag in isa.flags().iter() {
writeln!(file, "set {}", flag)?;
}
write!(file, "target {}", isa.triple().architecture.to_string())?;
for isa_flag in isa.isa_flags().iter() {
write!(file, " {}", isa_flag)?;
}
writeln!(file, "\n")?;
writeln!(file)?;
file.write_all(clif.as_bytes())?;
Ok(())
});
}
impl fmt::Debug for FunctionCx<'_, '_, '_> {

View File

@ -8,10 +8,8 @@ use rustc_session::Session;
/// Tries to infer the path of a binary for the target toolchain from the linker name.
pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf {
let (mut linker, _linker_flavor) = linker_and_flavor(sess);
let linker_file_name = linker
.file_name()
.and_then(|name| name.to_str())
.unwrap_or_else(|| sess.fatal("couldn't extract file name from specified linker"));
let linker_file_name =
linker.file_name().unwrap().to_str().expect("linker filename should be valid UTF-8");
if linker_file_name == "ld.lld" {
if tool != "ld" {

View File

@ -25,33 +25,10 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) {
fx.bcx.ins().call(puts, &[msg_ptr]);
}
/// Use this for example when a function call should never return. This will fill the current block,
/// so you can **not** add instructions to it afterwards.
///
/// Trap code: user65535
pub(crate) fn trap_unreachable(fx: &mut FunctionCx<'_, '_, '_>, msg: impl AsRef<str>) {
codegen_print(fx, msg.as_ref());
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}
/// Use this when something is unimplemented, but `libcore` or `libstd` requires it to codegen.
/// Unlike `trap_unreachable` this will not fill the current block, so you **must** add instructions
/// to it afterwards.
///
/// Trap code: user65535
pub(crate) fn trap_unimplemented(fx: &mut FunctionCx<'_, '_, '_>, msg: impl AsRef<str>) {
codegen_print(fx, msg.as_ref());
let true_ = fx.bcx.ins().iconst(types::I32, 1);
fx.bcx.ins().trapnz(true_, TrapCode::User(!0));
}
/// Like `trap_unimplemented` but returns a fake value of the specified type.
///
/// Trap code: user65535
pub(crate) fn trap_unimplemented_ret_value<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
dest_layout: TyAndLayout<'tcx>,
msg: impl AsRef<str>,
) -> CValue<'tcx> {
trap_unimplemented(fx, msg);
CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout)
fx.bcx.ins().trap(TrapCode::User(!0));
}

View File

@ -122,7 +122,7 @@ impl<'tcx> CValue<'tcx> {
let clif_ty = match layout.abi {
Abi::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar),
Abi::Vector { element, count } => scalar_to_clif_type(fx.tcx, element)
.by(u16::try_from(count).unwrap())
.by(u32::try_from(count).unwrap())
.unwrap(),
_ => unreachable!("{:?}", layout.ty),
};
@ -330,7 +330,7 @@ impl<'tcx> CPlace<'tcx> {
.fatal(&format!("values of type {} are too big to store on the stack", layout.ty));
}
let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
// specify stack slot alignment.
@ -472,7 +472,7 @@ impl<'tcx> CPlace<'tcx> {
}
_ if src_ty.is_vector() || dst_ty.is_vector() => {
// FIXME do something more efficient for transmutes between vectors and integers.
let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
// specify stack slot alignment.
@ -519,7 +519,7 @@ impl<'tcx> CPlace<'tcx> {
if let ty::Array(element, len) = dst_layout.ty.kind() {
// Can only happen for vector types
let len =
u16::try_from(len.eval_usize(fx.tcx, ParamEnv::reveal_all())).unwrap();
u32::try_from(len.eval_usize(fx.tcx, ParamEnv::reveal_all())).unwrap();
let vector_ty = fx.clif_type(*element).unwrap().by(len).unwrap();
let data = match from.0 {
@ -614,7 +614,7 @@ impl<'tcx> CPlace<'tcx> {
dst_align,
src_align,
true,
MemFlags::trusted(),
flags,
);
}
CValueInner::ByRef(_, Some(_)) => todo!(),

View File

@ -1,13 +1,2 @@
#!/usr/bin/env bash
set -e
./y.rs build --sysroot none "$@"
rm -r target/out || true
scripts/tests.sh no_sysroot
./y.rs build "$@"
scripts/tests.sh base_sysroot
scripts/tests.sh extended_sysroot
exec ./y.rs test

View File

@ -3,7 +3,6 @@ A `break` statement without a label appeared inside a labeled block.
Erroneous code example:
```compile_fail,E0695
# #![feature(label_break_value)]
loop {
'a: {
break;
@ -14,7 +13,6 @@ loop {
Make sure to always label the `break`:
```
# #![feature(label_break_value)]
'l: loop {
'a: {
break 'l;
@ -25,7 +23,6 @@ Make sure to always label the `break`:
Or if you want to `break` the labeled block:
```
# #![feature(label_break_value)]
loop {
'a: {
break 'a;

View File

@ -4,3 +4,40 @@ interface_ferris_identifier =
interface_emoji_identifier =
identifiers cannot contain emoji: `{$ident}`
interface_mixed_bin_crate =
cannot mix `bin` crate type with others
interface_mixed_proc_macro_crate =
cannot mix `proc-macro` crate type with others
interface_proc_macro_doc_without_arg =
Trying to document proc macro crate without passing '--crate-type proc-macro to rustdoc
.warn = The generated documentation may be incorrect
interface_error_writing_dependencies =
error writing dependencies to `{$path}`: {$error}
interface_input_file_would_be_overwritten =
the input file "{$path}" would be overwritten by the generated executable
interface_generated_file_conflicts_with_directory =
the generated executable for the input file "{$input_path}" conflicts with the existing directory "{$dir_path}"
interface_temps_dir_error =
failed to find or create the directory specified by `--temps-dir`
interface_out_dir_error =
failed to find or create the directory specified by `--out-dir`
interface_cant_emit_mir =
could not emit MIR: {$error}
interface_rustc_error_fatal =
fatal error triggered by #[rustc_error]
interface_rustc_error_unexpected_annotation =
unexpected annotation used with `#[rustc_error(...)]!
interface_failed_writing_file =
failed to write file {$path}: {$error}"

View File

@ -0,0 +1 @@
save_analysis_could_not_open = Could not open `{$file_name}`: `{$err}`

View File

@ -43,6 +43,7 @@ fluent_messages! {
passes => "../locales/en-US/passes.ftl",
plugin_impl => "../locales/en-US/plugin_impl.ftl",
privacy => "../locales/en-US/privacy.ftl",
save_analysis => "../locales/en-US/save_analysis.ftl",
typeck => "../locales/en-US/typeck.ftl",
}

View File

@ -13,6 +13,7 @@ use rustc_span::{edition::Edition, Span, DUMMY_SP};
use std::borrow::Cow;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::path::{Path, PathBuf};
/// Error type for `Diagnostic`'s `suggestions` field, indicating that
/// `.disable_suggestions()` was called on the `Diagnostic`.
@ -83,6 +84,7 @@ into_diagnostic_arg_using_display!(
u64,
i128,
u128,
std::io::Error,
std::num::NonZeroU32,
hir::Target,
Edition,
@ -124,6 +126,18 @@ impl IntoDiagnosticArg for String {
}
}
impl<'a> IntoDiagnosticArg for &'a Path {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
}
}
impl IntoDiagnosticArg for PathBuf {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
}
}
impl IntoDiagnosticArg for usize {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Number(self)

View File

@ -186,6 +186,8 @@ declare_features! (
/// Allows some increased flexibility in the name resolution rules,
/// especially around globs and shadowing (RFC 1560).
(accepted, item_like_imports, "1.15.0", Some(35120), None),
/// Allows `'a: { break 'a; }`.
(accepted, label_break_value, "1.65.0", Some(48594), None),
/// Allows `if/while p && let q = r && ...` chains.
(accepted, let_chains, "1.64.0", Some(53667), None),
/// Allows `break {expr}` with a value inside `loop`s.

View File

@ -420,8 +420,6 @@ declare_features! (
(active, intra_doc_pointers, "1.51.0", Some(80896), None),
/// Allows `#[instruction_set(_)]` attribute
(active, isa_attribute, "1.48.0", Some(74727), None),
/// Allows `'a: { break 'a; }`.
(active, label_break_value, "1.28.0", Some(48594), None),
// Allows setting the threshold for the `large_assignments` lint.
(active, large_assignments, "1.52.0", Some(83518), None),
/// Allows `let...else` statements.

View File

@ -17,7 +17,7 @@
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(extend_one)]
#![feature(label_break_value)]
#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(never_type)]

View File

@ -0,0 +1,89 @@
use rustc_macros::SessionDiagnostic;
use rustc_span::{Span, Symbol};
use std::io;
use std::path::Path;
#[derive(SessionDiagnostic)]
#[diag(interface::ferris_identifier)]
pub struct FerrisIdentifier {
#[primary_span]
pub spans: Vec<Span>,
#[suggestion(code = "ferris", applicability = "maybe-incorrect")]
pub first_span: Span,
}
#[derive(SessionDiagnostic)]
#[diag(interface::emoji_identifier)]
pub struct EmojiIdentifier {
#[primary_span]
pub spans: Vec<Span>,
pub ident: Symbol,
}
#[derive(SessionDiagnostic)]
#[diag(interface::mixed_bin_crate)]
pub struct MixedBinCrate;
#[derive(SessionDiagnostic)]
#[diag(interface::mixed_proc_macro_crate)]
pub struct MixedProcMacroCrate;
#[derive(SessionDiagnostic)]
#[diag(interface::proc_macro_doc_without_arg)]
pub struct ProcMacroDocWithoutArg;
#[derive(SessionDiagnostic)]
#[diag(interface::error_writing_dependencies)]
pub struct ErrorWritingDependencies<'a> {
pub path: &'a Path,
pub error: io::Error,
}
#[derive(SessionDiagnostic)]
#[diag(interface::input_file_would_be_overwritten)]
pub struct InputFileWouldBeOverWritten<'a> {
pub path: &'a Path,
}
#[derive(SessionDiagnostic)]
#[diag(interface::generated_file_conflicts_with_directory)]
pub struct GeneratedFileConflictsWithDirectory<'a> {
pub input_path: &'a Path,
pub dir_path: &'a Path,
}
#[derive(SessionDiagnostic)]
#[diag(interface::temps_dir_error)]
pub struct TempsDirError;
#[derive(SessionDiagnostic)]
#[diag(interface::out_dir_error)]
pub struct OutDirError;
#[derive(SessionDiagnostic)]
#[diag(interface::cant_emit_mir)]
pub struct CantEmitMIR {
pub error: io::Error,
}
#[derive(SessionDiagnostic)]
#[diag(interface::rustc_error_fatal)]
pub struct RustcErrorFatal {
#[primary_span]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[diag(interface::rustc_error_unexpected_annotation)]
pub struct RustcErrorUnexpectedAnnotation {
#[primary_span]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[diag(interface::failed_writing_file)]
pub struct FailedWritingFile<'a> {
pub path: &'a Path,
pub error: io::Error,
}

View File

@ -5,8 +5,11 @@
#![feature(once_cell)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
mod callbacks;
mod errors;
pub mod interface;
mod passes;
mod proc_macro_decls;

View File

@ -1,3 +1,8 @@
use crate::errors::{
CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier,
GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate,
MixedProcMacroCrate, OutDirError, ProcMacroDocWithoutArg, TempsDirError,
};
use crate::interface::{Compiler, Result};
use crate::proc_macro_decls;
use crate::util;
@ -13,7 +18,6 @@ use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
use rustc_hir::def_id::StableCrateId;
use rustc_hir::definitions::Definitions;
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore};
use rustc_macros::SessionDiagnostic;
use rustc_metadata::creader::CStore;
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
@ -31,7 +35,7 @@ use rustc_session::output::filename_for_input;
use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{FileName, Span};
use rustc_span::FileName;
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
use tracing::{info, warn};
@ -264,23 +268,6 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> {
}
}
#[derive(SessionDiagnostic)]
#[diag(interface::ferris_identifier)]
struct FerrisIdentifier {
#[primary_span]
spans: Vec<Span>,
#[suggestion(code = "ferris", applicability = "maybe-incorrect")]
first_span: Span,
}
#[derive(SessionDiagnostic)]
#[diag(interface::emoji_identifier)]
struct EmojiIdentifier {
#[primary_span]
spans: Vec<Span>,
ident: Symbol,
}
/// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
/// syntax expansion, secondary `cfg` expansion, synthesis of a test
/// harness if one is to be provided, injection of a dependency on the
@ -392,10 +379,10 @@ pub fn configure_and_expand(
if crate_types.len() > 1 {
if is_executable_crate {
sess.err("cannot mix `bin` crate type with others");
sess.emit_err(MixedBinCrate);
}
if is_proc_macro_crate {
sess.err("cannot mix `proc-macro` crate type with others");
sess.emit_err(MixedProcMacroCrate);
}
}
@ -406,13 +393,7 @@ pub fn configure_and_expand(
// However, we do emit a warning, to let such users know that they should
// start passing '--crate-type proc-macro'
if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate {
let mut msg = sess.diagnostic().struct_warn(
"Trying to document proc macro crate \
without passing '--crate-type proc-macro to rustdoc",
);
msg.warn("The generated documentation may be incorrect");
msg.emit();
sess.emit_warning(ProcMacroDocWithoutArg);
} else {
krate = sess.time("maybe_create_a_macro_crate", || {
let is_test_crate = sess.opts.test;
@ -666,11 +647,9 @@ fn write_out_deps(
.emit_artifact_notification(&deps_filename, "dep-info");
}
}
Err(e) => sess.fatal(&format!(
"error writing dependencies to `{}`: {}",
deps_filename.display(),
e
)),
Err(error) => {
sess.emit_fatal(ErrorWritingDependencies { path: &deps_filename, error });
}
}
}
@ -700,20 +679,12 @@ pub fn prepare_outputs(
if let Some(ref input_path) = compiler.input_path {
if sess.opts.will_create_output_file() {
if output_contains_path(&output_paths, input_path) {
let reported = sess.err(&format!(
"the input file \"{}\" would be overwritten by the generated \
executable",
input_path.display()
));
let reported = sess.emit_err(InputFileWouldBeOverWritten { path: input_path });
return Err(reported);
}
if let Some(dir_path) = output_conflicts_with_dir(&output_paths) {
let reported = sess.err(&format!(
"the generated executable for the input file \"{}\" conflicts with the \
existing directory \"{}\"",
input_path.display(),
dir_path.display()
));
if let Some(ref dir_path) = output_conflicts_with_dir(&output_paths) {
let reported =
sess.emit_err(GeneratedFileConflictsWithDirectory { input_path, dir_path });
return Err(reported);
}
}
@ -721,8 +692,7 @@ pub fn prepare_outputs(
if let Some(ref dir) = compiler.temps_dir {
if fs::create_dir_all(dir).is_err() {
let reported =
sess.err("failed to find or create the directory specified by `--temps-dir`");
let reported = sess.emit_err(TempsDirError);
return Err(reported);
}
}
@ -735,8 +705,7 @@ pub fn prepare_outputs(
if !only_dep_info {
if let Some(ref dir) = compiler.output_dir {
if fs::create_dir_all(dir).is_err() {
let reported =
sess.err("failed to find or create the directory specified by `--out-dir`");
let reported = sess.emit_err(OutDirError);
return Err(reported);
}
}
@ -1019,8 +988,8 @@ pub fn start_codegen<'tcx>(
info!("Post-codegen\n{:?}", tcx.debug_stats());
if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
if let Err(e) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) {
tcx.sess.err(&format!("could not emit MIR: {}", e));
if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) {
tcx.sess.emit_err(CantEmitMIR { error });
tcx.sess.abort_if_errors();
}
}

View File

@ -1,3 +1,4 @@
use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation};
use crate::interface::{Compiler, Result};
use crate::passes::{self, BoxedResolver, QueryContext};
@ -274,18 +275,14 @@ impl<'tcx> Queries<'tcx> {
// Bare `#[rustc_error]`.
None => {
tcx.sess.span_fatal(
tcx.def_span(def_id),
"fatal error triggered by #[rustc_error]",
);
tcx.sess.emit_fatal(RustcErrorFatal { span: tcx.def_span(def_id) });
}
// Some other attribute.
Some(_) => {
tcx.sess.span_warn(
tcx.def_span(def_id),
"unexpected annotation used with `#[rustc_error(...)]!",
);
tcx.sess.emit_warning(RustcErrorUnexpectedAnnotation {
span: tcx.def_span(def_id),
});
}
}
}
@ -360,9 +357,8 @@ impl Linker {
if sess.opts.unstable_opts.no_link {
let encoded = CodegenResults::serialize_rlink(&codegen_results);
let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT);
std::fs::write(&rlink_file, encoded).map_err(|err| {
sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err));
})?;
std::fs::write(&rlink_file, encoded)
.map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?;
return Ok(());
}

View File

@ -1,6 +1,7 @@
use crate::build::matches::ArmHasGuard;
use crate::build::ForGuard::OutsideGuard;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use rustc_middle::middle::region::Scope;
use rustc_middle::thir::*;
use rustc_middle::{mir::*, ty};
use rustc_span::Span;
@ -34,10 +35,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&stmts,
expr,
safety_mode,
region_scope,
))
})
} else {
this.ast_block_stmts(destination, block, span, &stmts, expr, safety_mode)
this.ast_block_stmts(
destination,
block,
span,
&stmts,
expr,
safety_mode,
region_scope,
)
}
})
})
@ -51,6 +61,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
stmts: &[StmtId],
expr: Option<&Expr<'tcx>>,
safety_mode: BlockSafety,
region_scope: Scope,
) -> BlockAnd<()> {
let this = self;
@ -73,6 +84,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut let_scope_stack = Vec::with_capacity(8);
let outer_source_scope = this.source_scope;
let outer_in_scope_unsafe = this.in_scope_unsafe;
// This scope information is kept for breaking out of the parent remainder scope in case
// one let-else pattern matching fails.
// By doing so, we can be sure that even temporaries that receive extended lifetime
// assignments are dropped, too.
let mut last_remainder_scope = region_scope;
this.update_source_scope_for_safety_mode(span, safety_mode);
let source_info = this.source_info(span);
@ -132,7 +148,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
initializer_span,
else_block,
visibility_scope,
*remainder_scope,
last_remainder_scope,
remainder_span,
pattern,
)
@ -178,6 +194,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if let Some(source_scope) = visibility_scope {
this.source_scope = source_scope;
}
last_remainder_scope = *remainder_scope;
}
}

View File

@ -22,7 +22,7 @@ use rustc_errors::{
use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, Ident};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
use std::ops::{Deref, DerefMut};
@ -977,15 +977,6 @@ impl<'a> Parser<'a> {
let mut err = self.struct_span_err(self.token.span, &msg_exp);
if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
if symbol.as_str() == "public" {
err.span_suggestion_short(
self.prev_token.span,
"write `pub` instead of `public` to make the item public",
"pub",
appl,
);
}
if ["def", "fun", "func", "function"].contains(&symbol.as_str()) {
err.span_suggestion_short(
self.prev_token.span,
@ -996,6 +987,19 @@ impl<'a> Parser<'a> {
}
}
// `pub` may be used for an item or `pub(crate)`
if self.prev_token.is_ident_named(sym::public)
&& (self.token.can_begin_item()
|| self.token.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
{
err.span_suggestion_short(
self.prev_token.span,
"write `pub` instead of `public` to make the item public",
"pub",
appl,
);
}
// Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens
// there are unclosed angle brackets
if self.unmatched_angle_bracket_count > 0

View File

@ -2014,10 +2014,6 @@ impl<'a> Parser<'a> {
}
}
if let Some(label) = opt_label {
self.sess.gated_spans.gate(sym::label_break_value, label.ident.span);
}
if self.token.is_whole_block() {
self.sess.emit_err(InvalidBlockMacroSegment {
span: self.token.span,

View File

@ -9,9 +9,11 @@ rustc_middle = { path = "../rustc_middle" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_macros = { path = "../rustc_macros" }
serde_json = "1"
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }

View File

@ -0,0 +1,10 @@
use rustc_macros::SessionDiagnostic;
use std::path::Path;
#[derive(SessionDiagnostic)]
#[diag(save_analysis::could_not_open)]
pub(crate) struct CouldNotOpen<'a> {
pub file_name: &'a Path,
pub err: std::io::Error,
}

View File

@ -3,11 +3,15 @@
#![feature(let_else)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![feature(never_type)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
mod dump_visitor;
mod dumper;
#[macro_use]
mod span_utils;
mod errors;
mod sig;
use rustc_ast as ast;
@ -928,7 +932,7 @@ impl<'a> DumpHandler<'a> {
info!("Writing output to {}", file_name.display());
let output_file = BufWriter::new(File::create(&file_name).unwrap_or_else(|e| {
sess.fatal(&format!("Could not open {}: {}", file_name.display(), e))
sess.emit_fatal(errors::CouldNotOpen { file_name: file_name.as_path(), err: e })
}));
(output_file, file_name)

View File

@ -1119,6 +1119,7 @@ symbols! {
ptr_offset_from_unsigned,
pub_macro_rules,
pub_restricted,
public,
pure,
pushpop_unsafe,
qreg,

View File

@ -16,7 +16,7 @@
#![feature(control_flow_enum)]
#![feature(drain_filter)]
#![feature(hash_drain_filter)]
#![feature(label_break_value)]
#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(let_else)]
#![feature(if_let_guard)]
#![feature(never_type)]

View File

@ -64,7 +64,7 @@ This API is completely unstable and subject to change.
#![feature(if_let_guard)]
#![feature(is_sorted)]
#![feature(iter_intersperse)]
#![feature(label_break_value)]
#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(never_type)]

View File

@ -1189,6 +1189,12 @@ impl<T> Option<T> {
/// Returns [`None`] if the option is [`None`], otherwise returns `optb`.
///
/// Arguments passed to `and` are eagerly evaluated; if you are passing the
/// result of a function call, it is recommended to use [`and_then`], which is
/// lazily evaluated.
///
/// [`and_then`]: Option::and_then
///
/// # Examples
///
/// ```

View File

@ -1285,6 +1285,11 @@ impl<T, E> Result<T, E> {
/// Returns `res` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`.
///
/// Arguments passed to `and` are eagerly evaluated; if you are passing the
/// result of a function call, it is recommended to use [`and_then`], which is
/// lazily evaluated.
///
/// [`and_then`]: Result::and_then
///
/// # Examples
///

View File

@ -252,7 +252,7 @@
#![feature(dropck_eyepatch)]
#![feature(exhaustive_patterns)]
#![feature(intra_doc_pointers)]
#![feature(label_break_value)]
#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(lang_items)]
#![feature(let_else)]
#![feature(linkage)]

View File

@ -47,7 +47,7 @@ h4 {
.docblock pre > code, pre > code {
color: #e6e1cf;
}
span code {
.item-info code {
color: #e6e1cf;
}
.docblock a > code {

View File

@ -1,5 +0,0 @@
pub fn main() {
'a: { //~ ERROR labels on blocks are unstable
break 'a;
}
}

View File

@ -1,12 +0,0 @@
error[E0658]: labels on blocks are unstable
--> $DIR/feature-gate-label_break_value.rs:2:5
|
LL | 'a: {
| ^^
|
= note: see issue #48594 <https://github.com/rust-lang/rust/issues/48594> for more information
= help: add `#![feature(label_break_value)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,7 +1,6 @@
// run-pass
#![allow(dead_code)]
#![allow(unused_assignments)]
#![feature(label_break_value)]
// Test control flow to follow label_break_value semantics
fn label_break(a: bool, b: bool) -> u32 {

View File

@ -1,5 +1,4 @@
#![crate_type = "lib"]
#![feature(label_break_value)]
fn lbv_macro_test_hygiene_respected() {
macro_rules! mac2 {

View File

@ -1,5 +1,5 @@
error[E0426]: use of undeclared label `'a`
--> $DIR/label_break_value_invalid.rs:7:19
--> $DIR/label_break_value_invalid.rs:6:19
|
LL | break 'a $val;
| ^^ undeclared label `'a`
@ -10,7 +10,7 @@ LL | mac2!(2);
= note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0426]: use of undeclared label `'a`
--> $DIR/label_break_value_invalid.rs:29:19
--> $DIR/label_break_value_invalid.rs:28:19
|
LL | let x: u8 = mac3!('b: {
| -- a label with a similar name is reachable
@ -22,7 +22,7 @@ LL | break 'a 3;
| help: try using similarly named label: `'b`
error[E0426]: use of undeclared label `'a`
--> $DIR/label_break_value_invalid.rs:34:29
--> $DIR/label_break_value_invalid.rs:33:29
|
LL | let x: u8 = mac3!(break 'a 4);
| ^^ undeclared label `'a`

View File

@ -1,5 +1,3 @@
#![feature(label_break_value)]
fn main() {
// This used to ICE during liveness check because `target_id` passed to
// `propagate_through_expr` would be the closure and not the `loop`, which wouldn't be found in

View File

@ -1,5 +1,5 @@
error[E0767]: use of unreachable label `'a`
--> $DIR/issue-62480.rs:8:18
--> $DIR/issue-62480.rs:6:18
|
LL | 'a: {
| -- unreachable label defined here
@ -9,7 +9,7 @@ LL | || break 'a
= note: labels are unreachable through functions, closures, async blocks and modules
error[E0267]: `break` inside of a closure
--> $DIR/issue-62480.rs:8:12
--> $DIR/issue-62480.rs:6:12
|
LL | || break 'a
| -- ^^^^^^^^ cannot `break` inside of a closure

View File

@ -1,4 +1,3 @@
#![feature(label_break_value)]
#![allow(unused_labels)]
// Simple continue pointing to an unlabeled break should yield in an error

View File

@ -1,11 +1,11 @@
error[E0695]: unlabeled `continue` inside of a labeled block
--> $DIR/label_break_value_continue.rs:7:9
--> $DIR/label_break_value_continue.rs:6:9
|
LL | continue;
| ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label
error[E0696]: `continue` pointing to a labeled block
--> $DIR/label_break_value_continue.rs:14:9
--> $DIR/label_break_value_continue.rs:13:9
|
LL | / 'b: {
LL | | continue 'b;
@ -14,7 +14,7 @@ LL | | }
| |_____- labeled block the `continue` points to
error[E0695]: unlabeled `continue` inside of a labeled block
--> $DIR/label_break_value_continue.rs:22:13
--> $DIR/label_break_value_continue.rs:21:13
|
LL | continue;
| ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label

View File

@ -1,5 +1,5 @@
// compile-flags: --edition 2018
#![feature(label_break_value, try_blocks)]
#![feature(try_blocks)]
// run-pass
fn main() {
@ -9,4 +9,11 @@ fn main() {
break 'foo;
}
};
'foo: {
let _: Result<(), ()> = try {
Err(())?;
break 'foo;
};
}
}

View File

@ -1,5 +1,4 @@
// run-rustfix
#![feature(label_break_value)]
// These are forbidden occurrences of label-break-value

View File

@ -1,5 +1,4 @@
// run-rustfix
#![feature(label_break_value)]
// These are forbidden occurrences of label-break-value

View File

@ -1,23 +1,23 @@
error: block label not supported here
--> $DIR/label_break_value_illegal_uses.rs:8:12
--> $DIR/label_break_value_illegal_uses.rs:7:12
|
LL | unsafe 'b: {}
| ^^^ not supported here
error: block label not supported here
--> $DIR/label_break_value_illegal_uses.rs:12:13
--> $DIR/label_break_value_illegal_uses.rs:11:13
|
LL | if true 'b: {}
| ^^^ not supported here
error: block label not supported here
--> $DIR/label_break_value_illegal_uses.rs:16:21
--> $DIR/label_break_value_illegal_uses.rs:15:21
|
LL | if true {} else 'b: {}
| ^^^ not supported here
error: block label not supported here
--> $DIR/label_break_value_illegal_uses.rs:20:17
--> $DIR/label_break_value_illegal_uses.rs:19:17
|
LL | match false 'b: {
| ^^^ not supported here

View File

@ -1,4 +1,3 @@
#![feature(label_break_value)]
#![allow(unused_labels)]
// Simple unlabeled break should yield in an error

View File

@ -1,11 +1,11 @@
error[E0695]: unlabeled `break` inside of a labeled block
--> $DIR/label_break_value_unlabeled_break.rs:7:9
--> $DIR/label_break_value_unlabeled_break.rs:6:9
|
LL | break;
| ^^^^^ `break` statements that would diverge to or through a labeled block need to bear a label
error[E0695]: unlabeled `break` inside of a labeled block
--> $DIR/label_break_value_unlabeled_break.rs:15:13
--> $DIR/label_break_value_unlabeled_break.rs:14:13
|
LL | break;
| ^^^^^ `break` statements that would diverge to or through a labeled block need to bear a label

View File

@ -74,6 +74,17 @@ fn main() {
};
}
}
{
fn must_pass() {
let rc = Rc::new(());
let &None = &Some(Rc::clone(&rc)) else {
Rc::try_unwrap(rc).unwrap();
return;
};
unreachable!();
}
must_pass();
}
{
// test let-else drops temps before else block
// NOTE: this test has to be the last block in the `main`

View File

@ -4,7 +4,6 @@
// check-pass
#![feature(label_break_value)]
#![warn(unused_labels)]
fn main() {

View File

@ -1,5 +1,5 @@
warning: label name `'many_used_shadowed` shadows a label name that is already in scope
--> $DIR/unused_labels.rs:62:9
--> $DIR/unused_labels.rs:61:9
|
LL | 'many_used_shadowed: for _ in 0..10 {
| ------------------- first declared here
@ -8,55 +8,55 @@ LL | 'many_used_shadowed: for _ in 0..10 {
| ^^^^^^^^^^^^^^^^^^^ label `'many_used_shadowed` already in scope
warning: unused label
--> $DIR/unused_labels.rs:11:5
--> $DIR/unused_labels.rs:10:5
|
LL | 'unused_while_label: while 0 == 0 {
| ^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/unused_labels.rs:8:9
--> $DIR/unused_labels.rs:7:9
|
LL | #![warn(unused_labels)]
| ^^^^^^^^^^^^^
warning: unused label
--> $DIR/unused_labels.rs:16:5
--> $DIR/unused_labels.rs:15:5
|
LL | 'unused_while_let_label: while let Some(_) = opt {
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: unused label
--> $DIR/unused_labels.rs:20:5
--> $DIR/unused_labels.rs:19:5
|
LL | 'unused_for_label: for _ in 0..10 {
| ^^^^^^^^^^^^^^^^^
warning: unused label
--> $DIR/unused_labels.rs:36:9
--> $DIR/unused_labels.rs:35:9
|
LL | 'unused_loop_label_inner_2: for _ in 0..10 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused label
--> $DIR/unused_labels.rs:42:5
--> $DIR/unused_labels.rs:41:5
|
LL | 'unused_loop_label_outer_3: for _ in 0..10 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused label
--> $DIR/unused_labels.rs:60:5
--> $DIR/unused_labels.rs:59:5
|
LL | 'many_used_shadowed: for _ in 0..10 {
| ^^^^^^^^^^^^^^^^^^^
warning: unused label
--> $DIR/unused_labels.rs:72:5
--> $DIR/unused_labels.rs:71:5
|
LL | 'unused_loop_label: loop {
| ^^^^^^^^^^^^^^^^^^
warning: unused label
--> $DIR/unused_labels.rs:78:5
--> $DIR/unused_labels.rs:77:5
|
LL | 'unused_block_label: {
| ^^^^^^^^^^^^^^^^^^^

View File

@ -9,7 +9,6 @@
#![feature(decl_macro)]
#![feature(generators)]
#![feature(half_open_range_patterns)]
#![feature(label_break_value)]
#![feature(more_qualified_paths)]
#![feature(raw_ref_op)]
#![feature(trait_alias)]

View File

@ -1,5 +1,3 @@
#![feature(label_break_value)]
fn main() {}
macro_rules! m {

View File

@ -1,5 +1,5 @@
error: cannot use a `block` macro fragment here
--> $DIR/bad-interpolated-block.rs:7:15
--> $DIR/bad-interpolated-block.rs:5:15
|
LL | 'lab: $b;
| ------^^
@ -12,7 +12,7 @@ LL | m!({});
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot use a `block` macro fragment here
--> $DIR/bad-interpolated-block.rs:8:16
--> $DIR/bad-interpolated-block.rs:6:16
|
LL | unsafe $b;
| -------^^
@ -25,7 +25,7 @@ LL | m!({});
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot use a `block` macro fragment here
--> $DIR/bad-interpolated-block.rs:9:23
--> $DIR/bad-interpolated-block.rs:7:23
|
LL | |x: u8| -> () $b;
| ^^ the `block` fragment is within this context

View File

@ -1,5 +1,3 @@
#![feature(label_break_value)]
fn main() {
'l0 while false {} //~ ERROR labeled expression must be followed by `:`
'l1 for _ in 0..1 {} //~ ERROR labeled expression must be followed by `:`

View File

@ -1,5 +1,5 @@
error: labeled expression must be followed by `:`
--> $DIR/labeled-no-colon-expr.rs:4:5
--> $DIR/labeled-no-colon-expr.rs:2:5
|
LL | 'l0 while false {}
| ----^^^^^^^^^^^^^^
@ -10,7 +10,7 @@ LL | 'l0 while false {}
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
error: labeled expression must be followed by `:`
--> $DIR/labeled-no-colon-expr.rs:5:5
--> $DIR/labeled-no-colon-expr.rs:3:5
|
LL | 'l1 for _ in 0..1 {}
| ----^^^^^^^^^^^^^^^^
@ -21,7 +21,7 @@ LL | 'l1 for _ in 0..1 {}
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
error: labeled expression must be followed by `:`
--> $DIR/labeled-no-colon-expr.rs:6:5
--> $DIR/labeled-no-colon-expr.rs:4:5
|
LL | 'l2 loop {}
| ----^^^^^^^
@ -32,7 +32,7 @@ LL | 'l2 loop {}
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
error: labeled expression must be followed by `:`
--> $DIR/labeled-no-colon-expr.rs:7:5
--> $DIR/labeled-no-colon-expr.rs:5:5
|
LL | 'l3 {}
| ----^^
@ -43,7 +43,7 @@ LL | 'l3 {}
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
error: expected `while`, `for`, `loop` or `{` after a label
--> $DIR/labeled-no-colon-expr.rs:8:9
--> $DIR/labeled-no-colon-expr.rs:6:9
|
LL | 'l4 0;
| ^ expected `while`, `for`, `loop` or `{` after a label
@ -55,7 +55,7 @@ LL + 0;
|
error: labeled expression must be followed by `:`
--> $DIR/labeled-no-colon-expr.rs:8:9
--> $DIR/labeled-no-colon-expr.rs:6:9
|
LL | 'l4 0;
| ----^
@ -66,7 +66,7 @@ LL | 'l4 0;
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
error: cannot use a `block` macro fragment here
--> $DIR/labeled-no-colon-expr.rs:13:17
--> $DIR/labeled-no-colon-expr.rs:11:17
|
LL | 'l5 $b;
| ----^^
@ -79,7 +79,7 @@ LL | m!({});
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: labeled expression must be followed by `:`
--> $DIR/labeled-no-colon-expr.rs:16:8
--> $DIR/labeled-no-colon-expr.rs:14:8
|
LL | 'l5 $b;
| ---- help: add `:` after the label

View File

@ -0,0 +1,11 @@
// Checks what happens when `public` is used instead of the correct, `pub`
// run-rustfix
pub enum Test {
//~^ ERROR expected one of `!` or `::`, found keyword `enum`
//~^^ HELP write `pub` instead of `public` to make the item public
A,
B,
}
fn main() { }

View File

@ -0,0 +1,11 @@
// Checks what happens when `public` is used instead of the correct, `pub`
// run-rustfix
public enum Test {
//~^ ERROR expected one of `!` or `::`, found keyword `enum`
//~^^ HELP write `pub` instead of `public` to make the item public
A,
B,
}
fn main() { }

View File

@ -0,0 +1,13 @@
error: expected one of `!` or `::`, found keyword `enum`
--> $DIR/public-instead-of-pub-1.rs:4:8
|
LL | public enum Test {
| ^^^^ expected one of `!` or `::`
|
help: write `pub` instead of `public` to make the item public
|
LL | pub enum Test {
| ~~~
error: aborting due to previous error

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