mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
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:
commit
9b9bc63599
@ -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",
|
||||
|
@ -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)]
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
3
compiler/rustc_codegen_cranelift/.gitignore
vendored
3
compiler/rustc_codegen_cranelift/.gitignore
vendored
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
]
|
||||
|
60
compiler/rustc_codegen_cranelift/build_system/abi_checker.rs
Normal file
60
compiler/rustc_codegen_cranelift/build_system/abi_checker.rs
Normal 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);
|
||||
}
|
@ -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";
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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('_', "-")
|
||||
}
|
||||
|
619
compiler/rustc_codegen_cranelift/build_system/tests.rs
Normal file
619
compiler/rustc_codegen_cranelift/build_system/tests.rs
Normal 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));
|
||||
}
|
||||
}
|
@ -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")
|
||||
}
|
||||
|
@ -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/
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
@ -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)
|
||||
|
@ -1,3 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2022-07-25"
|
||||
channel = "nightly-2022-08-24"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
@ -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
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
168
compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
Normal file
168
compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
114
compiler/rustc_codegen_cranelift/src/global_asm.rs
Normal file
114
compiler/rustc_codegen_cranelift/src/global_asm.rs
Normal 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
|
||||
}
|
@ -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(),
|
||||
});
|
||||
|
@ -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",
|
||||
);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) })
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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<'_, '_, '_> {
|
||||
|
@ -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" {
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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!(),
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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}"
|
||||
|
@ -0,0 +1 @@
|
||||
save_analysis_could_not_open = Could not open `{$file_name}`: `{$err}`
|
@ -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",
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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)]
|
||||
|
89
compiler/rustc_interface/src/errors.rs
Normal file
89
compiler/rustc_interface/src/errors.rs
Normal 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,
|
||||
}
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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(());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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" }
|
||||
|
10
compiler/rustc_save_analysis/src/errors.rs
Normal file
10
compiler/rustc_save_analysis/src/errors.rs
Normal 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,
|
||||
}
|
@ -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)
|
||||
|
@ -1119,6 +1119,7 @@ symbols! {
|
||||
ptr_offset_from_unsigned,
|
||||
pub_macro_rules,
|
||||
pub_restricted,
|
||||
public,
|
||||
pure,
|
||||
pushpop_unsafe,
|
||||
qreg,
|
||||
|
@ -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)]
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
///
|
||||
/// ```
|
||||
|
@ -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
|
||||
///
|
||||
|
@ -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)]
|
||||
|
@ -47,7 +47,7 @@ h4 {
|
||||
.docblock pre > code, pre > code {
|
||||
color: #e6e1cf;
|
||||
}
|
||||
span code {
|
||||
.item-info code {
|
||||
color: #e6e1cf;
|
||||
}
|
||||
.docblock a > code {
|
||||
|
@ -1,5 +0,0 @@
|
||||
pub fn main() {
|
||||
'a: { //~ ERROR labels on blocks are unstable
|
||||
break 'a;
|
||||
}
|
||||
}
|
@ -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`.
|
@ -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 {
|
||||
|
@ -1,5 +1,4 @@
|
||||
#![crate_type = "lib"]
|
||||
#![feature(label_break_value)]
|
||||
|
||||
fn lbv_macro_test_hygiene_respected() {
|
||||
macro_rules! mac2 {
|
||||
|
@ -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`
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,3 @@
|
||||
#![feature(label_break_value)]
|
||||
#![allow(unused_labels)]
|
||||
|
||||
// Simple continue pointing to an unlabeled break should yield in an error
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
// run-rustfix
|
||||
#![feature(label_break_value)]
|
||||
|
||||
// These are forbidden occurrences of label-break-value
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
// run-rustfix
|
||||
#![feature(label_break_value)]
|
||||
|
||||
// These are forbidden occurrences of label-break-value
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,3 @@
|
||||
#![feature(label_break_value)]
|
||||
#![allow(unused_labels)]
|
||||
|
||||
// Simple unlabeled break should yield in an error
|
||||
|
@ -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
|
||||
|
@ -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`
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
// check-pass
|
||||
|
||||
#![feature(label_break_value)]
|
||||
#![warn(unused_labels)]
|
||||
|
||||
fn main() {
|
||||
|
@ -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: {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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)]
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(label_break_value)]
|
||||
|
||||
fn main() {}
|
||||
|
||||
macro_rules! m {
|
||||
|
@ -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
|
||||
|
@ -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 `:`
|
||||
|
@ -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
|
||||
|
11
src/test/ui/parser/public-instead-of-pub-1.fixed
Normal file
11
src/test/ui/parser/public-instead-of-pub-1.fixed
Normal 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() { }
|
11
src/test/ui/parser/public-instead-of-pub-1.rs
Normal file
11
src/test/ui/parser/public-instead-of-pub-1.rs
Normal 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() { }
|
13
src/test/ui/parser/public-instead-of-pub-1.stderr
Normal file
13
src/test/ui/parser/public-instead-of-pub-1.stderr
Normal 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
Loading…
Reference in New Issue
Block a user