Merge branch 'master' of https://github.com/rust-lang/rust
This commit is contained in:
commit
c8f5d6d80d
1043 changed files with 13638 additions and 8494 deletions
8
.gitattributes
vendored
8
.gitattributes
vendored
|
|
@ -16,11 +16,3 @@ config.toml.example linguist-language=TOML
|
|||
*.ico binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
|
||||
# Needed as part of converting rustfmt to a subtree, can hopefully be removed later.
|
||||
src/tools/rustfmt/tests/source/issue-3494/crlf.rs -text
|
||||
src/tools/rustfmt/tests/source/comment_crlf_newline.rs -text
|
||||
src/tools/rustfmt/tests/source/configs/enum_discrim_align_threshold/40.rs -text
|
||||
src/tools/rustfmt/tests/target/issue-3494/crlf.rs -text
|
||||
src/tools/rustfmt/tests/target/comment_crlf_newline.rs -text
|
||||
src/tools/rustfmt/tests/target/configs/enum_discrim_align_threshold/40.rs -text
|
||||
|
|
|
|||
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
|
|
@ -259,6 +259,11 @@ jobs:
|
|||
- name: x86_64-gnu
|
||||
os: ubuntu-latest-xl
|
||||
env: {}
|
||||
- name: x86_64-gnu-stable
|
||||
env:
|
||||
IMAGE: x86_64-gnu
|
||||
RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable
|
||||
os: ubuntu-latest-xl
|
||||
- name: x86_64-gnu-aux
|
||||
os: ubuntu-latest-xl
|
||||
env: {}
|
||||
|
|
|
|||
147
Cargo.lock
147
Cargo.lock
|
|
@ -278,6 +278,7 @@ dependencies = [
|
|||
"humantime 2.0.1",
|
||||
"ignore",
|
||||
"im-rc",
|
||||
"itertools 0.10.0",
|
||||
"jobserver",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
|
|
@ -293,7 +294,7 @@ dependencies = [
|
|||
"rand 0.8.3",
|
||||
"rustc-workspace-hack",
|
||||
"rustfix",
|
||||
"semver 0.10.0",
|
||||
"semver 1.0.3",
|
||||
"serde",
|
||||
"serde_ignored",
|
||||
"serde_json",
|
||||
|
|
@ -551,10 +552,10 @@ name = "clippy"
|
|||
version = "0.1.54"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.12.0",
|
||||
"clippy-mini-macro-test",
|
||||
"clippy_lints",
|
||||
"compiletest_rs",
|
||||
"derive-new",
|
||||
"filetime",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-workspace-hack",
|
||||
|
|
@ -566,10 +567,6 @@ dependencies = [
|
|||
"tester",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clippy-mini-macro-test"
|
||||
version = "0.2.0"
|
||||
|
||||
[[package]]
|
||||
name = "clippy_dev"
|
||||
version = "0.0.1"
|
||||
|
|
@ -655,9 +652,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.43"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65af2dcae4779003dfa91aedc6ade7bdc7ba685944e50a8b4f9380df376a4466"
|
||||
checksum = "787187ae221adfcda34b03006f1617099e4ae26b50e5a4db282496014ab75837"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
@ -1715,6 +1712,15 @@ dependencies = [
|
|||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.6"
|
||||
|
|
@ -1743,11 +1749,10 @@ dependencies = [
|
|||
"fs-err",
|
||||
"getopts",
|
||||
"jsonpath_lib",
|
||||
"lazy_static",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shlex 0.1.1",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2128,16 +2133,16 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"shlex 1.0.0",
|
||||
"shlex",
|
||||
"tempfile",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "measureme"
|
||||
version = "9.1.1"
|
||||
version = "9.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49cf14eb7d2eea897d9949b68f19e165638755e3a1a3c0941b6b6c3e00141f2c"
|
||||
checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d"
|
||||
dependencies = [
|
||||
"log",
|
||||
"memmap2",
|
||||
|
|
@ -2149,9 +2154,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.3"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
|
|
@ -2289,6 +2294,7 @@ dependencies = [
|
|||
"hex 0.4.2",
|
||||
"libc",
|
||||
"log",
|
||||
"measureme",
|
||||
"rand 0.8.3",
|
||||
"rustc-workspace-hack",
|
||||
"rustc_version",
|
||||
|
|
@ -2353,6 +2359,17 @@ dependencies = [
|
|||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8bc1d42047cf336f0f939c99e97183cf31551bf0f2865a2ec9c8d91fd4ffb5e"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.7.2"
|
||||
|
|
@ -2845,9 +2862,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "racer"
|
||||
version = "2.1.47"
|
||||
version = "2.1.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "513c70e67444a0d62fdc581dffa521c6820942a5f08300d0864863f8d0e750e3"
|
||||
checksum = "7fec2e85e7a30f8fd31b7cf288ad363b5e51fd2cb6f53b416b0cfaabd84e1ccb"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap",
|
||||
|
|
@ -3071,7 +3088,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"cargo",
|
||||
"cargo-util",
|
||||
"cargo_metadata 0.8.2",
|
||||
"cargo_metadata 0.12.0",
|
||||
"clippy_lints",
|
||||
"crossbeam-channel",
|
||||
"difference",
|
||||
|
|
@ -3204,9 +3221,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_arena"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "526610f47139efa440178239553b59ea805ff57a532b4e295c71d2a9b18fd676"
|
||||
checksum = "550ca1a0925d31a0af089b18c89f5adf3b286e319e3e1f1a5204c21bd2f17371"
|
||||
dependencies = [
|
||||
"rustc-ap-rustc_data_structures",
|
||||
"smallvec",
|
||||
|
|
@ -3214,9 +3231,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_ast"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf6a9dda0804a7243b0282e3b75a8cf4654c7a61f033e587751941e1fe39391b"
|
||||
checksum = "4aa53b68080df17994a54747f7c37b0686288a670efb9ba3b382ce62e744aed2"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"rustc-ap-rustc_data_structures",
|
||||
|
|
@ -3231,9 +3248,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_ast_pretty"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82f5019be8b41a58664169fd2f4b1a37fe82705681db394b76419e4e87d40ab1"
|
||||
checksum = "0ae71e68fada466a4b2c39c79ca6aee3226587abe6787170d2f6c92237569565"
|
||||
dependencies = [
|
||||
"rustc-ap-rustc_ast",
|
||||
"rustc-ap-rustc_span",
|
||||
|
|
@ -3242,9 +3259,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_data_structures"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a701717fb14549331085756b9741ae3b4bf35808489f1887d72c1d0e0fe52b77"
|
||||
checksum = "faa484d6e0ca32d1d82303647275c696f745599b3d97e686f396ceef5b99d7ae"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
|
|
@ -3274,9 +3291,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_errors"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3182ce85e8bfc96443475547f2f5aa2b5e67655d9b88721795f36f0ba9e265a"
|
||||
checksum = "5f85ba19cca320ad797e3a29c35cab9bddfff0e7adbde336a436249e54cee7b1"
|
||||
dependencies = [
|
||||
"annotate-snippets",
|
||||
"atty",
|
||||
|
|
@ -3294,9 +3311,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_feature"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eed033b93270126ef60963c3ebbd0e026bf53b985172b6366c7b0e7881c9d507"
|
||||
checksum = "97d538adab96b8b2b1ca9fcd4c8c47d4e23e862a23d1a38b6c15cd8fd52b34b1"
|
||||
dependencies = [
|
||||
"rustc-ap-rustc_data_structures",
|
||||
"rustc-ap-rustc_span",
|
||||
|
|
@ -3304,21 +3321,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_fs_util"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28ee6531986a205101e09fd143d7bf31897388f33b1814d4bcc45fd62211dca6"
|
||||
checksum = "8ad6f13d240944fa8f360d2f3b849a7cadaec75e477829e7dde61e838deda83d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_graphviz"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3398fddc0e23d2db89c036f8952ddf78cadc597f7059752116e69483e164a5b6"
|
||||
checksum = "08b3451153cc5828c02cc4f1a0df146d25ac4b3382a112e25fd9d3f5bff15cdc"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_index"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dca4e27eb5b701f6bbd47d8fc9d242378fca3e4107a519a28415c2989c4a3bd3"
|
||||
checksum = "cd39a9f01b442c629bdff5778cb3dd29b7c2ea4afe62d5ab61d216bd1b556692"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"rustc-ap-rustc_macros",
|
||||
|
|
@ -3327,18 +3344,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_lexer"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "786bbfe9d4d5264294c1819dbf1497a2480b583d5eda1ca9ae22e12d6661f5df"
|
||||
checksum = "a5de290c44a90e671d2cd730062b9ef73d11155da7e44e7741d633e1e51e616e"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_lint_defs"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be2f045e2b999c154ec505d5fea69c994b742f3ebd2f552d11a6c81723921e47"
|
||||
checksum = "69570b4beb61088926b131579865bbe70d124d30778c46307a62ec8b310ae462"
|
||||
dependencies = [
|
||||
"rustc-ap-rustc_ast",
|
||||
"rustc-ap-rustc_data_structures",
|
||||
|
|
@ -3351,9 +3368,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_macros"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27789cd26d6b9e2fdfa68a262a20664d79ca67d31a3886d40fb88ebf6935869c"
|
||||
checksum = "86bd877df37f15c5a44d9679d1b5207ebc95f3943fbc336eeac670195ac58610"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -3363,9 +3380,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_parse"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dc331f4958350679679e619d63a891e8d5d34ef99087068c89aa9e657d52caa"
|
||||
checksum = "02502d8522ba31d0bcad28a78822b68c1b6ba947a2b4aa6a2341b30594379b80"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"rustc-ap-rustc_ast",
|
||||
|
|
@ -3383,9 +3400,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_serialize"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9a6824a462c4c1a379e911b0faf86d303a54bcf8673d4cc445195085966a4a4"
|
||||
checksum = "5f741f8e9aee6323fbe127329490608a5a250cc0072ac91e684ef62518cdb1ff"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"smallvec",
|
||||
|
|
@ -3393,9 +3410,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_session"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a782a5f6ada0dbe089c6416ad0104f0b8a8bdb4bd26ea95e5fefaec67aed5e8a"
|
||||
checksum = "dba61eca749f4fced4427ad1cc7f23342cfc6527c3bcc624e3aa56abc1f81298"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"getopts",
|
||||
|
|
@ -3415,9 +3432,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_span"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a257546cb264b250c7abdb81239bb02f18a274a966211755a3ea89411b122214"
|
||||
checksum = "a642e8d6fc883f34e0778e079f8242ac40c6614a6b7a0ef61681333e847f5e62"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"md-5",
|
||||
|
|
@ -3435,9 +3452,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_target"
|
||||
version = "718.0.0"
|
||||
version = "722.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a72dd689421bcb5750f3ed0dedf367076e714ef0ba56c02ed391b9a8582862"
|
||||
checksum = "80feebd8c323b80dd73a395fa7fabba9e2098b6277670ff89c473f618ffa07de"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"rustc-ap-rustc_data_structures",
|
||||
|
|
@ -3676,6 +3693,7 @@ dependencies = [
|
|||
"rustc_incremental",
|
||||
"rustc_index",
|
||||
"rustc_llvm",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
|
|
@ -3695,7 +3713,7 @@ dependencies = [
|
|||
"itertools 0.9.0",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"object",
|
||||
"object 0.25.2",
|
||||
"pathdiff",
|
||||
"rustc_apfloat",
|
||||
"rustc_ast",
|
||||
|
|
@ -4673,6 +4691,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
|
|
@ -4793,12 +4820,6 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.0.0"
|
||||
|
|
@ -4903,7 +4924,7 @@ dependencies = [
|
|||
"hermit-abi",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"object 0.22.0",
|
||||
"panic_abort",
|
||||
"panic_unwind",
|
||||
"profiler_builtins",
|
||||
|
|
@ -5032,9 +5053,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.33"
|
||||
version = "0.4.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228"
|
||||
checksum = "7d779dc6aeff029314570f666ec83f19df7280bb36ef338442cfa8c604021b80"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"libc",
|
||||
|
|
|
|||
|
|
@ -623,12 +623,13 @@ impl Pat {
|
|||
PatKind::Ident(_, _, Some(p)) => p.walk(it),
|
||||
|
||||
// Walk into each field of struct.
|
||||
PatKind::Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)),
|
||||
PatKind::Struct(_, _, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)),
|
||||
|
||||
// Sequence of patterns.
|
||||
PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) | PatKind::Or(s) => {
|
||||
s.iter().for_each(|p| p.walk(it))
|
||||
}
|
||||
PatKind::TupleStruct(_, _, s)
|
||||
| PatKind::Tuple(s)
|
||||
| PatKind::Slice(s)
|
||||
| PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
|
||||
|
||||
// Trivial wrappers over inner patterns.
|
||||
PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
|
||||
|
|
@ -701,10 +702,10 @@ pub enum PatKind {
|
|||
|
||||
/// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
|
||||
/// The `bool` is `true` in the presence of a `..`.
|
||||
Struct(Path, Vec<PatField>, /* recovered */ bool),
|
||||
Struct(Option<QSelf>, Path, Vec<PatField>, /* recovered */ bool),
|
||||
|
||||
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
|
||||
TupleStruct(Path, Vec<P<Pat>>),
|
||||
TupleStruct(Option<QSelf>, Path, Vec<P<Pat>>),
|
||||
|
||||
/// An or-pattern `A | B | C`.
|
||||
/// Invariant: `pats.len() >= 2`.
|
||||
|
|
@ -1247,6 +1248,7 @@ pub enum StructRest {
|
|||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct StructExpr {
|
||||
pub qself: Option<QSelf>,
|
||||
pub path: Path,
|
||||
pub fields: Vec<ExprField>,
|
||||
pub rest: StructRest,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ impl AstLike for crate::token::Nonterminal {
|
|||
Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
|
||||
Nonterminal::NtPath(path) => path.tokens_mut(),
|
||||
Nonterminal::NtVis(vis) => vis.tokens_mut(),
|
||||
_ => panic!("Called tokens_mut on {:?}", self),
|
||||
Nonterminal::NtBlock(block) => block.tokens_mut(),
|
||||
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) | Nonterminal::NtTT(..) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,13 +12,11 @@
|
|||
#![feature(box_patterns)]
|
||||
#![cfg_attr(bootstrap, feature(const_fn_unsize))]
|
||||
#![feature(const_fn_transmute)]
|
||||
#![feature(const_panic)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(label_break_value)]
|
||||
#![feature(nll)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_step)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
|||
|
|
@ -1139,7 +1139,8 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
|||
visit_opt(sub, |sub| vis.visit_pat(sub));
|
||||
}
|
||||
PatKind::Lit(e) => vis.visit_expr(e),
|
||||
PatKind::TupleStruct(path, elems) => {
|
||||
PatKind::TupleStruct(qself, path, elems) => {
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
visit_vec(elems, |elem| vis.visit_pat(elem));
|
||||
}
|
||||
|
|
@ -1147,7 +1148,8 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
|||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
}
|
||||
PatKind::Struct(path, fields, _etc) => {
|
||||
PatKind::Struct(qself, path, fields, _etc) => {
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
fields.flat_map_in_place(|field| vis.flat_map_pat_field(field));
|
||||
}
|
||||
|
|
@ -1333,7 +1335,8 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
|||
}
|
||||
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
ExprKind::Struct(se) => {
|
||||
let StructExpr { path, fields, rest } = se.deref_mut();
|
||||
let StructExpr { qself, path, fields, rest } = se.deref_mut();
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
fields.flat_map_in_place(|field| vis.flat_map_expr_field(field));
|
||||
match rest {
|
||||
|
|
|
|||
|
|
@ -218,8 +218,7 @@ impl AttrAnnotatedTokenStream {
|
|||
AttrAnnotatedTokenTree::Attributes(data) => {
|
||||
let mut outer_attrs = Vec::new();
|
||||
let mut inner_attrs = Vec::new();
|
||||
let attrs: Vec<_> = data.attrs.clone().into();
|
||||
for attr in attrs {
|
||||
for attr in &data.attrs {
|
||||
match attr.style {
|
||||
crate::AttrStyle::Outer => {
|
||||
assert!(
|
||||
|
|
@ -264,7 +263,7 @@ impl AttrAnnotatedTokenStream {
|
|||
// so we never reach this code.
|
||||
|
||||
let mut builder = TokenStreamBuilder::new();
|
||||
for inner_attr in &inner_attrs {
|
||||
for inner_attr in inner_attrs {
|
||||
builder.push(inner_attr.tokens().to_tokenstream());
|
||||
}
|
||||
builder.push(delim_tokens.clone());
|
||||
|
|
|
|||
|
|
@ -497,7 +497,10 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
|
|||
|
||||
pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
||||
match pattern.kind {
|
||||
PatKind::TupleStruct(ref path, ref elems) => {
|
||||
PatKind::TupleStruct(ref opt_qself, ref path, ref elems) => {
|
||||
if let Some(ref qself) = *opt_qself {
|
||||
visitor.visit_ty(&qself.ty);
|
||||
}
|
||||
visitor.visit_path(path, pattern.id);
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
}
|
||||
|
|
@ -507,7 +510,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
|||
}
|
||||
visitor.visit_path(path, pattern.id)
|
||||
}
|
||||
PatKind::Struct(ref path, ref fields, _) => {
|
||||
PatKind::Struct(ref opt_qself, ref path, ref fields, _) => {
|
||||
if let Some(ref qself) = *opt_qself {
|
||||
visitor.visit_ty(&qself.ty);
|
||||
}
|
||||
visitor.visit_path(path, pattern.id);
|
||||
walk_list!(visitor, visit_pat_field, fields);
|
||||
}
|
||||
|
|
@ -740,6 +746,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||
visitor.visit_anon_const(count)
|
||||
}
|
||||
ExprKind::Struct(ref se) => {
|
||||
if let Some(ref qself) = se.qself {
|
||||
visitor.visit_ty(&qself.ty);
|
||||
}
|
||||
visitor.visit_path(&se.path, expression.id);
|
||||
walk_list!(visitor, visit_expr_field, &se.fields);
|
||||
match &se.rest {
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ExprKind::Struct(
|
||||
self.arena.alloc(self.lower_qpath(
|
||||
e.id,
|
||||
&None,
|
||||
&se.qself,
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
|
|
@ -1041,10 +1041,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
/// It is not a complete check, but just tries to reject most paths early
|
||||
/// if they are not tuple structs.
|
||||
/// Type checking will take care of the full validation later.
|
||||
fn extract_tuple_struct_path<'a>(&mut self, expr: &'a Expr) -> Option<&'a Path> {
|
||||
// For tuple struct destructuring, it must be a non-qualified path (like in patterns).
|
||||
if let ExprKind::Path(None, path) = &expr.kind {
|
||||
// Does the path resolves to something disallowed in a tuple struct/variant pattern?
|
||||
fn extract_tuple_struct_path<'a>(
|
||||
&mut self,
|
||||
expr: &'a Expr,
|
||||
) -> Option<(&'a Option<QSelf>, &'a Path)> {
|
||||
if let ExprKind::Path(qself, path) = &expr.kind {
|
||||
// Does the path resolve to something disallowed in a tuple struct/variant pattern?
|
||||
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
||||
if partial_res.unresolved_segments() == 0
|
||||
&& !partial_res.base_res().expected_in_tuple_struct_pat()
|
||||
|
|
@ -1052,7 +1054,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
return None;
|
||||
}
|
||||
}
|
||||
return Some(path);
|
||||
return Some((qself, path));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
@ -1088,7 +1090,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
// Tuple structs.
|
||||
ExprKind::Call(callee, args) => {
|
||||
if let Some(path) = self.extract_tuple_struct_path(callee) {
|
||||
if let Some((qself, path)) = self.extract_tuple_struct_path(callee) {
|
||||
let (pats, rest) = self.destructure_sequence(
|
||||
args,
|
||||
"tuple struct or variant",
|
||||
|
|
@ -1097,7 +1099,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
let qpath = self.lower_qpath(
|
||||
callee.id,
|
||||
&None,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
|
|
@ -1122,7 +1124,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}));
|
||||
let qpath = self.lower_qpath(
|
||||
lhs.id,
|
||||
&None,
|
||||
&se.qself,
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ use rustc_ast::walk_list;
|
|||
use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -198,7 +198,7 @@ pub trait ResolverAstLowering {
|
|||
|
||||
fn next_node_id(&mut self) -> NodeId;
|
||||
|
||||
fn trait_map(&self) -> &NodeMap<Vec<hir::TraitCandidate>>;
|
||||
fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>;
|
||||
|
||||
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
|
||||
|
||||
|
|
@ -501,14 +501,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let proc_macros =
|
||||
c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect();
|
||||
|
||||
let trait_map = self
|
||||
.resolver
|
||||
.trait_map()
|
||||
.iter()
|
||||
.filter_map(|(&k, v)| {
|
||||
self.node_id_to_hir_id.get(k).and_then(|id| id.as_ref()).map(|id| (*id, v.clone()))
|
||||
})
|
||||
.collect();
|
||||
let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
|
||||
for (k, v) in self.resolver.take_trait_map().into_iter() {
|
||||
if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) {
|
||||
let map = trait_map.entry(hir_id.owner).or_default();
|
||||
map.insert(hir_id.local_id, v.into_boxed_slice());
|
||||
}
|
||||
}
|
||||
|
||||
let mut def_id_to_hir_id = IndexVec::default();
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
|
||||
}
|
||||
PatKind::Lit(ref e) => break hir::PatKind::Lit(self.lower_expr(e)),
|
||||
PatKind::TupleStruct(ref path, ref pats) => {
|
||||
PatKind::TupleStruct(ref qself, ref path, ref pats) => {
|
||||
let qpath = self.lower_qpath(
|
||||
pattern.id,
|
||||
&None,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
|
|
@ -47,10 +47,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
);
|
||||
break hir::PatKind::Path(qpath);
|
||||
}
|
||||
PatKind::Struct(ref path, ref fields, etc) => {
|
||||
PatKind::Struct(ref qself, ref path, ref fields, etc) => {
|
||||
let qpath = self.lower_qpath(
|
||||
pattern.id,
|
||||
&None,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
|
|
|
|||
|
|
@ -938,8 +938,11 @@ fn validate_generic_param_order(
|
|||
}
|
||||
GenericParamKind::Type { default: None } => (),
|
||||
GenericParamKind::Lifetime => (),
|
||||
// FIXME(const_generics_defaults)
|
||||
GenericParamKind::Const { ty: _, kw_span: _, default: _ } => (),
|
||||
GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
|
||||
ordered_params += " = ";
|
||||
ordered_params += &pprust::expr_to_string(&*default.value);
|
||||
}
|
||||
GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
|
@ -959,7 +962,7 @@ fn validate_generic_param_order(
|
|||
span,
|
||||
&format!(
|
||||
"reorder the parameters: lifetimes, {}",
|
||||
if sess.features_untracked().const_generics {
|
||||
if sess.features_untracked().unordered_const_ty_params() {
|
||||
"then consts and types"
|
||||
} else {
|
||||
"then types, then consts"
|
||||
|
|
|
|||
|
|
@ -318,7 +318,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}}
|
||||
|
||||
gate_doc!(
|
||||
include => external_doc
|
||||
cfg => doc_cfg
|
||||
masked => doc_masked
|
||||
notable_trait => doc_notable_trait
|
||||
|
|
@ -706,6 +705,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
|||
"async closures are unstable",
|
||||
"to use an async block, remove the `||`: `async {`"
|
||||
);
|
||||
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
|
||||
gate_all!(generators, "yield syntax is experimental");
|
||||
gate_all!(raw_ref_op, "raw address of syntax is experimental");
|
||||
gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#![feature(bindings_after_at)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(box_patterns)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1713,11 +1713,16 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_expr_struct(
|
||||
&mut self,
|
||||
qself: &Option<ast::QSelf>,
|
||||
path: &ast::Path,
|
||||
fields: &[ast::ExprField],
|
||||
rest: &ast::StructRest,
|
||||
) {
|
||||
self.print_path(path, true, 0);
|
||||
if let Some(qself) = qself {
|
||||
self.print_qpath(path, qself, true);
|
||||
} else {
|
||||
self.print_path(path, true, 0);
|
||||
}
|
||||
self.s.word("{");
|
||||
self.commasep_cmnt(
|
||||
Consistent,
|
||||
|
|
@ -1874,7 +1879,7 @@ impl<'a> State<'a> {
|
|||
self.print_expr_repeat(element, count);
|
||||
}
|
||||
ast::ExprKind::Struct(ref se) => {
|
||||
self.print_expr_struct(&se.path, &se.fields, &se.rest);
|
||||
self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
|
||||
}
|
||||
ast::ExprKind::Tup(ref exprs) => {
|
||||
self.print_expr_tup(exprs);
|
||||
|
|
@ -2340,8 +2345,12 @@ impl<'a> State<'a> {
|
|||
self.print_pat(p);
|
||||
}
|
||||
}
|
||||
PatKind::TupleStruct(ref path, ref elts) => {
|
||||
self.print_path(path, true, 0);
|
||||
PatKind::TupleStruct(ref qself, ref path, ref elts) => {
|
||||
if let Some(qself) = qself {
|
||||
self.print_qpath(path, qself, true);
|
||||
} else {
|
||||
self.print_path(path, true, 0);
|
||||
}
|
||||
self.popen();
|
||||
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
|
||||
self.pclose();
|
||||
|
|
@ -2355,8 +2364,12 @@ impl<'a> State<'a> {
|
|||
PatKind::Path(Some(ref qself), ref path) => {
|
||||
self.print_qpath(path, qself, false);
|
||||
}
|
||||
PatKind::Struct(ref path, ref fields, etc) => {
|
||||
self.print_path(path, true, 0);
|
||||
PatKind::Struct(ref qself, ref path, ref fields, etc) => {
|
||||
if let Some(qself) = qself {
|
||||
self.print_qpath(path, qself, true);
|
||||
} else {
|
||||
self.print_path(path, true, 0);
|
||||
}
|
||||
self.nbsp();
|
||||
self.word_space("{");
|
||||
self.commasep_cmnt(
|
||||
|
|
|
|||
|
|
@ -254,6 +254,10 @@ pub fn expand_test_or_bench(
|
|||
"allow_fail",
|
||||
cx.expr_bool(sp, should_fail(&cx.sess, &item)),
|
||||
),
|
||||
// compile_fail: true | false
|
||||
field("compile_fail", cx.expr_bool(sp, false)),
|
||||
// no_run: true | false
|
||||
field("no_run", cx.expr_bool(sp, false)),
|
||||
// should_panic: ...
|
||||
field(
|
||||
"should_panic",
|
||||
|
|
|
|||
|
|
@ -254,6 +254,15 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn inject_dll_import_lib(
|
||||
&mut self,
|
||||
_lib_name: &str,
|
||||
_dll_imports: &[rustc_middle::middle::cstore::DllImport],
|
||||
_tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
|
||||
) {
|
||||
bug!("injecting dll imports is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ArArchiveBuilder<'a> {
|
||||
|
|
|
|||
|
|
@ -177,21 +177,6 @@ pub(crate) fn run_aot(
|
|||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)> {
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
|
||||
let windows_subsystem = subsystem.map(|subsystem| {
|
||||
if subsystem != sym::windows && subsystem != sym::console {
|
||||
tcx.sess.fatal(&format!(
|
||||
"invalid windows subsystem `{}`, only \
|
||||
`windows` and `console` are allowed",
|
||||
subsystem
|
||||
));
|
||||
}
|
||||
subsystem.to_string()
|
||||
});
|
||||
|
||||
let mut work_products = FxHashMap::default();
|
||||
|
||||
let cgus = if tcx.sess.opts.output_types.should_codegen() {
|
||||
|
|
@ -307,12 +292,10 @@ pub(crate) fn run_aot(
|
|||
|
||||
Box::new((
|
||||
CodegenResults {
|
||||
crate_name: tcx.crate_name(LOCAL_CRATE),
|
||||
modules,
|
||||
allocator_module,
|
||||
metadata_module,
|
||||
metadata,
|
||||
windows_subsystem,
|
||||
linker_info: LinkerInfo::new(tcx, crate::target_triple(tcx.sess).to_string()),
|
||||
crate_info: CrateInfo::new(tcx),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ extern crate rustc_fs_util;
|
|||
extern crate rustc_hir;
|
||||
extern crate rustc_incremental;
|
||||
extern crate rustc_index;
|
||||
extern crate rustc_metadata;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
extern crate rustc_target;
|
||||
|
|
@ -28,8 +29,7 @@ use rustc_codegen_ssa::traits::CodegenBackend;
|
|||
use rustc_codegen_ssa::CodegenResults;
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::middle::cstore::EncodedMetadata;
|
||||
use rustc_session::config::OutputFilenames;
|
||||
use rustc_session::Session;
|
||||
|
||||
|
|
@ -164,17 +164,14 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
}
|
||||
}
|
||||
|
||||
fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
|
||||
Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
|
||||
}
|
||||
|
||||
fn provide(&self, _providers: &mut Providers) {}
|
||||
fn provide_extern(&self, _providers: &mut Providers) {}
|
||||
|
||||
fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn print_version(&self) {
|
||||
println!("Cranelift version: {}", cranelift_codegen::VERSION);
|
||||
}
|
||||
|
||||
fn codegen_crate(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
|
|
@ -222,7 +219,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
sess,
|
||||
&codegen_results,
|
||||
outputs,
|
||||
&codegen_results.crate_name.as_str(),
|
||||
&codegen_results.crate_info.local_crate_name.as_str(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O)
|
|||
use std::io::Write;
|
||||
|
||||
let metadata = tcx.encode_metadata();
|
||||
let mut compressed = tcx.metadata_encoding_version();
|
||||
let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
|
||||
FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
|
||||
|
||||
object.add_rustc_section(
|
||||
|
|
|
|||
|
|
@ -2,9 +2,8 @@
|
|||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rustc_middle::bug;
|
||||
use rustc_codegen_ssa::back::link::linker_and_flavor;
|
||||
use rustc_session::Session;
|
||||
use rustc_target::spec::LinkerFlavor;
|
||||
|
||||
/// 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 {
|
||||
|
|
@ -30,89 +29,3 @@ pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf {
|
|||
|
||||
linker
|
||||
}
|
||||
|
||||
// Adapted from https://github.com/rust-lang/rust/blob/5db778affee7c6600c8e7a177c48282dab3f6292/src/librustc_codegen_ssa/back/link.rs#L848-L931
|
||||
fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
||||
fn infer_from(
|
||||
sess: &Session,
|
||||
linker: Option<PathBuf>,
|
||||
flavor: Option<LinkerFlavor>,
|
||||
) -> Option<(PathBuf, LinkerFlavor)> {
|
||||
match (linker, flavor) {
|
||||
(Some(linker), Some(flavor)) => Some((linker, flavor)),
|
||||
// only the linker flavor is known; use the default linker for the selected flavor
|
||||
(None, Some(flavor)) => Some((
|
||||
PathBuf::from(match flavor {
|
||||
LinkerFlavor::Em => {
|
||||
if cfg!(windows) {
|
||||
"emcc.bat"
|
||||
} else {
|
||||
"emcc"
|
||||
}
|
||||
}
|
||||
LinkerFlavor::Gcc => {
|
||||
if cfg!(any(target_os = "solaris", target_os = "illumos")) {
|
||||
// On historical Solaris systems, "cc" may have
|
||||
// been Sun Studio, which is not flag-compatible
|
||||
// with "gcc". This history casts a long shadow,
|
||||
// and many modern illumos distributions today
|
||||
// ship GCC as "gcc" without also making it
|
||||
// available as "cc".
|
||||
"gcc"
|
||||
} else {
|
||||
"cc"
|
||||
}
|
||||
}
|
||||
LinkerFlavor::Ld => "ld",
|
||||
LinkerFlavor::Msvc => "link.exe",
|
||||
LinkerFlavor::Lld(_) => "lld",
|
||||
LinkerFlavor::PtxLinker => "rust-ptx-linker",
|
||||
}),
|
||||
flavor,
|
||||
)),
|
||||
(Some(linker), None) => {
|
||||
let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
|
||||
sess.fatal("couldn't extract file stem from specified linker")
|
||||
});
|
||||
|
||||
let flavor = if stem == "emcc" {
|
||||
LinkerFlavor::Em
|
||||
} else if stem == "gcc"
|
||||
|| stem.ends_with("-gcc")
|
||||
|| stem == "clang"
|
||||
|| stem.ends_with("-clang")
|
||||
{
|
||||
LinkerFlavor::Gcc
|
||||
} else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
|
||||
LinkerFlavor::Ld
|
||||
} else if stem == "link" || stem == "lld-link" {
|
||||
LinkerFlavor::Msvc
|
||||
} else if stem == "lld" || stem == "rust-lld" {
|
||||
LinkerFlavor::Lld(sess.target.lld_flavor)
|
||||
} else {
|
||||
// fall back to the value in the target spec
|
||||
sess.target.linker_flavor
|
||||
};
|
||||
|
||||
Some((linker, flavor))
|
||||
}
|
||||
(None, None) => None,
|
||||
}
|
||||
}
|
||||
|
||||
// linker and linker flavor specified via command line have precedence over what the target
|
||||
// specification specifies
|
||||
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if let Some(ret) = infer_from(
|
||||
sess,
|
||||
sess.target.linker.clone().map(PathBuf::from),
|
||||
Some(sess.target.linker_flavor),
|
||||
) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bug!("Not enough information provided to determine how to invoke the linker");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ rustc_hir = { path = "../rustc_hir" }
|
|||
rustc_incremental = { path = "../rustc_incremental" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_llvm = { path = "../rustc_llvm" }
|
||||
rustc_metadata = { path = "../rustc_metadata" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
|
||||
InlineAsmArch::SpirV => {}
|
||||
InlineAsmArch::Wasm32 => {}
|
||||
InlineAsmArch::Bpf => {}
|
||||
}
|
||||
}
|
||||
if !options.contains(InlineAsmOptions::NOMEM) {
|
||||
|
|
@ -593,6 +594,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
|
|||
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
}
|
||||
|
|
@ -661,6 +664,7 @@ fn modifier_to_llvm(
|
|||
},
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
|
||||
InlineAsmRegClass::Bpf(_) => None,
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
}
|
||||
|
|
@ -708,6 +712,8 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
|
|||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(),
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(),
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ use std::ptr;
|
|||
use std::str;
|
||||
|
||||
use crate::llvm::archive_ro::{ArchiveRO, Child};
|
||||
use crate::llvm::{self, ArchiveKind};
|
||||
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
|
||||
use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
|
||||
use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME};
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_middle::middle::cstore::DllImport;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
|
|
@ -61,6 +63,17 @@ fn archive_config<'a>(sess: &'a Session, output: &Path, input: Option<&Path>) ->
|
|||
}
|
||||
}
|
||||
|
||||
/// Map machine type strings to values of LLVM's MachineTypes enum.
|
||||
fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
|
||||
match cpu {
|
||||
"x86_64" => LLVMMachineType::AMD64,
|
||||
"x86" => LLVMMachineType::I386,
|
||||
"aarch64" => LLVMMachineType::ARM64,
|
||||
"arm" => LLVMMachineType::ARM,
|
||||
_ => panic!("unsupported cpu type {}", cpu),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
|
||||
/// Creates a new static archive, ready for modifying the archive specified
|
||||
/// by `config`.
|
||||
|
|
@ -175,6 +188,74 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
|
|||
self.config.sess.fatal(&format!("failed to build archive: {}", e));
|
||||
}
|
||||
}
|
||||
|
||||
fn inject_dll_import_lib(
|
||||
&mut self,
|
||||
lib_name: &str,
|
||||
dll_imports: &[DllImport],
|
||||
tmpdir: &MaybeTempDir,
|
||||
) {
|
||||
let output_path = {
|
||||
let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf();
|
||||
output_path.push(format!("{}_imports", lib_name));
|
||||
output_path.with_extension("lib")
|
||||
};
|
||||
|
||||
// we've checked for \0 characters in the library name already
|
||||
let dll_name_z = CString::new(lib_name).unwrap();
|
||||
// All import names are Rust identifiers and therefore cannot contain \0 characters.
|
||||
// FIXME: when support for #[link_name] implemented, ensure that import.name values don't
|
||||
// have any \0 characters
|
||||
let import_name_vector: Vec<CString> = dll_imports
|
||||
.iter()
|
||||
.map(if self.config.sess.target.arch == "x86" {
|
||||
|import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap()
|
||||
} else {
|
||||
|import: &DllImport| CString::new(import.name.to_string()).unwrap()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
|
||||
|
||||
tracing::trace!("invoking LLVMRustWriteImportLibrary");
|
||||
tracing::trace!(" dll_name {:#?}", dll_name_z);
|
||||
tracing::trace!(" output_path {}", output_path.display());
|
||||
tracing::trace!(
|
||||
" import names: {}",
|
||||
dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "),
|
||||
);
|
||||
|
||||
let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_vector
|
||||
.iter()
|
||||
.map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr()))
|
||||
.collect();
|
||||
let result = unsafe {
|
||||
crate::llvm::LLVMRustWriteImportLibrary(
|
||||
dll_name_z.as_ptr(),
|
||||
output_path_z.as_ptr(),
|
||||
ffi_exports.as_ptr(),
|
||||
ffi_exports.len(),
|
||||
llvm_machine_type(&self.config.sess.target.arch) as u16,
|
||||
!self.config.sess.target.is_like_msvc,
|
||||
)
|
||||
};
|
||||
|
||||
if result == crate::llvm::LLVMRustResult::Failure {
|
||||
self.config.sess.fatal(&format!(
|
||||
"Error creating import library for {}: {}",
|
||||
lib_name,
|
||||
llvm::last_error().unwrap_or("unknown LLVM error".to_string())
|
||||
));
|
||||
}
|
||||
|
||||
self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
|
||||
self.config.sess.fatal(&format!(
|
||||
"failed to add native library {}: {}",
|
||||
output_path.display(),
|
||||
e
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LlvmArchiveBuilder<'a> {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ pub fn write_compressed_metadata<'tcx>(
|
|||
let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };
|
||||
|
||||
let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
|
||||
let mut compressed = tcx.metadata_encoding_version();
|
||||
let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
|
||||
FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
|
||||
|
||||
let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ impl abi::HasDataLayout for Builder<'_, '_, '_> {
|
|||
}
|
||||
|
||||
impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
|
||||
#[inline]
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.cx.tcx
|
||||
}
|
||||
|
|
@ -81,6 +82,7 @@ impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
}
|
||||
|
||||
impl HasTargetSpec for Builder<'_, '_, 'tcx> {
|
||||
#[inline]
|
||||
fn target_spec(&self) -> &Target {
|
||||
&self.cx.target_spec()
|
||||
}
|
||||
|
|
@ -98,6 +100,7 @@ impl abi::LayoutOf for Builder<'_, '_, 'tcx> {
|
|||
impl Deref for Builder<'_, 'll, 'tcx> {
|
||||
type Target = CodegenCx<'ll, 'tcx>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.cx
|
||||
}
|
||||
|
|
|
|||
|
|
@ -765,18 +765,21 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
|
|||
}
|
||||
|
||||
impl HasDataLayout for CodegenCx<'ll, 'tcx> {
|
||||
#[inline]
|
||||
fn data_layout(&self) -> &TargetDataLayout {
|
||||
&self.tcx.data_layout
|
||||
}
|
||||
}
|
||||
|
||||
impl HasTargetSpec for CodegenCx<'ll, 'tcx> {
|
||||
#[inline]
|
||||
fn target_spec(&self) -> &Target {
|
||||
&self.tcx.sess.target
|
||||
}
|
||||
}
|
||||
|
||||
impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
#[inline]
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1457,7 +1457,6 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
enum_type: Ty<'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
tag_type_metadata: Option<&'ll DIType>,
|
||||
containing_scope: &'ll DIScope,
|
||||
common_members: Vec<Option<&'ll DIType>>,
|
||||
span: Span,
|
||||
}
|
||||
|
|
@ -1486,13 +1485,9 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
_ => bug!(),
|
||||
};
|
||||
|
||||
// This will always find the metadata in the type map.
|
||||
let fallback = use_enum_fallback(cx);
|
||||
let self_metadata = if fallback {
|
||||
self.containing_scope
|
||||
} else {
|
||||
type_metadata(cx, self.enum_type, self.span)
|
||||
};
|
||||
// This will always find the metadata in the type map.
|
||||
let self_metadata = type_metadata(cx, self.enum_type, self.span);
|
||||
|
||||
match self.layout.variants {
|
||||
Variants::Single { index } => {
|
||||
|
|
@ -1507,7 +1502,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
cx,
|
||||
self.layout,
|
||||
variant_info,
|
||||
NoTag,
|
||||
None,
|
||||
self_metadata,
|
||||
self.span,
|
||||
);
|
||||
|
|
@ -1539,13 +1534,26 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
..
|
||||
} => {
|
||||
let tag_info = if fallback {
|
||||
RegularTag {
|
||||
// For MSVC, we generate a union of structs for each variant with an explicit
|
||||
// discriminant field roughly equivalent to the following C:
|
||||
// ```c
|
||||
// union enum$<{name}> {
|
||||
// struct {variant 0 name} {
|
||||
// tag$ variant$;
|
||||
// <variant 0 fields>
|
||||
// } variant0;
|
||||
// <other variant structs>
|
||||
// }
|
||||
// ```
|
||||
// The natvis in `intrinsic.nativs` then matches on `this.variant0.variant$` to
|
||||
// determine which variant is active and then displays it.
|
||||
Some(DirectTag {
|
||||
tag_field: Field::from(tag_field),
|
||||
tag_type_metadata: self.tag_type_metadata.unwrap(),
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// This doesn't matter in this case.
|
||||
NoTag
|
||||
None
|
||||
};
|
||||
variants
|
||||
.iter_enumerated()
|
||||
|
|
@ -1574,7 +1582,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
|
||||
MemberDescription {
|
||||
name: if fallback {
|
||||
String::new()
|
||||
format!("variant{}", i.as_u32())
|
||||
} else {
|
||||
variant_info.variant_name()
|
||||
},
|
||||
|
|
@ -1599,77 +1607,135 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
ref variants,
|
||||
tag_field,
|
||||
} => {
|
||||
let calculate_niche_value = |i: VariantIdx| {
|
||||
if i == dataful_variant {
|
||||
None
|
||||
} else {
|
||||
let value = (i.as_u32() as u128)
|
||||
.wrapping_sub(niche_variants.start().as_u32() as u128)
|
||||
.wrapping_add(niche_start);
|
||||
let value = tag.value.size(cx).truncate(value);
|
||||
// NOTE(eddyb) do *NOT* remove this assert, until
|
||||
// we pass the full 128-bit value to LLVM, otherwise
|
||||
// truncation will be silent and remain undetected.
|
||||
assert_eq!(value as u64 as u128, value);
|
||||
Some(value as u64)
|
||||
}
|
||||
};
|
||||
|
||||
// For MSVC, we will generate a union of two fields, one for the dataful variant
|
||||
// and one that just points to the discriminant. We also create an enum that
|
||||
// contains tag values for the non-dataful variants and make the discriminant field
|
||||
// that type. We then use natvis to render the enum type correctly in Windbg/VS.
|
||||
// This will generate debuginfo roughly equivalent to the following C:
|
||||
// ```c
|
||||
// union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> {
|
||||
// struct <dataful variant name> {
|
||||
// <fields in dataful variant>
|
||||
// } dataful_variant;
|
||||
// enum Discriminant$ {
|
||||
// <non-dataful variants>
|
||||
// } discriminant;
|
||||
// }
|
||||
// ```
|
||||
// The natvis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>`
|
||||
// and evaluates `this.discriminant`. If the value is between the min niche and max
|
||||
// niche, then the enum is in the dataful variant and `this.dataful_variant` is
|
||||
// rendered. Otherwise, the enum is in one of the non-dataful variants. In that
|
||||
// case, we just need to render the name of the `this.discriminant` enum.
|
||||
if fallback {
|
||||
let variant = self.layout.for_variant(cx, dataful_variant);
|
||||
// Create a description of the non-null variant.
|
||||
let (variant_type_metadata, member_description_factory) = describe_enum_variant(
|
||||
let dataful_variant_layout = self.layout.for_variant(cx, dataful_variant);
|
||||
|
||||
let mut discr_enum_ty = tag.value.to_ty(cx.tcx);
|
||||
// If the niche is the NULL value of a reference, then `discr_enum_ty` will be a RawPtr.
|
||||
// CodeView doesn't know what to do with enums whose base type is a pointer so we fix this up
|
||||
// to just be `usize`.
|
||||
if let ty::RawPtr(_) = discr_enum_ty.kind() {
|
||||
discr_enum_ty = cx.tcx.types.usize;
|
||||
}
|
||||
|
||||
let tags: Vec<_> = variants
|
||||
.iter_enumerated()
|
||||
.filter_map(|(variant_idx, _)| {
|
||||
calculate_niche_value(variant_idx).map(|tag| {
|
||||
let variant = variant_info_for(variant_idx);
|
||||
let name = variant.variant_name();
|
||||
|
||||
Some(unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateEnumerator(
|
||||
DIB(cx),
|
||||
name.as_ptr().cast(),
|
||||
name.len(),
|
||||
tag as i64,
|
||||
!discr_enum_ty.is_signed(),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
let discr_enum = unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateEnumerationType(
|
||||
DIB(cx),
|
||||
self_metadata,
|
||||
"Discriminant$".as_ptr().cast(),
|
||||
"Discriminant$".len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
tag.value.size(cx).bits(),
|
||||
tag.value.align(cx).abi.bits() as u32,
|
||||
create_DIArray(DIB(cx), &tags),
|
||||
type_metadata(cx, discr_enum_ty, self.span),
|
||||
true,
|
||||
)
|
||||
};
|
||||
|
||||
let variant_info = variant_info_for(dataful_variant);
|
||||
let (variant_type_metadata, member_desc_factory) = describe_enum_variant(
|
||||
cx,
|
||||
variant,
|
||||
variant_info_for(dataful_variant),
|
||||
OptimizedTag,
|
||||
self.containing_scope,
|
||||
dataful_variant_layout,
|
||||
variant_info,
|
||||
Some(NicheTag),
|
||||
self_metadata,
|
||||
self.span,
|
||||
);
|
||||
|
||||
let variant_member_descriptions =
|
||||
member_description_factory.create_member_descriptions(cx);
|
||||
let member_descriptions = member_desc_factory.create_member_descriptions(cx);
|
||||
|
||||
set_members_of_composite_type(
|
||||
cx,
|
||||
self.enum_type,
|
||||
variant_type_metadata,
|
||||
variant_member_descriptions,
|
||||
member_descriptions,
|
||||
Some(&self.common_members),
|
||||
);
|
||||
|
||||
// Encode the information about the null variant in the union
|
||||
// member's name.
|
||||
let mut name = String::from("RUST$ENCODED$ENUM$");
|
||||
// Right now it's not even going to work for `niche_start > 0`,
|
||||
// and for multiple niche variants it only supports the first.
|
||||
fn compute_field_path<'a, 'tcx>(
|
||||
cx: &CodegenCx<'a, 'tcx>,
|
||||
name: &mut String,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
offset: Size,
|
||||
size: Size,
|
||||
) {
|
||||
for i in 0..layout.fields.count() {
|
||||
let field_offset = layout.fields.offset(i);
|
||||
if field_offset > offset {
|
||||
continue;
|
||||
}
|
||||
let inner_offset = offset - field_offset;
|
||||
let field = layout.field(cx, i);
|
||||
if inner_offset + size <= field.size {
|
||||
write!(name, "{}$", i).unwrap();
|
||||
compute_field_path(cx, name, field, inner_offset, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
compute_field_path(
|
||||
cx,
|
||||
&mut name,
|
||||
self.layout,
|
||||
self.layout.fields.offset(tag_field),
|
||||
self.layout.field(cx, tag_field).size,
|
||||
);
|
||||
let variant_info = variant_info_for(*niche_variants.start());
|
||||
variant_info.map_struct_name(|variant_name| {
|
||||
name.push_str(variant_name);
|
||||
});
|
||||
let (size, align) =
|
||||
cx.size_and_align_of(dataful_variant_layout.field(cx, tag_field).ty);
|
||||
|
||||
// Create the (singleton) list of descriptions of union members.
|
||||
vec![MemberDescription {
|
||||
name,
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: Size::ZERO,
|
||||
size: variant.size,
|
||||
align: variant.align.abi,
|
||||
flags: DIFlags::FlagZero,
|
||||
discriminant: None,
|
||||
source_info: variant_info.source_info(cx),
|
||||
}]
|
||||
vec![
|
||||
MemberDescription {
|
||||
// Name the dataful variant so that we can identify it for natvis
|
||||
name: "dataful_variant".to_string(),
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: Size::ZERO,
|
||||
size: self.layout.size,
|
||||
align: self.layout.align.abi,
|
||||
flags: DIFlags::FlagZero,
|
||||
discriminant: None,
|
||||
source_info: variant_info.source_info(cx),
|
||||
},
|
||||
MemberDescription {
|
||||
name: "discriminant".into(),
|
||||
type_metadata: discr_enum,
|
||||
offset: dataful_variant_layout.fields.offset(tag_field),
|
||||
size,
|
||||
align,
|
||||
flags: DIFlags::FlagZero,
|
||||
discriminant: None,
|
||||
source_info: None,
|
||||
},
|
||||
]
|
||||
} else {
|
||||
variants
|
||||
.iter_enumerated()
|
||||
|
|
@ -1681,7 +1747,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
cx,
|
||||
variant,
|
||||
variant_info,
|
||||
OptimizedTag,
|
||||
Some(NicheTag),
|
||||
self_metadata,
|
||||
self.span,
|
||||
);
|
||||
|
|
@ -1697,19 +1763,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
|
|||
Some(&self.common_members),
|
||||
);
|
||||
|
||||
let niche_value = if i == dataful_variant {
|
||||
None
|
||||
} else {
|
||||
let value = (i.as_u32() as u128)
|
||||
.wrapping_sub(niche_variants.start().as_u32() as u128)
|
||||
.wrapping_add(niche_start);
|
||||
let value = tag.value.size(cx).truncate(value);
|
||||
// NOTE(eddyb) do *NOT* remove this assert, until
|
||||
// we pass the full 128-bit value to LLVM, otherwise
|
||||
// truncation will be silent and remain undetected.
|
||||
assert_eq!(value as u64 as u128, value);
|
||||
Some(value as u64)
|
||||
};
|
||||
let niche_value = calculate_niche_value(i);
|
||||
|
||||
MemberDescription {
|
||||
name: variant_info.variant_name(),
|
||||
|
|
@ -1771,14 +1825,10 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: terminology here should be aligned with `abi::TagEncoding`.
|
||||
// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`.
|
||||
// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead.
|
||||
#[derive(Copy, Clone)]
|
||||
enum EnumTagInfo<'ll> {
|
||||
RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
|
||||
OptimizedTag,
|
||||
NoTag,
|
||||
DirectTag { tag_field: Field, tag_type_metadata: &'ll DIType },
|
||||
NicheTag,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -1859,7 +1909,7 @@ fn describe_enum_variant(
|
|||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
layout: layout::TyAndLayout<'tcx>,
|
||||
variant: VariantInfo<'_, 'tcx>,
|
||||
discriminant_info: EnumTagInfo<'ll>,
|
||||
discriminant_info: Option<EnumTagInfo<'ll>>,
|
||||
containing_scope: &'ll DIScope,
|
||||
span: Span,
|
||||
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
|
||||
|
|
@ -1882,12 +1932,11 @@ fn describe_enum_variant(
|
|||
let (offsets, args) = if use_enum_fallback(cx) {
|
||||
// If this is not a univariant enum, there is also the discriminant field.
|
||||
let (discr_offset, discr_arg) = match discriminant_info {
|
||||
RegularTag { tag_field, .. } => {
|
||||
Some(DirectTag { tag_field, .. }) => {
|
||||
// We have the layout of an enum variant, we need the layout of the outer enum
|
||||
let enum_layout = cx.layout_of(layout.ty);
|
||||
let offset = enum_layout.fields.offset(tag_field.as_usize());
|
||||
let args =
|
||||
("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
|
||||
let args = ("variant$".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
|
||||
(Some(offset), Some(args))
|
||||
}
|
||||
_ => (None, None),
|
||||
|
|
@ -1918,7 +1967,7 @@ fn describe_enum_variant(
|
|||
offsets,
|
||||
args,
|
||||
tag_type_metadata: match discriminant_info {
|
||||
RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
|
||||
Some(DirectTag { tag_type_metadata, .. }) => Some(tag_type_metadata),
|
||||
_ => None,
|
||||
},
|
||||
span,
|
||||
|
|
@ -2048,9 +2097,9 @@ fn prepare_enum_metadata(
|
|||
|
||||
if use_enum_fallback(cx) {
|
||||
let discriminant_type_metadata = match layout.variants {
|
||||
Variants::Single { .. }
|
||||
| Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
|
||||
Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
|
||||
Variants::Single { .. } => None,
|
||||
Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, ref tag, .. }
|
||||
| Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
|
||||
Some(discriminant_type_metadata(tag.value))
|
||||
}
|
||||
};
|
||||
|
|
@ -2062,7 +2111,7 @@ fn prepare_enum_metadata(
|
|||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateUnionType(
|
||||
DIB(cx),
|
||||
containing_scope,
|
||||
None,
|
||||
enum_name.as_ptr().cast(),
|
||||
enum_name.len(),
|
||||
file_metadata,
|
||||
|
|
@ -2088,7 +2137,6 @@ fn prepare_enum_metadata(
|
|||
enum_type,
|
||||
layout,
|
||||
tag_type_metadata: discriminant_type_metadata,
|
||||
containing_scope,
|
||||
common_members: vec![],
|
||||
span,
|
||||
}),
|
||||
|
|
@ -2241,7 +2289,6 @@ fn prepare_enum_metadata(
|
|||
enum_type,
|
||||
layout,
|
||||
tag_type_metadata: None,
|
||||
containing_scope,
|
||||
common_members: outer_fields,
|
||||
span,
|
||||
}),
|
||||
|
|
@ -2437,7 +2484,7 @@ fn create_union_stub(
|
|||
|
||||
llvm::LLVMRustDIBuilderCreateUnionType(
|
||||
DIB(cx),
|
||||
containing_scope,
|
||||
Some(containing_scope),
|
||||
union_type_name.as_ptr().cast(),
|
||||
union_type_name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ use rustc_codegen_ssa::{CodegenResults, CompiledModule};
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{ErrorReported, FatalError, Handler};
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::middle::cstore::EncodedMetadata;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
|
@ -248,13 +248,6 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
target_features(sess)
|
||||
}
|
||||
|
||||
fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
|
||||
Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
|
||||
}
|
||||
|
||||
fn provide(&self, _providers: &mut ty::query::Providers) {}
|
||||
fn provide_extern(&self, _providers: &mut ty::query::Providers) {}
|
||||
|
||||
fn codegen_crate<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
@ -304,7 +297,7 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
sess,
|
||||
&codegen_results,
|
||||
outputs,
|
||||
&codegen_results.crate_name.as_str(),
|
||||
&codegen_results.crate_info.local_crate_name.as_str(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -29,6 +29,31 @@ pub enum LLVMRustResult {
|
|||
Success,
|
||||
Failure,
|
||||
}
|
||||
|
||||
// Rust version of the C struct with the same name in rustc_llvm/llvm-wrapper/RustWrapper.cpp.
|
||||
#[repr(C)]
|
||||
pub struct LLVMRustCOFFShortExport {
|
||||
pub name: *const c_char,
|
||||
}
|
||||
|
||||
impl LLVMRustCOFFShortExport {
|
||||
pub fn from_name(name: *const c_char) -> LLVMRustCOFFShortExport {
|
||||
LLVMRustCOFFShortExport { name }
|
||||
}
|
||||
}
|
||||
|
||||
/// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h.
|
||||
///
|
||||
/// We include only architectures supported on Windows.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub enum LLVMMachineType {
|
||||
AMD64 = 0x8664,
|
||||
I386 = 0x14c,
|
||||
ARM64 = 0xaa64,
|
||||
ARM = 0x01c0,
|
||||
}
|
||||
|
||||
// Consts for the LLVM CallConv type, pre-cast to usize.
|
||||
|
||||
/// LLVM CallingConv::ID. Should we wrap this?
|
||||
|
|
@ -582,11 +607,6 @@ pub struct PassManager<'a>(InvariantOpaque<'a>);
|
|||
extern "C" {
|
||||
pub type PassManagerBuilder;
|
||||
}
|
||||
extern "C" {
|
||||
pub type ObjectFile;
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct SectionIterator<'a>(InvariantOpaque<'a>);
|
||||
extern "C" {
|
||||
pub type Pass;
|
||||
}
|
||||
|
|
@ -1703,35 +1723,6 @@ extern "C" {
|
|||
|
||||
pub fn LLVMDisposeMessage(message: *mut c_char);
|
||||
|
||||
// Stuff that's in llvm-wrapper/ because it's not upstream yet.
|
||||
|
||||
/// Opens an object file.
|
||||
pub fn LLVMCreateObjectFile(
|
||||
MemBuf: &'static mut MemoryBuffer,
|
||||
) -> Option<&'static mut ObjectFile>;
|
||||
/// Closes an object file.
|
||||
pub fn LLVMDisposeObjectFile(ObjFile: &'static mut ObjectFile);
|
||||
|
||||
/// Enumerates the sections in an object file.
|
||||
pub fn LLVMGetSections(ObjFile: &'a ObjectFile) -> &'a mut SectionIterator<'a>;
|
||||
/// Destroys a section iterator.
|
||||
pub fn LLVMDisposeSectionIterator(SI: &'a mut SectionIterator<'a>);
|
||||
/// Returns `true` if the section iterator is at the end of the section
|
||||
/// list:
|
||||
pub fn LLVMIsSectionIteratorAtEnd(ObjFile: &'a ObjectFile, SI: &SectionIterator<'a>) -> Bool;
|
||||
/// Moves the section iterator to point to the next section.
|
||||
pub fn LLVMMoveToNextSection(SI: &SectionIterator<'_>);
|
||||
/// Returns the current section size.
|
||||
pub fn LLVMGetSectionSize(SI: &SectionIterator<'_>) -> c_ulonglong;
|
||||
/// Returns the current section contents as a string buffer.
|
||||
pub fn LLVMGetSectionContents(SI: &SectionIterator<'_>) -> *const c_char;
|
||||
|
||||
/// Reads the given file and returns it as a memory buffer. Use
|
||||
/// LLVMDisposeMemoryBuffer() to get rid of it.
|
||||
pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(
|
||||
Path: *const c_char,
|
||||
) -> Option<&'static mut MemoryBuffer>;
|
||||
|
||||
pub fn LLVMStartMultithreaded() -> Bool;
|
||||
|
||||
/// Returns a string describing the last error caused by an LLVMRust* call.
|
||||
|
|
@ -2038,7 +2029,7 @@ extern "C" {
|
|||
|
||||
pub fn LLVMRustDIBuilderCreateUnionType(
|
||||
Builder: &DIBuilder<'a>,
|
||||
Scope: &'a DIScope,
|
||||
Scope: Option<&'a DIScope>,
|
||||
Name: *const c_char,
|
||||
NameLen: size_t,
|
||||
File: &'a DIFile,
|
||||
|
|
@ -2236,12 +2227,6 @@ extern "C" {
|
|||
pub fn LLVMRustArchiveIteratorFree(AIR: &'a mut ArchiveIterator<'a>);
|
||||
pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustGetSectionName(
|
||||
SI: &SectionIterator<'_>,
|
||||
data: &mut Option<std::ptr::NonNull<c_char>>,
|
||||
) -> size_t;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
|
||||
|
||||
|
|
@ -2305,6 +2290,15 @@ extern "C" {
|
|||
) -> &'a mut RustArchiveMember<'a>;
|
||||
pub fn LLVMRustArchiveMemberFree(Member: &'a mut RustArchiveMember<'a>);
|
||||
|
||||
pub fn LLVMRustWriteImportLibrary(
|
||||
ImportName: *const c_char,
|
||||
Path: *const c_char,
|
||||
Exports: *const LLVMRustCOFFShortExport,
|
||||
NumExports: usize,
|
||||
Machine: u16,
|
||||
MinGW: bool,
|
||||
) -> LLVMRustResult;
|
||||
|
||||
pub fn LLVMRustSetDataLayoutFromTargetMachine(M: &'a Module, TM: &'a TargetMachine);
|
||||
|
||||
pub fn LLVMRustBuildOperandBundleDef(
|
||||
|
|
|
|||
|
|
@ -150,50 +150,6 @@ impl Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
// Memory-managed interface to object files.
|
||||
|
||||
pub struct ObjectFile {
|
||||
pub llof: &'static mut ffi::ObjectFile,
|
||||
}
|
||||
|
||||
unsafe impl Send for ObjectFile {}
|
||||
|
||||
impl ObjectFile {
|
||||
// This will take ownership of llmb
|
||||
pub fn new(llmb: &'static mut MemoryBuffer) -> Option<ObjectFile> {
|
||||
unsafe {
|
||||
let llof = LLVMCreateObjectFile(llmb)?;
|
||||
Some(ObjectFile { llof })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ObjectFile {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
LLVMDisposeObjectFile(&mut *(self.llof as *mut _));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Memory-managed interface to section iterators.
|
||||
|
||||
pub struct SectionIter<'a> {
|
||||
pub llsi: &'a mut SectionIterator<'a>,
|
||||
}
|
||||
|
||||
impl Drop for SectionIter<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
LLVMDisposeSectionIterator(&mut *(self.llsi as *mut _));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_section_iter(llof: &ffi::ObjectFile) -> SectionIter<'_> {
|
||||
unsafe { SectionIter { llsi: LLVMGetSections(llof) } }
|
||||
}
|
||||
|
||||
pub fn set_section(llglobal: &Value, section_name: &str) {
|
||||
let section_name_cstr = CString::new(section_name).expect("unexpected CString error");
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::llvm;
|
||||
use crate::{llvm, llvm_util};
|
||||
use libc::c_int;
|
||||
use rustc_codegen_ssa::target_features::supported_target_features;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
|
@ -84,6 +84,17 @@ unsafe fn configure_llvm(sess: &Session) {
|
|||
if !sess.opts.debugging_opts.no_generate_arange_section {
|
||||
add("-generate-arange-section", false);
|
||||
}
|
||||
|
||||
// FIXME(nagisa): disable the machine outliner by default in LLVM versions 11, where it was
|
||||
// introduced and up.
|
||||
//
|
||||
// This should remain in place until https://reviews.llvm.org/D103167 is fixed. If LLVM
|
||||
// has been upgraded since, consider adjusting the version check below to contain an upper
|
||||
// bound.
|
||||
if llvm_util::get_version() >= (11, 0, 0) {
|
||||
add("-enable-machine-outliner=never", false);
|
||||
}
|
||||
|
||||
match sess.opts.debugging_opts.merge_functions.unwrap_or(sess.target.merge_functions) {
|
||||
MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
|
||||
MergeFunctions::Aliases => {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,6 @@ rustc_target = { path = "../rustc_target" }
|
|||
rustc_session = { path = "../rustc_session" }
|
||||
|
||||
[dependencies.object]
|
||||
version = "0.22.0"
|
||||
version = "0.25.2"
|
||||
default-features = false
|
||||
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive"]
|
||||
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_middle::middle::cstore::DllImport;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
|
|
@ -57,4 +59,11 @@ pub trait ArchiveBuilder<'a> {
|
|||
fn update_symbols(&mut self);
|
||||
|
||||
fn build(self);
|
||||
|
||||
fn inject_dll_import_lib(
|
||||
&mut self,
|
||||
lib_name: &str,
|
||||
dll_imports: &[DllImport],
|
||||
tmpdir: &MaybeTempDir,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_errors::Handler;
|
||||
use rustc_fs_util::fix_windows_verbatim_for_gcc;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_middle::middle::cstore::{EncodedMetadata, LibSource};
|
||||
use rustc_middle::middle::cstore::{DllImport, LibSource};
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
|
||||
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
|
||||
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
|
||||
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
|
||||
use rustc_session::search_paths::PathKind;
|
||||
|
|
@ -14,6 +14,7 @@ use rustc_session::utils::NativeLibKind;
|
|||
/// need out of the shared crate context before we get rid of it.
|
||||
use rustc_session::{filesearch, Session};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::abi::Endian;
|
||||
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
|
||||
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
|
||||
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
|
||||
|
|
@ -28,8 +29,12 @@ use crate::{
|
|||
};
|
||||
|
||||
use cc::windows_registry;
|
||||
use object::elf;
|
||||
use object::write::Object;
|
||||
use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
|
||||
use tempfile::Builder as TempFileBuilder;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::ffi::OsString;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{ExitStatus, Output, Stdio};
|
||||
|
|
@ -278,9 +283,9 @@ pub fn each_linked_rlib(
|
|||
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
|
||||
/// directory being searched for `extern crate` (observing an incomplete file).
|
||||
/// The returned path is the temporary file containing the complete metadata.
|
||||
pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeTempDir) -> PathBuf {
|
||||
pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf {
|
||||
let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
|
||||
let result = fs::write(&out_filename, &metadata.raw_data);
|
||||
let result = fs::write(&out_filename, metadata);
|
||||
|
||||
if let Err(e) = result {
|
||||
sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
|
||||
|
|
@ -339,6 +344,12 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
|
|||
}
|
||||
}
|
||||
|
||||
for (raw_dylib_name, raw_dylib_imports) in
|
||||
collate_raw_dylibs(&codegen_results.crate_info.used_libraries)
|
||||
{
|
||||
ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir);
|
||||
}
|
||||
|
||||
// After adding all files to the archive, we need to update the
|
||||
// symbol table of the archive.
|
||||
ab.update_symbols();
|
||||
|
|
@ -366,9 +377,11 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
|
|||
// code above.
|
||||
match flavor {
|
||||
RlibFlavor::Normal => {
|
||||
// Instead of putting the metadata in an object file section, rlibs
|
||||
// contain the metadata in a separate file.
|
||||
ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir));
|
||||
// metadata in rlib files is wrapped in a "dummy" object file for
|
||||
// the target platform so the rlib can be processed entirely by
|
||||
// normal linkers for the platform.
|
||||
let metadata = create_metadata_file(sess, &codegen_results.metadata.raw_data);
|
||||
ab.add_file(&emit_metadata(sess, &metadata, tmpdir));
|
||||
|
||||
// After adding all files to the archive, we need to update the
|
||||
// symbol table of the archive. This currently dies on macOS (see
|
||||
|
|
@ -385,8 +398,188 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
|
|||
}
|
||||
}
|
||||
}
|
||||
return ab;
|
||||
|
||||
ab
|
||||
// For rlibs we "pack" rustc metadata into a dummy object file. When rustc
|
||||
// creates a dylib crate type it will pass `--whole-archive` (or the
|
||||
// platform equivalent) to include all object files from an rlib into the
|
||||
// final dylib itself. This causes linkers to iterate and try to include all
|
||||
// files located in an archive, so if metadata is stored in an archive then
|
||||
// it needs to be of a form that the linker will be able to process.
|
||||
//
|
||||
// Note, though, that we don't actually want this metadata to show up in any
|
||||
// final output of the compiler. Instead this is purely for rustc's own
|
||||
// metadata tracking purposes.
|
||||
//
|
||||
// With the above in mind, each "flavor" of object format gets special
|
||||
// handling here depending on the target:
|
||||
//
|
||||
// * MachO - macos-like targets will insert the metadata into a section that
|
||||
// is sort of fake dwarf debug info. Inspecting the source of the macos
|
||||
// linker this causes these sections to be skipped automatically because
|
||||
// it's not in an allowlist of otherwise well known dwarf section names to
|
||||
// go into the final artifact.
|
||||
//
|
||||
// * WebAssembly - we actually don't have any container format for this
|
||||
// target. WebAssembly doesn't support the `dylib` crate type anyway so
|
||||
// there's no need for us to support this at this time. Consequently the
|
||||
// metadata bytes are simply stored as-is into an rlib.
|
||||
//
|
||||
// * COFF - Windows-like targets create an object with a section that has
|
||||
// the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
|
||||
// ever sees the section it doesn't process it and it's removed.
|
||||
//
|
||||
// * ELF - All other targets are similar to Windows in that there's a
|
||||
// `SHF_EXCLUDE` flag we can set on sections in an object file to get
|
||||
// automatically removed from the final output.
|
||||
//
|
||||
// Note that this metdata format is kept in sync with
|
||||
// `rustc_codegen_ssa/src/back/metadata.rs`.
|
||||
fn create_metadata_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
|
||||
let endianness = match sess.target.options.endian {
|
||||
Endian::Little => Endianness::Little,
|
||||
Endian::Big => Endianness::Big,
|
||||
};
|
||||
let architecture = match &sess.target.arch[..] {
|
||||
"arm" => Architecture::Arm,
|
||||
"aarch64" => Architecture::Aarch64,
|
||||
"x86" => Architecture::I386,
|
||||
"s390x" => Architecture::S390x,
|
||||
"mips" => Architecture::Mips,
|
||||
"mips64" => Architecture::Mips64,
|
||||
"x86_64" => {
|
||||
if sess.target.pointer_width == 32 {
|
||||
Architecture::X86_64_X32
|
||||
} else {
|
||||
Architecture::X86_64
|
||||
}
|
||||
}
|
||||
"powerpc" => Architecture::PowerPc,
|
||||
"powerpc64" => Architecture::PowerPc64,
|
||||
"riscv32" => Architecture::Riscv32,
|
||||
"riscv64" => Architecture::Riscv64,
|
||||
"sparc64" => Architecture::Sparc64,
|
||||
|
||||
// This is used to handle all "other" targets. This includes targets
|
||||
// in two categories:
|
||||
//
|
||||
// * Some targets don't have support in the `object` crate just yet
|
||||
// to write an object file. These targets are likely to get filled
|
||||
// out over time.
|
||||
//
|
||||
// * Targets like WebAssembly don't support dylibs, so the purpose
|
||||
// of putting metadata in object files, to support linking rlibs
|
||||
// into dylibs, is moot.
|
||||
//
|
||||
// In both of these cases it means that linking into dylibs will
|
||||
// not be supported by rustc. This doesn't matter for targets like
|
||||
// WebAssembly and for targets not supported by the `object` crate
|
||||
// yet it means that work will need to be done in the `object` crate
|
||||
// to add a case above.
|
||||
_ => return metadata.to_vec(),
|
||||
};
|
||||
|
||||
if sess.target.is_like_osx {
|
||||
let mut file = Object::new(BinaryFormat::MachO, architecture, endianness);
|
||||
|
||||
let section =
|
||||
file.add_section(b"__DWARF".to_vec(), b".rmeta".to_vec(), SectionKind::Debug);
|
||||
file.append_section_data(section, metadata, 1);
|
||||
file.write().unwrap()
|
||||
} else if sess.target.is_like_windows {
|
||||
const IMAGE_SCN_LNK_REMOVE: u32 = 0;
|
||||
let mut file = Object::new(BinaryFormat::Coff, architecture, endianness);
|
||||
|
||||
let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
|
||||
file.section_mut(section).flags =
|
||||
SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
|
||||
file.append_section_data(section, metadata, 1);
|
||||
file.write().unwrap()
|
||||
} else {
|
||||
const SHF_EXCLUDE: u64 = 0x80000000;
|
||||
let mut file = Object::new(BinaryFormat::Elf, architecture, endianness);
|
||||
|
||||
match &sess.target.arch[..] {
|
||||
// copied from `mipsel-linux-gnu-gcc foo.c -c` and
|
||||
// inspecting the resulting `e_flags` field.
|
||||
"mips" => {
|
||||
let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
|
||||
file.flags = FileFlags::Elf { e_flags };
|
||||
}
|
||||
// copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
|
||||
"mips64" => {
|
||||
let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
|
||||
file.flags = FileFlags::Elf { e_flags };
|
||||
}
|
||||
|
||||
// copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
|
||||
// that the `+d` target feature represents whether the double
|
||||
// float abi is enabled.
|
||||
"riscv64" if sess.target.options.features.contains("+d") => {
|
||||
let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
|
||||
file.flags = FileFlags::Elf { e_flags };
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
|
||||
file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
|
||||
file.append_section_data(section, metadata, 1);
|
||||
file.write().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract all symbols defined in raw-dylib libraries, collated by library name.
|
||||
///
|
||||
/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
|
||||
/// then the CodegenResults value contains one NativeLib instance for each block. However, the
|
||||
/// linker appears to expect only a single import library for each library used, so we need to
|
||||
/// collate the symbols together by library name before generating the import libraries.
|
||||
fn collate_raw_dylibs(used_libraries: &[NativeLib]) -> Vec<(String, Vec<DllImport>)> {
|
||||
let mut dylib_table: FxHashMap<String, FxHashSet<Symbol>> = FxHashMap::default();
|
||||
|
||||
for lib in used_libraries {
|
||||
if lib.kind == NativeLibKind::RawDylib {
|
||||
let name = lib.name.unwrap_or_else(||
|
||||
bug!("`link` attribute with kind = \"raw-dylib\" and no name should have caused error earlier")
|
||||
);
|
||||
let name = if matches!(lib.verbatim, Some(true)) {
|
||||
name.to_string()
|
||||
} else {
|
||||
format!("{}.dll", name)
|
||||
};
|
||||
dylib_table
|
||||
.entry(name)
|
||||
.or_default()
|
||||
.extend(lib.dll_imports.iter().map(|import| import.name));
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: when we add support for ordinals, fix this to propagate ordinals. Also figure out
|
||||
// what we should do if we have two DllImport values with the same name but different
|
||||
// ordinals.
|
||||
let mut result = dylib_table
|
||||
.into_iter()
|
||||
.map(|(lib_name, imported_names)| {
|
||||
let mut names = imported_names
|
||||
.iter()
|
||||
.map(|name| DllImport { name: *name, ordinal: None })
|
||||
.collect::<Vec<_>>();
|
||||
names.sort_unstable_by(|a: &DllImport, b: &DllImport| {
|
||||
match a.name.as_str().cmp(&b.name.as_str()) {
|
||||
Ordering::Equal => a.ordinal.cmp(&b.ordinal),
|
||||
x => x,
|
||||
}
|
||||
});
|
||||
(lib_name, names)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
result.sort_unstable_by(|a: &(String, Vec<DllImport>), b: &(String, Vec<DllImport>)| {
|
||||
a.0.cmp(&b.0)
|
||||
});
|
||||
result
|
||||
}
|
||||
|
||||
/// Create a static archive.
|
||||
|
|
@ -714,14 +907,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
|
|||
}
|
||||
}
|
||||
|
||||
fn escape_string(s: &[u8]) -> String {
|
||||
str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| {
|
||||
let mut x = "Non-UTF-8 output: ".to_string();
|
||||
x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from));
|
||||
x
|
||||
})
|
||||
}
|
||||
|
||||
match prog {
|
||||
Ok(prog) => {
|
||||
if !prog.status.success() {
|
||||
|
|
@ -863,9 +1048,50 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
|
|||
// ... and otherwise we're processing a `*.dwp` packed dwarf file.
|
||||
SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename),
|
||||
}
|
||||
|
||||
if sess.target.is_like_osx {
|
||||
if let Some(option) = osx_strip_opt(sess.opts.debugging_opts.strip) {
|
||||
strip_symbols_in_osx(sess, &out_filename, option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
|
||||
fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: &str) {
|
||||
let prog = Command::new("strip").arg(option).arg(out_filename).output();
|
||||
match prog {
|
||||
Ok(prog) => {
|
||||
if !prog.status.success() {
|
||||
let mut output = prog.stderr.clone();
|
||||
output.extend_from_slice(&prog.stdout);
|
||||
sess.struct_warn(&format!(
|
||||
"stripping debug info with `strip` failed: {}",
|
||||
prog.status
|
||||
))
|
||||
.note(&escape_string(&output))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
Err(e) => sess.fatal(&format!("unable to run `strip`: {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn osx_strip_opt<'a>(strip: Strip) -> Option<&'a str> {
|
||||
match strip {
|
||||
Strip::Debuginfo => Some("-S"),
|
||||
Strip::Symbols => Some("-x"),
|
||||
Strip::None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn escape_string(s: &[u8]) -> String {
|
||||
str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| {
|
||||
let mut x = "Non-UTF-8 output: ".to_string();
|
||||
x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from));
|
||||
x
|
||||
})
|
||||
}
|
||||
|
||||
fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
|
||||
// On macOS the runtimes are distributed as dylibs which should be linked to
|
||||
// both executables and dynamic shared objects. Everywhere else the runtimes
|
||||
// are currently distributed as static liraries which should be linked to
|
||||
|
|
@ -954,7 +1180,8 @@ pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool
|
|||
&& (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
|
||||
}
|
||||
|
||||
fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
||||
// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use
|
||||
pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
||||
fn infer_from(
|
||||
sess: &Session,
|
||||
linker: Option<PathBuf>,
|
||||
|
|
@ -989,6 +1216,7 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
|||
LinkerFlavor::Msvc => "link.exe",
|
||||
LinkerFlavor::Lld(_) => "lld",
|
||||
LinkerFlavor::PtxLinker => "rust-ptx-linker",
|
||||
LinkerFlavor::BpfLinker => "bpf-linker",
|
||||
}),
|
||||
flavor,
|
||||
)),
|
||||
|
|
@ -1005,6 +1233,8 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
|||
|| stem.ends_with("-clang")
|
||||
{
|
||||
LinkerFlavor::Gcc
|
||||
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
|
||||
LinkerFlavor::Lld(LldFlavor::Wasm)
|
||||
} else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
|
||||
LinkerFlavor::Ld
|
||||
} else if stem == "link" || stem == "lld-link" {
|
||||
|
|
@ -1484,55 +1714,6 @@ fn add_local_crate_metadata_objects(
|
|||
}
|
||||
}
|
||||
|
||||
/// Link native libraries corresponding to the current crate and all libraries corresponding to
|
||||
/// all its dependency crates.
|
||||
/// FIXME: Consider combining this with the functions above adding object files for the local crate.
|
||||
fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<'a>>(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &'a Session,
|
||||
crate_type: CrateType,
|
||||
codegen_results: &CodegenResults,
|
||||
tmpdir: &Path,
|
||||
) {
|
||||
// Take careful note of the ordering of the arguments we pass to the linker
|
||||
// here. Linkers will assume that things on the left depend on things to the
|
||||
// right. Things on the right cannot depend on things on the left. This is
|
||||
// all formally implemented in terms of resolving symbols (libs on the right
|
||||
// resolve unknown symbols of libs on the left, but not vice versa).
|
||||
//
|
||||
// For this reason, we have organized the arguments we pass to the linker as
|
||||
// such:
|
||||
//
|
||||
// 1. The local object that LLVM just generated
|
||||
// 2. Local native libraries
|
||||
// 3. Upstream rust libraries
|
||||
// 4. Upstream native libraries
|
||||
//
|
||||
// The rationale behind this ordering is that those items lower down in the
|
||||
// list can't depend on items higher up in the list. For example nothing can
|
||||
// depend on what we just generated (e.g., that'd be a circular dependency).
|
||||
// Upstream rust libraries are not allowed to depend on our local native
|
||||
// libraries as that would violate the structure of the DAG, in that
|
||||
// scenario they are required to link to them as well in a shared fashion.
|
||||
//
|
||||
// Note that upstream rust libraries may contain native dependencies as
|
||||
// well, but they also can't depend on what we just started to add to the
|
||||
// link line. And finally upstream native libraries can't depend on anything
|
||||
// in this DAG so far because they're only dylibs and dylibs can only depend
|
||||
// on other dylibs (e.g., other native deps).
|
||||
//
|
||||
// If -Zlink-native-libraries=false is set, then the assumption is that an
|
||||
// external build system already has the native dependencies defined, and it
|
||||
// will provide them to the linker itself.
|
||||
if sess.opts.debugging_opts.link_native_libraries {
|
||||
add_local_native_libraries(cmd, sess, codegen_results);
|
||||
}
|
||||
add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
|
||||
if sess.opts.debugging_opts.link_native_libraries {
|
||||
add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add sysroot and other globally set directories to the directory search list.
|
||||
fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
|
||||
// The default library location, we need this to find the runtime.
|
||||
|
|
@ -1567,36 +1748,27 @@ fn add_rpath_args(
|
|||
) {
|
||||
// FIXME (#2397): At some point we want to rpath our guesses as to
|
||||
// where extern libraries might live, based on the
|
||||
// addl_lib_search_paths
|
||||
// add_lib_search_paths
|
||||
if sess.opts.cg.rpath {
|
||||
let target_triple = sess.opts.target_triple.triple();
|
||||
let mut get_install_prefix_lib_path = || {
|
||||
let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX");
|
||||
let tlib = rustc_target::target_rustlib_path(&sess.sysroot, target_triple).join("lib");
|
||||
let mut path = PathBuf::from(install_prefix);
|
||||
path.push(&tlib);
|
||||
|
||||
path
|
||||
};
|
||||
let mut rpath_config = RPathConfig {
|
||||
used_crates: &codegen_results.crate_info.used_crates_dynamic,
|
||||
out_filename: out_filename.to_path_buf(),
|
||||
has_rpath: sess.target.has_rpath,
|
||||
is_like_osx: sess.target.is_like_osx,
|
||||
linker_is_gnu: sess.target.linker_is_gnu,
|
||||
get_install_prefix_lib_path: &mut get_install_prefix_lib_path,
|
||||
};
|
||||
cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
|
||||
}
|
||||
}
|
||||
|
||||
/// Produce the linker command line containing linker path and arguments.
|
||||
/// `NO-OPT-OUT` marks the arguments that cannot be removed from the command line
|
||||
/// by the user without creating a custom target specification.
|
||||
/// `OBJECT-FILES` specify whether the arguments can add object files.
|
||||
/// `CUSTOMIZATION-POINT` means that arbitrary arguments defined by the user
|
||||
/// or by the target spec can be inserted here.
|
||||
/// `AUDIT-ORDER` - need to figure out whether the option is order-dependent or not.
|
||||
///
|
||||
/// When comments in the function say "order-(in)dependent" they mean order-dependence between
|
||||
/// options and libraries/object files. For example `--whole-archive` (order-dependent) applies
|
||||
/// to specific libraries passed after it, and `-o` (output file, order-independent) applies
|
||||
/// to the linking process as a whole.
|
||||
/// Order-independent options may still override each other in order-dependent fashion,
|
||||
/// e.g `--foo=yes --foo=no` may be equivalent to `--foo=no`.
|
||||
fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
||||
path: &Path,
|
||||
flavor: LinkerFlavor,
|
||||
|
|
@ -1614,16 +1786,153 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
|||
let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor);
|
||||
let link_output_kind = link_output_kind(sess, crate_type);
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
|
||||
// ------------ Early order-dependent options ------------
|
||||
|
||||
// If we're building something like a dynamic library then some platforms
|
||||
// need to make sure that all symbols are exported correctly from the
|
||||
// dynamic library.
|
||||
// Must be passed before any libraries to prevent the symbols to export from being thrown away,
|
||||
// at least on some platforms (e.g. windows-gnu).
|
||||
cmd.export_symbols(tmpdir, crate_type);
|
||||
|
||||
// Can be used for adding custom CRT objects or overriding order-dependent options above.
|
||||
// FIXME: In practice built-in target specs use this for arbitrary order-independent options,
|
||||
// introduce a target spec option for order-independent linker options and migrate built-in
|
||||
// specs to it.
|
||||
add_pre_link_args(cmd, sess, flavor);
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO
|
||||
// ------------ Object code and libraries, order-dependent ------------
|
||||
|
||||
// Pre-link CRT objects.
|
||||
add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
|
||||
|
||||
// Sanitizer libraries.
|
||||
add_sanitizer_libraries(sess, crate_type, cmd);
|
||||
|
||||
// Object code from the current crate.
|
||||
// Take careful note of the ordering of the arguments we pass to the linker
|
||||
// here. Linkers will assume that things on the left depend on things to the
|
||||
// right. Things on the right cannot depend on things on the left. This is
|
||||
// all formally implemented in terms of resolving symbols (libs on the right
|
||||
// resolve unknown symbols of libs on the left, but not vice versa).
|
||||
//
|
||||
// For this reason, we have organized the arguments we pass to the linker as
|
||||
// such:
|
||||
//
|
||||
// 1. The local object that LLVM just generated
|
||||
// 2. Local native libraries
|
||||
// 3. Upstream rust libraries
|
||||
// 4. Upstream native libraries
|
||||
//
|
||||
// The rationale behind this ordering is that those items lower down in the
|
||||
// list can't depend on items higher up in the list. For example nothing can
|
||||
// depend on what we just generated (e.g., that'd be a circular dependency).
|
||||
// Upstream rust libraries are not supposed to depend on our local native
|
||||
// libraries as that would violate the structure of the DAG, in that
|
||||
// scenario they are required to link to them as well in a shared fashion.
|
||||
// (The current implementation still doesn't prevent it though, see the FIXME below.)
|
||||
//
|
||||
// Note that upstream rust libraries may contain native dependencies as
|
||||
// well, but they also can't depend on what we just started to add to the
|
||||
// link line. And finally upstream native libraries can't depend on anything
|
||||
// in this DAG so far because they can only depend on other native libraries
|
||||
// and such dependencies are also required to be specified.
|
||||
add_local_crate_regular_objects(cmd, codegen_results);
|
||||
add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
|
||||
add_local_crate_allocator_objects(cmd, codegen_results);
|
||||
|
||||
// Avoid linking to dynamic libraries unless they satisfy some undefined symbols
|
||||
// at the point at which they are specified on the command line.
|
||||
// Must be passed before any (dynamic) libraries to have effect on them.
|
||||
// On Solaris-like systems, `-z ignore` acts as both `--as-needed` and `--gc-sections`
|
||||
// so it will ignore unreferenced ELF sections from relocatable objects.
|
||||
// For that reason, we put this flag after metadata objects as they would otherwise be removed.
|
||||
// FIXME: Support more fine-grained dead code removal on Solaris/illumos
|
||||
// and move this option back to the top.
|
||||
cmd.add_as_needed();
|
||||
|
||||
// FIXME: Move this below to other native libraries
|
||||
// (or alternatively link all native libraries after their respective crates).
|
||||
// This change is somewhat breaking in practice due to local static libraries being linked
|
||||
// as whole-archive (#85144), so removing whole-archive may be a pre-requisite.
|
||||
if sess.opts.debugging_opts.link_native_libraries {
|
||||
add_local_native_libraries(cmd, sess, codegen_results);
|
||||
}
|
||||
|
||||
// Rust libraries.
|
||||
add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
|
||||
|
||||
// Native libraries linked with `#[link]` attributes at and `-l` command line options.
|
||||
// If -Zlink-native-libraries=false is set, then the assumption is that an
|
||||
// external build system already has the native dependencies defined, and it
|
||||
// will provide them to the linker itself.
|
||||
if sess.opts.debugging_opts.link_native_libraries {
|
||||
add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
|
||||
}
|
||||
|
||||
// Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
|
||||
// command line shorter, reset it to default here before adding more libraries.
|
||||
cmd.reset_per_library_state();
|
||||
|
||||
// FIXME: Built-in target specs occasionally use this for linking system libraries,
|
||||
// eliminate all such uses by migrating them to `#[link]` attributes in `lib(std,c,unwind)`
|
||||
// and remove the option.
|
||||
add_late_link_args(cmd, sess, flavor, crate_type, codegen_results);
|
||||
|
||||
// ------------ Arbitrary order-independent options ------------
|
||||
|
||||
// Add order-independent options determined by rustc from its compiler options,
|
||||
// target properties and source code.
|
||||
add_order_independent_options(
|
||||
cmd,
|
||||
sess,
|
||||
link_output_kind,
|
||||
crt_objects_fallback,
|
||||
flavor,
|
||||
crate_type,
|
||||
codegen_results,
|
||||
out_filename,
|
||||
tmpdir,
|
||||
);
|
||||
|
||||
// Can be used for arbitrary order-independent options.
|
||||
// In practice may also be occasionally used for linking native libraries.
|
||||
// Passed after compiler-generated options to support manual overriding when necessary.
|
||||
add_user_defined_link_args(cmd, sess);
|
||||
|
||||
// ------------ Object code and libraries, order-dependent ------------
|
||||
|
||||
// Post-link CRT objects.
|
||||
add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
|
||||
|
||||
// ------------ Late order-dependent options ------------
|
||||
|
||||
// Doesn't really make sense.
|
||||
// FIXME: In practice built-in target specs use this for arbitrary order-independent options,
|
||||
// introduce a target spec option for order-independent linker options, migrate built-in specs
|
||||
// to it and remove the option.
|
||||
add_post_link_args(cmd, sess, flavor);
|
||||
|
||||
cmd.take_cmd()
|
||||
}
|
||||
|
||||
fn add_order_independent_options(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &Session,
|
||||
link_output_kind: LinkOutputKind,
|
||||
crt_objects_fallback: bool,
|
||||
flavor: LinkerFlavor,
|
||||
crate_type: CrateType,
|
||||
codegen_results: &CodegenResults,
|
||||
out_filename: &Path,
|
||||
tmpdir: &Path,
|
||||
) {
|
||||
add_gcc_ld_path(cmd, sess, flavor);
|
||||
|
||||
add_apple_sdk(cmd, sess, flavor);
|
||||
|
||||
// NO-OPT-OUT
|
||||
add_link_script(cmd, sess, tmpdir, crate_type);
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
if sess.target.is_like_fuchsia && crate_type == CrateType::Executable {
|
||||
let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
|
||||
"asan/"
|
||||
|
|
@ -1633,30 +1942,17 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
|||
cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
|
||||
}
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
if sess.target.eh_frame_header {
|
||||
cmd.add_eh_frame_header();
|
||||
}
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// Make the binary compatible with data execution prevention schemes.
|
||||
cmd.add_no_exec();
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO
|
||||
// Avoid linking to dynamic libraries unless they satisfy some undefined symbols
|
||||
// at the point at which they are specified on the command line.
|
||||
// Must be passed before any dynamic libraries.
|
||||
cmd.add_as_needed();
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO
|
||||
if crt_objects_fallback {
|
||||
cmd.no_crt_objects();
|
||||
}
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-YES
|
||||
add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
if sess.target.is_like_emscripten {
|
||||
cmd.arg("-s");
|
||||
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
|
||||
|
|
@ -1666,45 +1962,32 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
|||
});
|
||||
}
|
||||
|
||||
// OBJECT-FILES-YES, AUDIT-ORDER
|
||||
link_sanitizers(sess, crate_type, cmd);
|
||||
if flavor == LinkerFlavor::PtxLinker {
|
||||
// Provide the linker with fallback to internal `target-cpu`.
|
||||
cmd.arg("--fallback-arch");
|
||||
cmd.arg(&codegen_results.linker_info.target_cpu);
|
||||
} else if flavor == LinkerFlavor::BpfLinker {
|
||||
cmd.arg("--cpu");
|
||||
cmd.arg(&codegen_results.linker_info.target_cpu);
|
||||
cmd.arg("--cpu-features");
|
||||
cmd.arg(match &sess.opts.cg.target_feature {
|
||||
feat if !feat.is_empty() => feat,
|
||||
_ => &sess.target.options.features,
|
||||
});
|
||||
}
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// Linker plugins should be specified early in the list of arguments
|
||||
// FIXME: How "early" exactly?
|
||||
cmd.linker_plugin_lto();
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// FIXME: Order-dependent, at least relatively to other args adding searh directories.
|
||||
add_library_search_dirs(cmd, sess, crt_objects_fallback);
|
||||
|
||||
// OBJECT-FILES-YES
|
||||
add_local_crate_regular_objects(cmd, codegen_results);
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
cmd.output_filename(out_filename);
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
if crate_type == CrateType::Executable && sess.target.is_like_windows {
|
||||
if let Some(ref s) = codegen_results.windows_subsystem {
|
||||
if let Some(ref s) = codegen_results.crate_info.windows_subsystem {
|
||||
cmd.subsystem(s);
|
||||
}
|
||||
}
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// If we're building something like a dynamic library then some platforms
|
||||
// need to make sure that all symbols are exported correctly from the
|
||||
// dynamic library.
|
||||
cmd.export_symbols(tmpdir, crate_type);
|
||||
|
||||
// OBJECT-FILES-YES
|
||||
add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
|
||||
|
||||
// OBJECT-FILES-YES
|
||||
add_local_crate_allocator_objects(cmd, codegen_results);
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// FIXME: Order dependent, applies to the following objects. Where should it be placed?
|
||||
// Try to strip as much out of the generated object by removing unused
|
||||
// sections if possible. See more comments in linker.rs
|
||||
if !sess.link_dead_code() {
|
||||
|
|
@ -1712,65 +1995,31 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
|||
cmd.gc_sections(keep_metadata);
|
||||
}
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
cmd.set_output_kind(link_output_kind, out_filename);
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
add_relro_args(cmd, sess);
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// Pass optimization flags down to the linker.
|
||||
cmd.optimize();
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// Pass debuginfo and strip flags down to the linker.
|
||||
cmd.debuginfo(sess.opts.debugging_opts.strip);
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// We want to prevent the compiler from accidentally leaking in any system libraries,
|
||||
// so by default we tell linkers not to link to any default libraries.
|
||||
if !sess.opts.cg.default_linker_libraries && sess.target.no_default_libraries {
|
||||
cmd.no_default_libraries();
|
||||
}
|
||||
|
||||
// OBJECT-FILES-YES
|
||||
link_local_crate_native_libs_and_dependent_crate_libs::<B>(
|
||||
cmd,
|
||||
sess,
|
||||
crate_type,
|
||||
codegen_results,
|
||||
tmpdir,
|
||||
);
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
if sess.opts.cg.profile_generate.enabled() || sess.instrument_coverage() {
|
||||
cmd.pgo_gen();
|
||||
}
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
if sess.opts.cg.control_flow_guard != CFGuard::Disabled {
|
||||
cmd.control_flow_guard();
|
||||
}
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
add_rpath_args(cmd, sess, codegen_results, out_filename);
|
||||
|
||||
// OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
|
||||
add_user_defined_link_args(cmd, sess);
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
cmd.finalize();
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
|
||||
add_late_link_args(cmd, sess, flavor, crate_type, codegen_results);
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-YES
|
||||
add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
|
||||
add_post_link_args(cmd, sess, flavor);
|
||||
|
||||
cmd.take_cmd()
|
||||
}
|
||||
|
||||
/// # Native library linking
|
||||
|
|
@ -1964,11 +2213,8 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
|
|||
}
|
||||
|
||||
// Adds the static "rlib" versions of all crates to the command line.
|
||||
// There's a bit of magic which happens here specifically related to LTO and
|
||||
// dynamic libraries. Specifically:
|
||||
//
|
||||
// * For LTO, we remove upstream object files.
|
||||
// * For dylibs we remove metadata and bytecode from upstream rlibs
|
||||
// There's a bit of magic which happens here specifically related to LTO,
|
||||
// namely that we remove upstream object files.
|
||||
//
|
||||
// When performing LTO, almost(*) all of the bytecode from the upstream
|
||||
// libraries has already been included in our object file output. As a
|
||||
|
|
@ -1981,20 +2227,9 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
|
|||
// their bytecode wasn't included. The object files in those libraries must
|
||||
// still be passed to the linker.
|
||||
//
|
||||
// When making a dynamic library, linkers by default don't include any
|
||||
// object files in an archive if they're not necessary to resolve the link.
|
||||
// We basically want to convert the archive (rlib) to a dylib, though, so we
|
||||
// *do* want everything included in the output, regardless of whether the
|
||||
// linker thinks it's needed or not. As a result we must use the
|
||||
// --whole-archive option (or the platform equivalent). When using this
|
||||
// option the linker will fail if there are non-objects in the archive (such
|
||||
// as our own metadata and/or bytecode). All in all, for rlibs to be
|
||||
// entirely included in dylibs, we need to remove all non-object files.
|
||||
//
|
||||
// Note, however, that if we're not doing LTO or we're not producing a dylib
|
||||
// (aka we're making an executable), we can just pass the rlib blindly to
|
||||
// the linker (fast) because it's fine if it's not actually included as
|
||||
// we're at the end of the dependency chain.
|
||||
// Note, however, that if we're not doing LTO we can just pass the rlib
|
||||
// blindly to the linker (fast) because it's fine if it's not actually
|
||||
// included as we're at the end of the dependency chain.
|
||||
fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &'a Session,
|
||||
|
|
@ -2006,6 +2241,24 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
|
|||
let src = &codegen_results.crate_info.used_crate_source[&cnum];
|
||||
let cratepath = &src.rlib.as_ref().unwrap().0;
|
||||
|
||||
let mut link_upstream = |path: &Path| {
|
||||
// If we're creating a dylib, then we need to include the
|
||||
// whole of each object in our archive into that artifact. This is
|
||||
// because a `dylib` can be reused as an intermediate artifact.
|
||||
//
|
||||
// Note, though, that we don't want to include the whole of a
|
||||
// compiler-builtins crate (e.g., compiler-rt) because it'll get
|
||||
// repeatedly linked anyway.
|
||||
let path = fix_windows_verbatim_for_gcc(path);
|
||||
if crate_type == CrateType::Dylib
|
||||
&& codegen_results.crate_info.compiler_builtins != Some(cnum)
|
||||
{
|
||||
cmd.link_whole_rlib(&path);
|
||||
} else {
|
||||
cmd.link_rlib(&path);
|
||||
}
|
||||
};
|
||||
|
||||
// See the comment above in `link_staticlib` and `link_rlib` for why if
|
||||
// there's a static library that's not relevant we skip all object
|
||||
// files.
|
||||
|
|
@ -2017,10 +2270,9 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
|
|||
|
||||
if (!are_upstream_rust_objects_already_included(sess)
|
||||
|| ignored_for_lto(sess, &codegen_results.crate_info, cnum))
|
||||
&& crate_type != CrateType::Dylib
|
||||
&& !skip_native
|
||||
{
|
||||
cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
|
||||
link_upstream(cratepath);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2070,21 +2322,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
|
|||
return;
|
||||
}
|
||||
archive.build();
|
||||
|
||||
// If we're creating a dylib, then we need to include the
|
||||
// whole of each object in our archive into that artifact. This is
|
||||
// because a `dylib` can be reused as an intermediate artifact.
|
||||
//
|
||||
// Note, though, that we don't want to include the whole of a
|
||||
// compiler-builtins crate (e.g., compiler-rt) because it'll get
|
||||
// repeatedly linked anyway.
|
||||
if crate_type == CrateType::Dylib
|
||||
&& codegen_results.crate_info.compiler_builtins != Some(cnum)
|
||||
{
|
||||
cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst));
|
||||
} else {
|
||||
cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst));
|
||||
}
|
||||
link_upstream(&dst);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -2178,10 +2416,7 @@ fn add_upstream_native_libraries(
|
|||
// already included them when we included the rust library
|
||||
// previously
|
||||
NativeLibKind::Static { bundle: None | Some(true), .. } => {}
|
||||
NativeLibKind::RawDylib => {
|
||||
// FIXME(#58713): Proper handling for raw dylibs.
|
||||
bug!("raw_dylib feature not yet implemented");
|
||||
}
|
||||
NativeLibKind::RawDylib => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2295,3 +2530,30 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
|
|||
Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
|
||||
if let Some(ld_impl) = sess.opts.debugging_opts.gcc_ld {
|
||||
if let LinkerFlavor::Gcc = flavor {
|
||||
match ld_impl {
|
||||
LdImpl::Lld => {
|
||||
let tools_path =
|
||||
sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
|
||||
let lld_path = tools_path
|
||||
.into_iter()
|
||||
.map(|p| p.join("gcc-ld"))
|
||||
.find(|p| {
|
||||
p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists()
|
||||
})
|
||||
.unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
|
||||
cmd.cmd().arg({
|
||||
let mut arg = OsString::from("-B");
|
||||
arg.push(lld_path);
|
||||
arg
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sess.fatal("option `-Z gcc-ld` is used even though linker flavor is not gcc");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ pub fn disable_localization(linker: &mut Command) {
|
|||
/// need out of the shared crate context before we get rid of it.
|
||||
#[derive(Encodable, Decodable)]
|
||||
pub struct LinkerInfo {
|
||||
target_cpu: String,
|
||||
pub(super) target_cpu: String,
|
||||
exports: FxHashMap<CrateType, Vec<String>>,
|
||||
}
|
||||
|
||||
|
|
@ -81,8 +81,10 @@ impl LinkerInfo {
|
|||
Box::new(WasmLd::new(cmd, sess, self)) as Box<dyn Linker>
|
||||
}
|
||||
|
||||
LinkerFlavor::PtxLinker => {
|
||||
Box::new(PtxLinker { cmd, sess, info: self }) as Box<dyn Linker>
|
||||
LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
|
||||
|
||||
LinkerFlavor::BpfLinker => {
|
||||
Box::new(BpfLinker { cmd, sess, info: self }) as Box<dyn Linker>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +130,7 @@ pub trait Linker {
|
|||
fn add_eh_frame_header(&mut self) {}
|
||||
fn add_no_exec(&mut self) {}
|
||||
fn add_as_needed(&mut self) {}
|
||||
fn finalize(&mut self);
|
||||
fn reset_per_library_state(&mut self) {}
|
||||
}
|
||||
|
||||
impl dyn Linker + '_ {
|
||||
|
|
@ -472,7 +474,9 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
// eliminate the metadata. If we're building an executable, however,
|
||||
// --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
|
||||
// reduction.
|
||||
} else if self.sess.target.linker_is_gnu && !keep_metadata {
|
||||
} else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm)
|
||||
&& !keep_metadata
|
||||
{
|
||||
self.linker_arg("--gc-sections");
|
||||
}
|
||||
}
|
||||
|
|
@ -480,13 +484,13 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
fn no_gc_sections(&mut self) {
|
||||
if self.sess.target.is_like_osx {
|
||||
self.linker_arg("-no_dead_strip");
|
||||
} else if self.sess.target.linker_is_gnu {
|
||||
} else if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm {
|
||||
self.linker_arg("--no-gc-sections");
|
||||
}
|
||||
}
|
||||
|
||||
fn optimize(&mut self) {
|
||||
if !self.sess.target.linker_is_gnu {
|
||||
if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -522,15 +526,18 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
fn control_flow_guard(&mut self) {}
|
||||
|
||||
fn debuginfo(&mut self, strip: Strip) {
|
||||
// MacOS linker doesn't support stripping symbols directly anymore.
|
||||
if self.sess.target.is_like_osx {
|
||||
return;
|
||||
}
|
||||
|
||||
match strip {
|
||||
Strip::None => {}
|
||||
Strip::Debuginfo => {
|
||||
// MacOS linker does not support longhand argument --strip-debug
|
||||
self.linker_arg("-S");
|
||||
self.linker_arg("--strip-debug");
|
||||
}
|
||||
Strip::Symbols => {
|
||||
// MacOS linker does not support longhand argument --strip-all
|
||||
self.linker_arg("-s");
|
||||
self.linker_arg("--strip-all");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -647,7 +654,7 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
self.linker_arg(&subsystem);
|
||||
}
|
||||
|
||||
fn finalize(&mut self) {
|
||||
fn reset_per_library_state(&mut self) {
|
||||
self.hint_dynamic(); // Reset to default before returning the composed command line.
|
||||
}
|
||||
|
||||
|
|
@ -931,8 +938,6 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn finalize(&mut self) {}
|
||||
|
||||
// MSVC doesn't need group indicators
|
||||
fn group_start(&mut self) {}
|
||||
fn group_end(&mut self) {}
|
||||
|
|
@ -1093,8 +1098,6 @@ impl<'a> Linker for EmLinker<'a> {
|
|||
// noop
|
||||
}
|
||||
|
||||
fn finalize(&mut self) {}
|
||||
|
||||
// Appears not necessary on Emscripten
|
||||
fn group_start(&mut self) {}
|
||||
fn group_end(&mut self) {}
|
||||
|
|
@ -1275,8 +1278,6 @@ impl<'a> Linker for WasmLd<'a> {
|
|||
|
||||
fn subsystem(&mut self, _subsystem: &str) {}
|
||||
|
||||
fn finalize(&mut self) {}
|
||||
|
||||
// Not needed for now with LLD
|
||||
fn group_start(&mut self) {}
|
||||
fn group_end(&mut self) {}
|
||||
|
|
@ -1330,7 +1331,6 @@ fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
|
|||
pub struct PtxLinker<'a> {
|
||||
cmd: Command,
|
||||
sess: &'a Session,
|
||||
info: &'a LinkerInfo,
|
||||
}
|
||||
|
||||
impl<'a> Linker for PtxLinker<'a> {
|
||||
|
|
@ -1374,11 +1374,6 @@ impl<'a> Linker for PtxLinker<'a> {
|
|||
self.cmd.arg("-o").arg(path);
|
||||
}
|
||||
|
||||
fn finalize(&mut self) {
|
||||
// Provide the linker with fallback to internal `target-cpu`.
|
||||
self.cmd.arg("--fallback-arch").arg(&self.info.target_cpu);
|
||||
}
|
||||
|
||||
fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
|
||||
panic!("external dylibs not supported")
|
||||
}
|
||||
|
|
@ -1431,3 +1426,117 @@ impl<'a> Linker for PtxLinker<'a> {
|
|||
|
||||
fn linker_plugin_lto(&mut self) {}
|
||||
}
|
||||
|
||||
pub struct BpfLinker<'a> {
|
||||
cmd: Command,
|
||||
sess: &'a Session,
|
||||
info: &'a LinkerInfo,
|
||||
}
|
||||
|
||||
impl<'a> Linker for BpfLinker<'a> {
|
||||
fn cmd(&mut self) -> &mut Command {
|
||||
&mut self.cmd
|
||||
}
|
||||
|
||||
fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
|
||||
|
||||
fn link_rlib(&mut self, path: &Path) {
|
||||
self.cmd.arg(path);
|
||||
}
|
||||
|
||||
fn link_whole_rlib(&mut self, path: &Path) {
|
||||
self.cmd.arg(path);
|
||||
}
|
||||
|
||||
fn include_path(&mut self, path: &Path) {
|
||||
self.cmd.arg("-L").arg(path);
|
||||
}
|
||||
|
||||
fn debuginfo(&mut self, _strip: Strip) {
|
||||
self.cmd.arg("--debug");
|
||||
}
|
||||
|
||||
fn add_object(&mut self, path: &Path) {
|
||||
self.cmd.arg(path);
|
||||
}
|
||||
|
||||
fn optimize(&mut self) {
|
||||
self.cmd.arg(match self.sess.opts.optimize {
|
||||
OptLevel::No => "-O0",
|
||||
OptLevel::Less => "-O1",
|
||||
OptLevel::Default => "-O2",
|
||||
OptLevel::Aggressive => "-O3",
|
||||
OptLevel::Size => "-Os",
|
||||
OptLevel::SizeMin => "-Oz",
|
||||
});
|
||||
}
|
||||
|
||||
fn output_filename(&mut self, path: &Path) {
|
||||
self.cmd.arg("-o").arg(path);
|
||||
}
|
||||
|
||||
fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
|
||||
panic!("external dylibs not supported")
|
||||
}
|
||||
|
||||
fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
|
||||
panic!("external dylibs not supported")
|
||||
}
|
||||
|
||||
fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
|
||||
panic!("staticlibs not supported")
|
||||
}
|
||||
|
||||
fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
|
||||
panic!("staticlibs not supported")
|
||||
}
|
||||
|
||||
fn framework_path(&mut self, _path: &Path) {
|
||||
panic!("frameworks not supported")
|
||||
}
|
||||
|
||||
fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
|
||||
panic!("frameworks not supported")
|
||||
}
|
||||
|
||||
fn full_relro(&mut self) {}
|
||||
|
||||
fn partial_relro(&mut self) {}
|
||||
|
||||
fn no_relro(&mut self) {}
|
||||
|
||||
fn gc_sections(&mut self, _keep_metadata: bool) {}
|
||||
|
||||
fn no_gc_sections(&mut self) {}
|
||||
|
||||
fn pgo_gen(&mut self) {}
|
||||
|
||||
fn no_crt_objects(&mut self) {}
|
||||
|
||||
fn no_default_libraries(&mut self) {}
|
||||
|
||||
fn control_flow_guard(&mut self) {}
|
||||
|
||||
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
|
||||
let path = tmpdir.join("symbols");
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
for sym in self.info.exports[&crate_type].iter() {
|
||||
writeln!(f, "{}", sym)?;
|
||||
}
|
||||
};
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to write symbols file: {}", e));
|
||||
} else {
|
||||
self.cmd.arg("--export-symbols").arg(&path);
|
||||
}
|
||||
}
|
||||
|
||||
fn subsystem(&mut self, _subsystem: &str) {}
|
||||
|
||||
fn group_start(&mut self) {}
|
||||
|
||||
fn group_end(&mut self) {}
|
||||
|
||||
fn linker_plugin_lto(&mut self) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
|
||||
use object::{Object, ObjectSection};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::owning_ref::OwningRef;
|
||||
use rustc_data_structures::rustc_erase_owner;
|
||||
|
|
@ -46,7 +47,10 @@ impl MetadataLoader for DefaultMetadataLoader {
|
|||
let entry = entry_result
|
||||
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
|
||||
if entry.name() == METADATA_FILENAME.as_bytes() {
|
||||
return Ok(entry.data());
|
||||
let data = entry
|
||||
.data(data)
|
||||
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
|
||||
return search_for_metadata(path, data, ".rmeta");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -55,17 +59,27 @@ impl MetadataLoader for DefaultMetadataLoader {
|
|||
}
|
||||
|
||||
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
|
||||
use object::{Object, ObjectSection};
|
||||
|
||||
load_metadata_with(path, |data| {
|
||||
let file = object::File::parse(&data)
|
||||
.map_err(|e| format!("failed to parse dylib '{}': {}", path.display(), e))?;
|
||||
file.section_by_name(".rustc")
|
||||
.ok_or_else(|| format!("no .rustc section in '{}'", path.display()))?
|
||||
.data()
|
||||
.map_err(|e| {
|
||||
format!("failed to read .rustc section in '{}': {}", path.display(), e)
|
||||
})
|
||||
})
|
||||
load_metadata_with(path, |data| search_for_metadata(path, data, ".rustc"))
|
||||
}
|
||||
}
|
||||
|
||||
fn search_for_metadata<'a>(
|
||||
path: &Path,
|
||||
bytes: &'a [u8],
|
||||
section: &str,
|
||||
) -> Result<&'a [u8], String> {
|
||||
let file = match object::File::parse(bytes) {
|
||||
Ok(f) => f,
|
||||
// The parse above could fail for odd reasons like corruption, but for
|
||||
// now we just interpret it as this target doesn't support metadata
|
||||
// emission in object files so the entire byte slice itself is probably
|
||||
// a metadata file. Ideally though if necessary we could at least check
|
||||
// the prefix of bytes to see if it's an actual metadata object and if
|
||||
// not forward the error along here.
|
||||
Err(_) => return Ok(bytes),
|
||||
};
|
||||
file.section_by_name(section)
|
||||
.ok_or_else(|| format!("no `{}` section in '{}'", section, path.display()))?
|
||||
.data()
|
||||
.map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ pub struct RPathConfig<'a> {
|
|||
pub is_like_osx: bool,
|
||||
pub has_rpath: bool,
|
||||
pub linker_is_gnu: bool,
|
||||
pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf,
|
||||
}
|
||||
|
||||
pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
|
||||
|
|
@ -63,24 +62,13 @@ fn get_rpaths(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec<String> {
|
|||
// Use relative paths to the libraries. Binaries can be moved
|
||||
// as long as they maintain the relative relationship to the
|
||||
// crates they depend on.
|
||||
let rel_rpaths = get_rpaths_relative_to_output(config, libs);
|
||||
let rpaths = get_rpaths_relative_to_output(config, libs);
|
||||
|
||||
// And a final backup rpath to the global library location.
|
||||
let fallback_rpaths = vec![get_install_prefix_rpath(config)];
|
||||
|
||||
fn log_rpaths(desc: &str, rpaths: &[String]) {
|
||||
debug!("{} rpaths:", desc);
|
||||
for rpath in rpaths {
|
||||
debug!(" {}", *rpath);
|
||||
}
|
||||
debug!("rpaths:");
|
||||
for rpath in &rpaths {
|
||||
debug!(" {}", rpath);
|
||||
}
|
||||
|
||||
log_rpaths("relative", &rel_rpaths);
|
||||
log_rpaths("fallback", &fallback_rpaths);
|
||||
|
||||
let mut rpaths = rel_rpaths;
|
||||
rpaths.extend_from_slice(&fallback_rpaths);
|
||||
|
||||
// Remove duplicates
|
||||
minimize_rpaths(&rpaths)
|
||||
}
|
||||
|
|
@ -113,13 +101,6 @@ fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
|
|||
diff_paths(path, base)
|
||||
}
|
||||
|
||||
fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String {
|
||||
let path = (config.get_install_prefix_lib_path)();
|
||||
let path = env::current_dir().unwrap().join(&path);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
path.to_str().expect("non-utf8 component in rpath").to_owned()
|
||||
}
|
||||
|
||||
fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
|
||||
let mut set = FxHashSet::default();
|
||||
let mut minimized = Vec::new();
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ fn test_rpath_relative() {
|
|||
is_like_osx: true,
|
||||
linker_is_gnu: false,
|
||||
out_filename: PathBuf::from("bin/rustc"),
|
||||
get_install_prefix_lib_path: &mut || panic!(),
|
||||
};
|
||||
let res = get_rpath_relative_to_output(config, Path::new("lib/libstd.so"));
|
||||
assert_eq!(res, "@loader_path/../lib");
|
||||
|
|
@ -48,7 +47,6 @@ fn test_rpath_relative() {
|
|||
let config = &mut RPathConfig {
|
||||
used_crates: &[],
|
||||
out_filename: PathBuf::from("bin/rustc"),
|
||||
get_install_prefix_lib_path: &mut || panic!(),
|
||||
has_rpath: true,
|
||||
is_like_osx: false,
|
||||
linker_is_gnu: true,
|
||||
|
|
|
|||
|
|
@ -370,7 +370,6 @@ pub fn provide(providers: &mut Providers) {
|
|||
pub fn provide_extern(providers: &mut Providers) {
|
||||
providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
|
||||
providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
|
||||
providers.wasm_import_module_map = wasm_import_module_map;
|
||||
}
|
||||
|
||||
fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType};
|
|||
use rustc_session::config::{Passes, SwitchWithOptPath};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
|
||||
use rustc_target::spec::{MergeFunctions, PanicStrategy, SanitizerSet};
|
||||
|
||||
|
|
@ -426,21 +426,9 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
let (coordinator_send, coordinator_receive) = channel();
|
||||
let sess = tcx.sess;
|
||||
|
||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins);
|
||||
let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins);
|
||||
let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
|
||||
let windows_subsystem = subsystem.map(|subsystem| {
|
||||
if subsystem != sym::windows && subsystem != sym::console {
|
||||
tcx.sess.fatal(&format!(
|
||||
"invalid windows subsystem `{}`, only \
|
||||
`windows` and `console` are allowed",
|
||||
subsystem
|
||||
));
|
||||
}
|
||||
subsystem.to_string()
|
||||
});
|
||||
|
||||
let linker_info = LinkerInfo::new(tcx, target_cpu);
|
||||
let crate_info = CrateInfo::new(tcx);
|
||||
|
|
@ -472,9 +460,7 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
|
||||
OngoingCodegen {
|
||||
backend,
|
||||
crate_name,
|
||||
metadata,
|
||||
windows_subsystem,
|
||||
linker_info,
|
||||
crate_info,
|
||||
|
||||
|
|
@ -1812,9 +1798,7 @@ impl SharedEmitterMain {
|
|||
|
||||
pub struct OngoingCodegen<B: ExtraBackendMethods> {
|
||||
pub backend: B,
|
||||
pub crate_name: Symbol,
|
||||
pub metadata: EncodedMetadata,
|
||||
pub windows_subsystem: Option<String>,
|
||||
pub linker_info: LinkerInfo,
|
||||
pub crate_info: CrateInfo,
|
||||
pub coordinator_send: Sender<Box<dyn Any + Send>>,
|
||||
|
|
@ -1857,9 +1841,7 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
|||
|
||||
(
|
||||
CodegenResults {
|
||||
crate_name: self.crate_name,
|
||||
metadata: self.metadata,
|
||||
windows_subsystem: self.windows_subsystem,
|
||||
linker_info: self.linker_info,
|
||||
crate_info: self.crate_info,
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
|||
use rustc_session::cgu_reuse_tracker::CguReuse;
|
||||
use rustc_session::config::{self, EntryFnType};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_target::abi::{Align, LayoutOf, VariantIdx};
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
|
@ -755,7 +756,22 @@ impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> {
|
|||
|
||||
impl CrateInfo {
|
||||
pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
|
||||
let local_crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
|
||||
let windows_subsystem = subsystem.map(|subsystem| {
|
||||
if subsystem != sym::windows && subsystem != sym::console {
|
||||
tcx.sess.fatal(&format!(
|
||||
"invalid windows subsystem `{}`, only \
|
||||
`windows` and `console` are allowed",
|
||||
subsystem
|
||||
));
|
||||
}
|
||||
subsystem.to_string()
|
||||
});
|
||||
|
||||
let mut info = CrateInfo {
|
||||
local_crate_name,
|
||||
panic_runtime: None,
|
||||
compiler_builtins: None,
|
||||
profiler_runtime: None,
|
||||
|
|
@ -769,6 +785,7 @@ impl CrateInfo {
|
|||
lang_item_to_crate: Default::default(),
|
||||
missing_lang_items: Default::default(),
|
||||
dependency_formats: tcx.dependency_formats(()),
|
||||
windows_subsystem,
|
||||
};
|
||||
let lang_items = tcx.lang_items();
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ pub struct Expression {
|
|||
/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
|
||||
/// for a gap area is only used as the line execution count if there are no other regions on a
|
||||
/// line."
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionCoverage<'tcx> {
|
||||
instance: Instance<'tcx>,
|
||||
source_hash: u64,
|
||||
|
|
@ -113,6 +114,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
|
|||
expression_id, lhs, op, rhs, region
|
||||
);
|
||||
let expression_index = self.expression_index(u32::from(expression_id));
|
||||
debug_assert!(
|
||||
expression_index.as_usize() < self.expressions.len(),
|
||||
"expression_index {} is out of range for expressions.len() = {}
|
||||
for {:?}",
|
||||
expression_index.as_usize(),
|
||||
self.expressions.len(),
|
||||
self,
|
||||
);
|
||||
if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
|
||||
lhs,
|
||||
op,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty, TyCtxt};
|
||||
use rustc_target::abi::{TagEncoding, Variants};
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
|
|
@ -45,8 +46,12 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
ty::Float(float_ty) => output.push_str(float_ty.name_str()),
|
||||
ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
|
||||
ty::Adt(def, substs) => {
|
||||
push_item_name(tcx, def.did, qualified, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
if def.is_enum() && cpp_like_names {
|
||||
msvc_enum_fallback(tcx, t, def, substs, output, visited);
|
||||
} else {
|
||||
push_item_name(tcx, def.did, qualified, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
}
|
||||
}
|
||||
ty::Tuple(component_types) => {
|
||||
if cpp_like_names {
|
||||
|
|
@ -233,6 +238,54 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
/// MSVC names enums differently than other platforms so that the debugging visualization
|
||||
// format (natvis) is able to understand enums and render the active variant correctly in the
|
||||
// debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and
|
||||
// `EnumMemberDescriptionFactor::create_member_descriptions`.
|
||||
fn msvc_enum_fallback(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
def: &AdtDef,
|
||||
substs: SubstsRef<'tcx>,
|
||||
output: &mut String,
|
||||
visited: &mut FxHashSet<Ty<'tcx>>,
|
||||
) {
|
||||
let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error");
|
||||
|
||||
if let Variants::Multiple {
|
||||
tag_encoding: TagEncoding::Niche { dataful_variant, .. },
|
||||
tag,
|
||||
variants,
|
||||
..
|
||||
} = &layout.variants
|
||||
{
|
||||
let dataful_variant_layout = &variants[*dataful_variant];
|
||||
|
||||
// calculate the range of values for the dataful variant
|
||||
let dataful_discriminant_range =
|
||||
&dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range;
|
||||
|
||||
let min = dataful_discriminant_range.start();
|
||||
let min = tag.value.size(&tcx).truncate(*min);
|
||||
|
||||
let max = dataful_discriminant_range.end();
|
||||
let max = tag.value.size(&tcx).truncate(*max);
|
||||
|
||||
output.push_str("enum$<");
|
||||
push_item_name(tcx, def.did, true, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
|
||||
let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
|
||||
|
||||
output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name));
|
||||
} else {
|
||||
output.push_str("enum$<");
|
||||
push_item_name(tcx, def.did, true, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
output.push('>');
|
||||
}
|
||||
}
|
||||
|
||||
fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
|
||||
if qualified {
|
||||
output.push_str(&tcx.crate_name(def_id.krate).as_str());
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(nll)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(iter_zip)]
|
||||
#![recursion_limit = "256"]
|
||||
#![feature(box_syntax)]
|
||||
|
||||
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
|
||||
//! The backend-agnostic functions of this crate use functions defined in various traits that
|
||||
|
|
@ -114,11 +110,18 @@ pub struct NativeLib {
|
|||
pub name: Option<Symbol>,
|
||||
pub cfg: Option<ast::MetaItem>,
|
||||
pub verbatim: Option<bool>,
|
||||
pub dll_imports: Vec<cstore::DllImport>,
|
||||
}
|
||||
|
||||
impl From<&cstore::NativeLib> for NativeLib {
|
||||
fn from(lib: &cstore::NativeLib) -> Self {
|
||||
NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim }
|
||||
NativeLib {
|
||||
kind: lib.kind,
|
||||
name: lib.name,
|
||||
cfg: lib.cfg.clone(),
|
||||
verbatim: lib.verbatim,
|
||||
dll_imports: lib.dll_imports.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,6 +135,7 @@ impl From<&cstore::NativeLib> for NativeLib {
|
|||
/// and the corresponding properties without referencing information outside of a `CrateInfo`.
|
||||
#[derive(Debug, Encodable, Decodable)]
|
||||
pub struct CrateInfo {
|
||||
pub local_crate_name: Symbol,
|
||||
pub panic_runtime: Option<CrateNum>,
|
||||
pub compiler_builtins: Option<CrateNum>,
|
||||
pub profiler_runtime: Option<CrateNum>,
|
||||
|
|
@ -145,16 +149,15 @@ pub struct CrateInfo {
|
|||
pub lang_item_to_crate: FxHashMap<LangItem, CrateNum>,
|
||||
pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
|
||||
pub dependency_formats: Lrc<Dependencies>,
|
||||
pub windows_subsystem: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Encodable, Decodable)]
|
||||
pub struct CodegenResults {
|
||||
pub crate_name: Symbol,
|
||||
pub modules: Vec<CompiledModule>,
|
||||
pub allocator_module: Option<CompiledModule>,
|
||||
pub metadata_module: Option<CompiledModule>,
|
||||
pub metadata: rustc_middle::middle::cstore::EncodedMetadata,
|
||||
pub windows_subsystem: Option<String>,
|
||||
pub linker_info: back::linker::LinkerInfo,
|
||||
pub crate_info: CrateInfo,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,8 @@ use rustc_data_structures::graph::dominators::Dominators;
|
|||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_middle::mir::traversal;
|
||||
use rustc_middle::mir::visit::{
|
||||
MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, Visitor,
|
||||
};
|
||||
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{self, Location, TerminatorKind};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
use rustc_target::abi::LayoutOf;
|
||||
|
||||
|
|
@ -21,7 +18,12 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
let mir = fx.mir;
|
||||
let mut analyzer = LocalAnalyzer::new(fx);
|
||||
|
||||
analyzer.visit_body(&mir);
|
||||
// If there exists a local definition that dominates all uses of that local,
|
||||
// the definition should be visited first. Traverse blocks in preorder which
|
||||
// is a topological sort of dominance partial order.
|
||||
for (bb, data) in traversal::preorder(&mir) {
|
||||
analyzer.visit_basic_block_data(bb, data);
|
||||
}
|
||||
|
||||
for (local, decl) in mir.local_decls.iter_enumerated() {
|
||||
let ty = fx.monomorphize(decl.ty);
|
||||
|
|
@ -142,36 +144,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
|
||||
if let mir::ProjectionElem::Deref = elem {
|
||||
// Deref projections typically only read the pointer.
|
||||
// (the exception being `VarDebugInfo` contexts, handled below)
|
||||
base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
|
||||
|
||||
// Indirect debuginfo requires going through memory, that only
|
||||
// the debugger accesses, following our emitted DWARF pointer ops.
|
||||
//
|
||||
// FIXME(eddyb) Investigate the possibility of relaxing this, but
|
||||
// note that `llvm.dbg.declare` *must* be used for indirect places,
|
||||
// even if we start using `llvm.dbg.value` for all other cases,
|
||||
// as we don't necessarily know when the value changes, but only
|
||||
// where it lives in memory.
|
||||
//
|
||||
// It's possible `llvm.dbg.declare` could support starting from
|
||||
// a pointer that doesn't point to an `alloca`, but this would
|
||||
// only be useful if we know the pointer being `Deref`'d comes
|
||||
// from an immutable place, and if `llvm.dbg.declare` calls
|
||||
// must be at the very start of the function, then only function
|
||||
// arguments could contain such pointers.
|
||||
if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
|
||||
// We use `NonUseContext::VarDebugInfo` for the base,
|
||||
// which might not force the base local to memory,
|
||||
// so we have to do it manually.
|
||||
self.visit_local(&place_ref.local, context, location);
|
||||
}
|
||||
}
|
||||
|
||||
// `NonUseContext::VarDebugInfo` needs to flow all the
|
||||
// way down to the base local (see `visit_local`).
|
||||
if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
|
||||
base_context = context;
|
||||
}
|
||||
|
||||
self.process_place(&place_base, base_context, location);
|
||||
|
|
@ -186,20 +159,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
// FIXME this is super_place code, is repeated here to avoid cloning place or changing
|
||||
// visit_place API
|
||||
let mut context = context;
|
||||
|
||||
if !place_ref.projection.is_empty() {
|
||||
context = if context.is_mutating_use() {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
||||
} else {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
|
||||
};
|
||||
}
|
||||
|
||||
self.visit_local(&place_ref.local, context, location);
|
||||
self.visit_projection(*place_ref, context, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -228,34 +188,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
self.visit_rvalue(rvalue, location);
|
||||
}
|
||||
|
||||
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
|
||||
let check = match terminator.kind {
|
||||
mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => {
|
||||
match *c.ty().kind() {
|
||||
ty::FnDef(did, _) => Some((did, args)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some((def_id, args)) = check {
|
||||
if Some(def_id) == self.fx.cx.tcx().lang_items().box_free_fn() {
|
||||
// box_free(x) shares with `drop x` the property that it
|
||||
// is not guaranteed to be statically dominated by the
|
||||
// definition of x, so x must always be in an alloca.
|
||||
if let mir::Operand::Move(ref place) = args[0] {
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop),
|
||||
location,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.super_terminator(terminator, location);
|
||||
}
|
||||
|
||||
fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
|
||||
debug!("visit_place(place={:?}, context={:?})", place, context);
|
||||
self.process_place(&place.as_ref(), context, location);
|
||||
|
|
|
|||
|
|
@ -205,11 +205,13 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
|||
];
|
||||
|
||||
const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
("simd128", Some(sym::wasm_target_feature)),
|
||||
("simd128", None),
|
||||
("atomics", Some(sym::wasm_target_feature)),
|
||||
("nontrapping-fptoint", Some(sym::wasm_target_feature)),
|
||||
];
|
||||
|
||||
const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];
|
||||
|
||||
/// When rustdoc is running, provide a list of all known features so that all their respective
|
||||
/// primitives may be documented.
|
||||
///
|
||||
|
|
@ -224,6 +226,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol
|
|||
.chain(MIPS_ALLOWED_FEATURES.iter())
|
||||
.chain(RISCV_ALLOWED_FEATURES.iter())
|
||||
.chain(WASM_ALLOWED_FEATURES.iter())
|
||||
.chain(BPF_ALLOWED_FEATURES.iter())
|
||||
.cloned()
|
||||
}
|
||||
|
||||
|
|
@ -237,6 +240,7 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt
|
|||
"powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
|
||||
"riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
|
||||
"wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
|
||||
"bpf" => BPF_ALLOWED_FEATURES,
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,9 +63,16 @@ pub trait CodegenBackend {
|
|||
None
|
||||
}
|
||||
|
||||
fn metadata_loader(&self) -> Box<MetadataLoaderDyn>;
|
||||
fn provide(&self, _providers: &mut Providers);
|
||||
fn provide_extern(&self, _providers: &mut Providers);
|
||||
/// The metadata loader used to load rlib and dylib metadata.
|
||||
///
|
||||
/// Alternative codegen backends may want to use different rlib or dylib formats than the
|
||||
/// default native static archives and dynamic libraries.
|
||||
fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
|
||||
Box::new(crate::back::metadata::DefaultMetadataLoader)
|
||||
}
|
||||
|
||||
fn provide(&self, _providers: &mut Providers) {}
|
||||
fn provide_extern(&self, _providers: &mut Providers) {}
|
||||
fn codegen_crate<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -1,169 +0,0 @@
|
|||
//! This module provides a way to deal with self-referential data.
|
||||
//!
|
||||
//! The main idea is to allocate such data in a generator frame and then
|
||||
//! give access to it by executing user-provided closures inside that generator.
|
||||
//! The module provides a safe abstraction for the latter task.
|
||||
//!
|
||||
//! The interface consists of two exported macros meant to be used together:
|
||||
//! * `declare_box_region_type` wraps a generator inside a struct with `access`
|
||||
//! method which accepts closures.
|
||||
//! * `box_region_allow_access` is a helper which should be called inside
|
||||
//! a generator to actually execute those closures.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Generator, GeneratorState};
|
||||
use std::pin::Pin;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AccessAction(*mut dyn FnMut());
|
||||
|
||||
impl AccessAction {
|
||||
pub fn get(self) -> *mut dyn FnMut() {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Action {
|
||||
Initial,
|
||||
Access(AccessAction),
|
||||
Complete,
|
||||
}
|
||||
|
||||
pub struct PinnedGenerator<I, A, R> {
|
||||
generator: Pin<Box<dyn Generator<Action, Yield = YieldType<I, A>, Return = R>>>,
|
||||
}
|
||||
|
||||
impl<I, A, R> PinnedGenerator<I, A, R> {
|
||||
pub fn new<T: Generator<Action, Yield = YieldType<I, A>, Return = R> + 'static>(
|
||||
generator: T,
|
||||
) -> (I, Self) {
|
||||
let mut result = PinnedGenerator { generator: Box::pin(generator) };
|
||||
|
||||
// Run it to the first yield to set it up
|
||||
let init = match Pin::new(&mut result.generator).resume(Action::Initial) {
|
||||
GeneratorState::Yielded(YieldType::Initial(y)) => y,
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
(init, result)
|
||||
}
|
||||
|
||||
pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) {
|
||||
// Call the generator, which in turn will call the closure
|
||||
if let GeneratorState::Complete(_) =
|
||||
Pin::new(&mut self.generator).resume(Action::Access(AccessAction(closure)))
|
||||
{
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn complete(&mut self) -> R {
|
||||
// Tell the generator we want it to complete, consuming it and yielding a result
|
||||
let result = Pin::new(&mut self.generator).resume(Action::Complete);
|
||||
if let GeneratorState::Complete(r) = result { r } else { panic!() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct Marker<T>(PhantomData<T>);
|
||||
|
||||
impl<T> Marker<T> {
|
||||
pub unsafe fn new() -> Self {
|
||||
Marker(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum YieldType<I, A> {
|
||||
Initial(I),
|
||||
Accessor(Marker<A>),
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable(fn_traits)]
|
||||
macro_rules! declare_box_region_type {
|
||||
(impl $v:vis
|
||||
$name: ident,
|
||||
$yield_type:ty,
|
||||
for($($lifetimes:tt)*),
|
||||
($($args:ty),*) -> ($reti:ty, $retc:ty)
|
||||
) => {
|
||||
$v struct $name($crate::box_region::PinnedGenerator<
|
||||
$reti,
|
||||
for<$($lifetimes)*> fn(($($args,)*)),
|
||||
$retc
|
||||
>);
|
||||
|
||||
impl $name {
|
||||
fn new<T: ::std::ops::Generator<$crate::box_region::Action, Yield = $yield_type, Return = $retc> + 'static>(
|
||||
generator: T
|
||||
) -> ($reti, Self) {
|
||||
let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator);
|
||||
(initial, $name(pinned))
|
||||
}
|
||||
|
||||
$v fn access<F: for<$($lifetimes)*> FnOnce($($args,)*) -> R, R>(&mut self, f: F) -> R {
|
||||
// Turn the FnOnce closure into *mut dyn FnMut()
|
||||
// so we can pass it in to the generator
|
||||
let mut r = None;
|
||||
let mut f = Some(f);
|
||||
let mut_f: &mut dyn for<$($lifetimes)*> FnMut(($($args,)*)) =
|
||||
&mut |args| {
|
||||
let f = f.take().unwrap();
|
||||
r = Some(FnOnce::call_once(f, args));
|
||||
};
|
||||
let mut_f = mut_f as *mut dyn for<$($lifetimes)*> FnMut(($($args,)*));
|
||||
|
||||
// Get the generator to call our closure
|
||||
unsafe {
|
||||
self.0.access(::std::mem::transmute(mut_f));
|
||||
}
|
||||
|
||||
// Unwrap the result
|
||||
r.unwrap()
|
||||
}
|
||||
|
||||
$v fn complete(mut self) -> $retc {
|
||||
self.0.complete()
|
||||
}
|
||||
|
||||
fn initial_yield(value: $reti) -> $yield_type {
|
||||
$crate::box_region::YieldType::Initial(value)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($v:vis $name: ident, for($($lifetimes:tt)*), ($($args:ty),*) -> ($reti:ty, $retc:ty)) => {
|
||||
declare_box_region_type!(
|
||||
impl $v $name,
|
||||
$crate::box_region::YieldType<$reti, for<$($lifetimes)*> fn(($($args,)*))>,
|
||||
for($($lifetimes)*),
|
||||
($($args),*) -> ($reti, $retc)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable(fn_traits)]
|
||||
macro_rules! box_region_allow_access {
|
||||
(for($($lifetimes:tt)*), ($($args:ty),*), ($($exprs:expr),*), $action:ident) => {
|
||||
loop {
|
||||
match $action {
|
||||
$crate::box_region::Action::Access(accessor) => {
|
||||
let accessor: &mut dyn for<$($lifetimes)*> FnMut($($args),*) = unsafe {
|
||||
::std::mem::transmute(accessor.get())
|
||||
};
|
||||
(*accessor)(($($exprs),*));
|
||||
unsafe {
|
||||
let marker = $crate::box_region::Marker::<
|
||||
for<$($lifetimes)*> fn(($($args,)*))
|
||||
>::new();
|
||||
$action = yield $crate::box_region::YieldType::Accessor(marker);
|
||||
};
|
||||
}
|
||||
$crate::box_region::Action::Complete => break,
|
||||
$crate::box_region::Action::Initial => panic!("unexpected box_region action: Initial"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,15 +10,11 @@
|
|||
#![feature(array_windows)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(generator_trait)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(auto_traits)]
|
||||
#![feature(nll)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(hash_raw_entry)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(test)]
|
||||
#![feature(associated_type_bounds)]
|
||||
|
|
@ -66,7 +62,6 @@ macro_rules! unlikely {
|
|||
|
||||
pub mod base_n;
|
||||
pub mod binary_search_util;
|
||||
pub mod box_region;
|
||||
pub mod captures;
|
||||
pub mod flock;
|
||||
pub mod functor;
|
||||
|
|
@ -99,6 +94,7 @@ pub mod thin_vec;
|
|||
pub mod tiny_list;
|
||||
pub mod transitive_relation;
|
||||
pub mod vec_linked_list;
|
||||
pub mod vec_map;
|
||||
pub mod work_queue;
|
||||
pub use atomic_ref::AtomicRef;
|
||||
pub mod frozen;
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
match self.active_cache.entry(cache_key.clone()) {
|
||||
match self.active_cache.entry(cache_key) {
|
||||
Entry::Occupied(o) => {
|
||||
let node = &mut self.nodes[*o.get()];
|
||||
if let Some(parent_index) = parent {
|
||||
|
|
@ -366,8 +366,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
&& self
|
||||
.error_cache
|
||||
.get(&obligation_tree_id)
|
||||
.map(|errors| errors.contains(&cache_key))
|
||||
.unwrap_or(false);
|
||||
.map_or(false, |errors| errors.contains(v.key()));
|
||||
|
||||
if already_failed {
|
||||
Err(())
|
||||
|
|
@ -597,7 +596,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
Some(rpos) => {
|
||||
// Cycle detected.
|
||||
processor.process_backedge(
|
||||
stack[rpos..].iter().map(GetObligation(&self.nodes)),
|
||||
stack[rpos..].iter().map(|&i| &self.nodes[i].obligation),
|
||||
PhantomData,
|
||||
);
|
||||
}
|
||||
|
|
@ -705,20 +704,3 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
// I need a Clone closure.
|
||||
#[derive(Clone)]
|
||||
struct GetObligation<'a, O>(&'a [Node<O>]);
|
||||
|
||||
impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> {
|
||||
type Output = &'a O;
|
||||
extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O {
|
||||
&self.0[*args.0].obligation
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> {
|
||||
extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O {
|
||||
&self.0[*args.0].obligation
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -550,35 +550,3 @@ pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>(
|
|||
entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2));
|
||||
entries.hash_stable(hcx, hasher);
|
||||
}
|
||||
|
||||
/// A vector container that makes sure that its items are hashed in a stable
|
||||
/// order.
|
||||
#[derive(Debug)]
|
||||
pub struct StableVec<T>(Vec<T>);
|
||||
|
||||
impl<T> StableVec<T> {
|
||||
pub fn new(v: Vec<T>) -> Self {
|
||||
StableVec(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ::std::ops::Deref for StableVec<T> {
|
||||
type Target = Vec<T>;
|
||||
|
||||
fn deref(&self) -> &Vec<T> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, HCX> HashStable<HCX> for StableVec<T>
|
||||
where
|
||||
T: HashStable<HCX> + ToStableHashKey<HCX>,
|
||||
{
|
||||
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
|
||||
let StableVec(ref v) = *self;
|
||||
|
||||
let mut sorted: Vec<_> = v.iter().map(|x| x.to_stable_hash_key(hcx)).collect();
|
||||
sorted.sort_unstable();
|
||||
sorted.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,49 +43,9 @@ cfg_if! {
|
|||
use std::ops::Add;
|
||||
use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe};
|
||||
|
||||
/// This is a single threaded variant of AtomicCell provided by crossbeam.
|
||||
/// Unlike `Atomic` this is intended for all `Copy` types,
|
||||
/// but it lacks the explicit ordering arguments.
|
||||
#[derive(Debug)]
|
||||
pub struct AtomicCell<T: Copy>(Cell<T>);
|
||||
|
||||
impl<T: Copy> AtomicCell<T> {
|
||||
#[inline]
|
||||
pub fn new(v: T) -> Self {
|
||||
AtomicCell(Cell::new(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
self.0.get_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> AtomicCell<T> {
|
||||
#[inline]
|
||||
pub fn into_inner(self) -> T {
|
||||
self.0.into_inner()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn load(&self) -> T {
|
||||
self.0.get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn store(&self, val: T) {
|
||||
self.0.set(val)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn swap(&self, val: T) -> T {
|
||||
self.0.replace(val)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc.
|
||||
/// It differs from `AtomicCell` in that it has explicit ordering arguments
|
||||
/// and is only intended for use with the native atomic types.
|
||||
/// It has explicit ordering arguments and is only intended for use with
|
||||
/// the native atomic types.
|
||||
/// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases
|
||||
/// as it's not intended to be used separately.
|
||||
#[derive(Debug)]
|
||||
|
|
@ -159,22 +119,6 @@ cfg_if! {
|
|||
(oper_a(), oper_b())
|
||||
}
|
||||
|
||||
pub struct SerialScope;
|
||||
|
||||
impl SerialScope {
|
||||
pub fn spawn<F>(&self, f: F)
|
||||
where F: FnOnce(&SerialScope)
|
||||
{
|
||||
f(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scope<F, R>(f: F) -> R
|
||||
where F: FnOnce(&SerialScope) -> R
|
||||
{
|
||||
f(&SerialScope)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! parallel {
|
||||
($($blocks:tt),*) => {
|
||||
|
|
@ -318,8 +262,6 @@ cfg_if! {
|
|||
|
||||
pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
|
||||
|
||||
pub use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
pub use std::sync::Arc as Lrc;
|
||||
pub use std::sync::Weak as Weak;
|
||||
|
||||
|
|
|
|||
|
|
@ -90,9 +90,11 @@ pub unsafe trait Tag: Copy {
|
|||
|
||||
unsafe impl<T> Pointer for Box<T> {
|
||||
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
|
||||
#[inline]
|
||||
fn into_usize(self) -> usize {
|
||||
Box::into_raw(self) as usize
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn from_usize(ptr: usize) -> Self {
|
||||
Box::from_raw(ptr as *mut T)
|
||||
}
|
||||
|
|
@ -104,9 +106,11 @@ unsafe impl<T> Pointer for Box<T> {
|
|||
|
||||
unsafe impl<T> Pointer for Rc<T> {
|
||||
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
|
||||
#[inline]
|
||||
fn into_usize(self) -> usize {
|
||||
Rc::into_raw(self) as usize
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn from_usize(ptr: usize) -> Self {
|
||||
Rc::from_raw(ptr as *const T)
|
||||
}
|
||||
|
|
@ -118,9 +122,11 @@ unsafe impl<T> Pointer for Rc<T> {
|
|||
|
||||
unsafe impl<T> Pointer for Arc<T> {
|
||||
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
|
||||
#[inline]
|
||||
fn into_usize(self) -> usize {
|
||||
Arc::into_raw(self) as usize
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn from_usize(ptr: usize) -> Self {
|
||||
Arc::from_raw(ptr as *const T)
|
||||
}
|
||||
|
|
@ -132,9 +138,11 @@ unsafe impl<T> Pointer for Arc<T> {
|
|||
|
||||
unsafe impl<'a, T: 'a> Pointer for &'a T {
|
||||
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
|
||||
#[inline]
|
||||
fn into_usize(self) -> usize {
|
||||
self as *const T as usize
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn from_usize(ptr: usize) -> Self {
|
||||
&*(ptr as *const T)
|
||||
}
|
||||
|
|
@ -145,9 +153,11 @@ unsafe impl<'a, T: 'a> Pointer for &'a T {
|
|||
|
||||
unsafe impl<'a, T: 'a> Pointer for &'a mut T {
|
||||
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
|
||||
#[inline]
|
||||
fn into_usize(self) -> usize {
|
||||
self as *mut T as usize
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn from_usize(ptr: usize) -> Self {
|
||||
&mut *(ptr as *mut T)
|
||||
}
|
||||
|
|
|
|||
155
compiler/rustc_data_structures/src/vec_map.rs
Normal file
155
compiler/rustc_data_structures/src/vec_map.rs
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::iter::FromIterator;
|
||||
use std::slice::{Iter, IterMut};
|
||||
use std::vec::IntoIter;
|
||||
|
||||
use crate::stable_hasher::{HashStable, StableHasher};
|
||||
|
||||
/// A map type implemented as a vector of pairs `K` (key) and `V` (value).
|
||||
/// It currently provides a subset of all the map operations, the rest could be added as needed.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct VecMap<K, V>(Vec<(K, V)>);
|
||||
|
||||
impl<K, V> VecMap<K, V>
|
||||
where
|
||||
K: PartialEq,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
VecMap(Default::default())
|
||||
}
|
||||
|
||||
/// Sets the value of the entry, and returns the entry's old value.
|
||||
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
|
||||
if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) {
|
||||
Some(std::mem::replace(&mut elem.1, v))
|
||||
} else {
|
||||
self.0.push((k, v));
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a reference to the value in the entry.
|
||||
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
|
||||
}
|
||||
|
||||
/// Returns the value corresponding to the supplied predicate filter.
|
||||
///
|
||||
/// The supplied predicate will be applied to each (key, value) pair and it will return a
|
||||
/// reference to the values where the predicate returns `true`.
|
||||
pub fn get_by(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
|
||||
self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1)
|
||||
}
|
||||
|
||||
/// Returns `true` if the map contains a value for the specified key.
|
||||
///
|
||||
/// The key may be any borrowed form of the map's key type,
|
||||
/// [`Eq`] on the borrowed form *must* match those for
|
||||
/// the key type.
|
||||
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
self.get(k).is_some()
|
||||
}
|
||||
|
||||
/// Returns `true` if the map contains no elements.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<'_, (K, V)> {
|
||||
self.into_iter()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> IterMut<'_, (K, V)> {
|
||||
self.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Default for VecMap<K, V> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> {
|
||||
fn from(vec: Vec<(K, V)>) -> Self {
|
||||
Self(vec)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Into<Vec<(K, V)>> for VecMap<K, V> {
|
||||
fn into(self) -> Vec<(K, V)> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> FromIterator<(K, V)> for VecMap<K, V> {
|
||||
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
|
||||
Self(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> IntoIterator for &'a VecMap<K, V> {
|
||||
type Item = &'a (K, V);
|
||||
type IntoIter = Iter<'a, (K, V)>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> IntoIterator for &'a mut VecMap<K, V> {
|
||||
type Item = &'a mut (K, V);
|
||||
type IntoIter = IterMut<'a, (K, V)>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> IntoIterator for VecMap<K, V> {
|
||||
type Item = (K, V);
|
||||
type IntoIter = IntoIter<(K, V)>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Extend<(K, V)> for VecMap<K, V> {
|
||||
fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
|
||||
self.0.extend(iter);
|
||||
}
|
||||
|
||||
fn extend_one(&mut self, item: (K, V)) {
|
||||
self.0.extend_one(item);
|
||||
}
|
||||
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
self.0.extend_reserve(additional);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, CTX> HashStable<CTX> for VecMap<K, V>
|
||||
where
|
||||
K: HashStable<CTX> + Eq,
|
||||
V: HashStable<CTX>,
|
||||
{
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.0.hash_stable(hcx, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
48
compiler/rustc_data_structures/src/vec_map/tests.rs
Normal file
48
compiler/rustc_data_structures/src/vec_map/tests.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
use super::*;
|
||||
|
||||
impl<K, V> VecMap<K, V> {
|
||||
fn into_vec(self) -> Vec<(K, V)> {
|
||||
self.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iterator() {
|
||||
assert_eq!(
|
||||
std::iter::empty().collect::<VecMap<i32, bool>>().into_vec(),
|
||||
Vec::<(i32, bool)>::new()
|
||||
);
|
||||
assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]);
|
||||
assert_eq!(
|
||||
vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
|
||||
vec![(1, true), (2, false)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iterator_owned() {
|
||||
assert_eq!(VecMap::new().into_iter().collect::<Vec<(i32, bool)>>(), Vec::<(i32, bool)>::new());
|
||||
assert_eq!(VecMap::from(vec![(1, true)]).into_iter().collect::<Vec<_>>(), vec![(1, true)]);
|
||||
assert_eq!(
|
||||
VecMap::from(vec![(1, true), (2, false)]).into_iter().collect::<Vec<_>>(),
|
||||
vec![(1, true), (2, false)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_insert() {
|
||||
let mut v = VecMap::new();
|
||||
assert_eq!(v.insert(1, true), None);
|
||||
assert_eq!(v.insert(2, false), None);
|
||||
assert_eq!(v.clone().into_vec(), vec![(1, true), (2, false)]);
|
||||
assert_eq!(v.insert(1, false), Some(true));
|
||||
assert_eq!(v.into_vec(), vec![(1, false), (2, false)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get() {
|
||||
let v = vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
|
||||
assert_eq!(v.get(&1), Some(&true));
|
||||
assert_eq!(v.get(&2), Some(&false));
|
||||
assert_eq!(v.get(&3), None);
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ use rustc_data_structures::sync::SeqCst;
|
|||
use rustc_errors::registry::{InvalidErrorCode, Registry};
|
||||
use rustc_errors::{ErrorReported, PResult};
|
||||
use rustc_feature::find_gated_cfg;
|
||||
use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend};
|
||||
use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
|
||||
use rustc_interface::{interface, Queries};
|
||||
use rustc_lint::LintStore;
|
||||
use rustc_metadata::locator;
|
||||
|
|
@ -499,7 +499,7 @@ fn make_input(
|
|||
}
|
||||
}
|
||||
|
||||
// Whether to stop or continue compilation.
|
||||
/// Whether to stop or continue compilation.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Compilation {
|
||||
Stop,
|
||||
|
|
@ -765,9 +765,16 @@ pub fn version(binary: &str, matches: &getopts::Matches) {
|
|||
println!("commit-date: {}", unw(util::commit_date_str()));
|
||||
println!("host: {}", config::host_triple());
|
||||
println!("release: {}", unw(util::release_str()));
|
||||
if cfg!(feature = "llvm") {
|
||||
get_builtin_codegen_backend(&None, "llvm")().print_version();
|
||||
}
|
||||
|
||||
let debug_flags = matches.opt_strs("Z");
|
||||
let backend_name = debug_flags.iter().find_map(|x| {
|
||||
if x.starts_with("codegen-backend=") {
|
||||
Some(&x["codegen-backends=".len()..])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
get_codegen_backend(&None, backend_name).print_version();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1039,8 +1046,8 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
|
|||
}
|
||||
|
||||
// Don't handle -W help here, because we might first load plugins.
|
||||
let r = matches.opt_strs("Z");
|
||||
if r.iter().any(|x| *x == "help") {
|
||||
let debug_flags = matches.opt_strs("Z");
|
||||
if debug_flags.iter().any(|x| *x == "help") {
|
||||
describe_debug_flags();
|
||||
return None;
|
||||
}
|
||||
|
|
@ -1060,9 +1067,14 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
|
|||
}
|
||||
|
||||
if cg_flags.iter().any(|x| *x == "passes=list") {
|
||||
if cfg!(feature = "llvm") {
|
||||
get_builtin_codegen_backend(&None, "llvm")().print_passes();
|
||||
}
|
||||
let backend_name = debug_flags.iter().find_map(|x| {
|
||||
if x.starts_with("codegen-backend=") {
|
||||
Some(&x["codegen-backends=".len()..])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
get_codegen_backend(&None, backend_name).print_passes();
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ E0308: include_str!("./error_codes/E0308.md"),
|
|||
E0309: include_str!("./error_codes/E0309.md"),
|
||||
E0310: include_str!("./error_codes/E0310.md"),
|
||||
E0312: include_str!("./error_codes/E0312.md"),
|
||||
E0316: include_str!("./error_codes/E0316.md"),
|
||||
E0317: include_str!("./error_codes/E0317.md"),
|
||||
E0321: include_str!("./error_codes/E0321.md"),
|
||||
E0322: include_str!("./error_codes/E0322.md"),
|
||||
|
|
@ -553,9 +554,8 @@ E0783: include_str!("./error_codes/E0783.md"),
|
|||
E0311, // thing may not live long enough
|
||||
E0313, // lifetime of borrowed pointer outlives lifetime of captured
|
||||
// variable
|
||||
E0314, // closure outlives stack frame
|
||||
E0315, // cannot invoke closure outside of its lifetime
|
||||
E0316, // nested quantification of lifetimes
|
||||
// E0314, // closure outlives stack frame
|
||||
// E0315, // cannot invoke closure outside of its lifetime
|
||||
// E0319, // trait impls for defaulted traits allowed just for structs/enums
|
||||
E0320, // recursive overflow during dropck
|
||||
// E0372, // coherence not object safe
|
||||
|
|
@ -584,21 +584,21 @@ E0783: include_str!("./error_codes/E0783.md"),
|
|||
// E0470, removed
|
||||
// E0471, // constant evaluation error (in pattern)
|
||||
E0472, // llvm_asm! is unsupported on this target
|
||||
E0473, // dereference of reference outside its lifetime
|
||||
E0474, // captured variable `..` does not outlive the enclosing closure
|
||||
E0475, // index of slice outside its lifetime
|
||||
// E0473, // dereference of reference outside its lifetime
|
||||
// E0474, // captured variable `..` does not outlive the enclosing closure
|
||||
// E0475, // index of slice outside its lifetime
|
||||
E0476, // lifetime of the source pointer does not outlive lifetime bound...
|
||||
E0479, // the type `..` (provided as the value of a type parameter) is...
|
||||
E0480, // lifetime of method receiver does not outlive the method call
|
||||
E0481, // lifetime of function argument does not outlive the function call
|
||||
// E0479, // the type `..` (provided as the value of a type parameter) is...
|
||||
// E0480, // lifetime of method receiver does not outlive the method call
|
||||
// E0481, // lifetime of function argument does not outlive the function call
|
||||
E0482, // lifetime of return value does not outlive the function call
|
||||
E0483, // lifetime of operand does not outlive the operation
|
||||
E0484, // reference is not valid at the time of borrow
|
||||
E0485, // automatically reference is not valid at the time of borrow
|
||||
E0486, // type of expression contains references that are not valid during..
|
||||
E0487, // unsafe use of destructor: destructor might be called while...
|
||||
E0488, // lifetime of variable does not enclose its declaration
|
||||
E0489, // type/lifetime parameter not in scope here
|
||||
// E0483, // lifetime of operand does not outlive the operation
|
||||
// E0484, // reference is not valid at the time of borrow
|
||||
// E0485, // automatically reference is not valid at the time of borrow
|
||||
// E0486, // type of expression contains references that are not valid during..
|
||||
// E0487, // unsafe use of destructor: destructor might be called while...
|
||||
// E0488, // lifetime of variable does not enclose its declaration
|
||||
// E0489, // type/lifetime parameter not in scope here
|
||||
E0490, // a value of type `..` is borrowed for too long
|
||||
E0498, // malformed plugin attribute
|
||||
E0514, // metadata version mismatch
|
||||
|
|
|
|||
32
compiler/rustc_error_codes/src/error_codes/E0316.md
Normal file
32
compiler/rustc_error_codes/src/error_codes/E0316.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
A `where` clause contains a nested quantification over lifetimes.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0316
|
||||
trait Tr<'a, 'b> {}
|
||||
|
||||
fn foo<T>(t: T)
|
||||
where
|
||||
for<'a> &'a T: for<'b> Tr<'a, 'b>, // error: nested quantification
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
Rust syntax allows lifetime quantifications in two places within
|
||||
`where` clauses: Quantifying over the trait bound only (as in
|
||||
`Ty: for<'l> Trait<'l>`) and quantifying over the whole clause
|
||||
(as in `for<'l> &'l Ty: Trait<'l>`). Using both in the same clause
|
||||
leads to a nested lifetime quantification, which is not supported.
|
||||
|
||||
The following example compiles, because the clause with the nested
|
||||
quantification has been rewritten to use only one `for<>`:
|
||||
|
||||
```
|
||||
trait Tr<'a, 'b> {}
|
||||
|
||||
fn foo<T>(t: T)
|
||||
where
|
||||
for<'a, 'b> &'a T: Tr<'a, 'b>, // ok
|
||||
{
|
||||
}
|
||||
```
|
||||
|
|
@ -16,13 +16,13 @@ fn bar(x: &i32) -> Box<dyn Debug> { // error!
|
|||
|
||||
Add `'static` requirement to fix them:
|
||||
|
||||
```compile_fail,E0759
|
||||
```
|
||||
# use std::fmt::Debug;
|
||||
fn foo(x: &i32) -> impl Debug + 'static { // ok!
|
||||
fn foo(x: &'static i32) -> impl Debug + 'static { // ok!
|
||||
x
|
||||
}
|
||||
|
||||
fn bar(x: &i32) -> Box<dyn Debug + 'static> { // ok!
|
||||
fn bar(x: &'static i32) -> Box<dyn Debug + 'static> { // ok!
|
||||
Box::new(x)
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ macro_rules! encode_fields {
|
|||
$(
|
||||
$enc.emit_struct_field(
|
||||
stringify!($name),
|
||||
idx,
|
||||
idx == 0,
|
||||
|enc| $name.encode(enc),
|
||||
)?;
|
||||
idx += 1;
|
||||
|
|
@ -229,7 +229,7 @@ macro_rules! encode_fields {
|
|||
// Special-case encoder to skip tool_metadata if not set
|
||||
impl<E: Encoder> Encodable<E> for Diagnostic {
|
||||
fn encode(&self, s: &mut E) -> Result<(), E::Error> {
|
||||
s.emit_struct("diagnostic", 7, |s| {
|
||||
s.emit_struct(false, |s| {
|
||||
let mut idx = 0;
|
||||
|
||||
idx = encode_fields!(
|
||||
|
|
|
|||
|
|
@ -715,6 +715,7 @@ impl Handler {
|
|||
self.inner.borrow_mut().bug(msg)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn err_count(&self) -> usize {
|
||||
self.inner.borrow().err_count()
|
||||
}
|
||||
|
|
@ -924,6 +925,7 @@ impl HandlerInner {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn err_count(&self) -> usize {
|
||||
self.err_count + self.stashed_diagnostics.len()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1068,11 +1068,11 @@ impl<'a> ExtCtxt<'a> {
|
|||
self.resolver.check_unused_macros();
|
||||
}
|
||||
|
||||
/// Resolves a path mentioned inside Rust code.
|
||||
/// Resolves a `path` mentioned inside Rust code, returning an absolute path.
|
||||
///
|
||||
/// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths.
|
||||
/// This unifies the logic used for resolving `include_X!`.
|
||||
///
|
||||
/// Returns an absolute path to the file that `path` refers to.
|
||||
/// FIXME: move this to `rustc_builtin_macros` and make it private.
|
||||
pub fn resolve_path(
|
||||
&self,
|
||||
path: impl Into<PathBuf>,
|
||||
|
|
|
|||
|
|
@ -275,7 +275,12 @@ impl<'a> ExtCtxt<'a> {
|
|||
) -> P<ast::Expr> {
|
||||
self.expr(
|
||||
span,
|
||||
ast::ExprKind::Struct(P(ast::StructExpr { path, fields, rest: ast::StructRest::None })),
|
||||
ast::ExprKind::Struct(P(ast::StructExpr {
|
||||
qself: None,
|
||||
path,
|
||||
fields,
|
||||
rest: ast::StructRest::None,
|
||||
})),
|
||||
)
|
||||
}
|
||||
pub fn expr_struct_ident(
|
||||
|
|
@ -405,7 +410,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
path: ast::Path,
|
||||
subpats: Vec<P<ast::Pat>>,
|
||||
) -> P<ast::Pat> {
|
||||
self.pat(span, PatKind::TupleStruct(path, subpats))
|
||||
self.pat(span, PatKind::TupleStruct(None, path, subpats))
|
||||
}
|
||||
pub fn pat_struct(
|
||||
&self,
|
||||
|
|
@ -413,7 +418,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
path: ast::Path,
|
||||
field_pats: Vec<ast::PatField>,
|
||||
) -> P<ast::Pat> {
|
||||
self.pat(span, PatKind::Struct(path, field_pats, false))
|
||||
self.pat(span, PatKind::Struct(None, path, field_pats, false))
|
||||
}
|
||||
pub fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
|
||||
self.pat(span, PatKind::Tuple(pats))
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ use rustc_ast::ptr::P;
|
|||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
||||
use rustc_ast::{AstLike, AttrItem, Block, Inline, ItemKind, LitKind, MacArgs};
|
||||
use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs};
|
||||
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
|
||||
use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::{self as attr, is_builtin_attr};
|
||||
use rustc_attr::is_builtin_attr;
|
||||
use rustc_data_structures::map_in_place::MapInPlace;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
|
@ -28,15 +28,14 @@ use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
|
|||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
use rustc_session::parse::{feature_err, ParseSess};
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::{ExpnId, FileName, Span, DUMMY_SP};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::{ExpnId, FileName, Span};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::io::ErrorKind;
|
||||
use std::ops::DerefMut;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::{iter, mem, slice};
|
||||
use std::{iter, mem};
|
||||
|
||||
macro_rules! ast_fragments {
|
||||
(
|
||||
|
|
@ -1524,139 +1523,6 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
noop_flat_map_generic_param(param, self)
|
||||
}
|
||||
|
||||
fn visit_attribute(&mut self, at: &mut ast::Attribute) {
|
||||
// turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
|
||||
// contents="file contents")]` attributes
|
||||
if !self.cx.sess.check_name(at, sym::doc) {
|
||||
return noop_visit_attribute(at, self);
|
||||
}
|
||||
|
||||
if let Some(list) = at.meta_item_list() {
|
||||
if !list.iter().any(|it| it.has_name(sym::include)) {
|
||||
return noop_visit_attribute(at, self);
|
||||
}
|
||||
|
||||
let mut items = vec![];
|
||||
|
||||
for mut it in list {
|
||||
if !it.has_name(sym::include) {
|
||||
items.push({
|
||||
noop_visit_meta_list_item(&mut it, self);
|
||||
it
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(file) = it.value_str() {
|
||||
let err_count = self.cx.sess.parse_sess.span_diagnostic.err_count();
|
||||
self.check_attributes(slice::from_ref(at));
|
||||
if self.cx.sess.parse_sess.span_diagnostic.err_count() > err_count {
|
||||
// avoid loading the file if they haven't enabled the feature
|
||||
return noop_visit_attribute(at, self);
|
||||
}
|
||||
|
||||
let filename = match self.cx.resolve_path(&*file.as_str(), it.span()) {
|
||||
Ok(filename) => filename,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match self.cx.source_map().load_file(&filename) {
|
||||
Ok(source_file) => {
|
||||
let src = source_file
|
||||
.src
|
||||
.as_ref()
|
||||
.expect("freshly loaded file should have a source");
|
||||
let src_interned = Symbol::intern(src.as_str());
|
||||
|
||||
let include_info = vec![
|
||||
ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(
|
||||
Ident::with_dummy_span(sym::file),
|
||||
file,
|
||||
DUMMY_SP,
|
||||
)),
|
||||
ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(
|
||||
Ident::with_dummy_span(sym::contents),
|
||||
src_interned,
|
||||
DUMMY_SP,
|
||||
)),
|
||||
];
|
||||
|
||||
let include_ident = Ident::with_dummy_span(sym::include);
|
||||
let item = attr::mk_list_item(include_ident, include_info);
|
||||
items.push(ast::NestedMetaItem::MetaItem(item));
|
||||
}
|
||||
Err(e) => {
|
||||
let lit_span = it.name_value_literal_span().unwrap();
|
||||
|
||||
if e.kind() == ErrorKind::InvalidData {
|
||||
self.cx
|
||||
.struct_span_err(
|
||||
lit_span,
|
||||
&format!("{} wasn't a utf-8 file", filename.display()),
|
||||
)
|
||||
.span_label(lit_span, "contains invalid utf-8")
|
||||
.emit();
|
||||
} else {
|
||||
let mut err = self.cx.struct_span_err(
|
||||
lit_span,
|
||||
&format!("couldn't read {}: {}", filename.display(), e),
|
||||
);
|
||||
err.span_label(lit_span, "couldn't read file");
|
||||
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mut err = self
|
||||
.cx
|
||||
.struct_span_err(it.span(), "expected path to external documentation");
|
||||
|
||||
// Check if the user erroneously used `doc(include(...))` syntax.
|
||||
let literal = it.meta_item_list().and_then(|list| {
|
||||
if list.len() == 1 {
|
||||
list[0].literal().map(|literal| &literal.kind)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let (path, applicability) = match &literal {
|
||||
Some(LitKind::Str(path, ..)) => {
|
||||
(path.to_string(), Applicability::MachineApplicable)
|
||||
}
|
||||
_ => (String::from("<path>"), Applicability::HasPlaceholders),
|
||||
};
|
||||
|
||||
err.span_suggestion(
|
||||
it.span(),
|
||||
"provide a file path with `=`",
|
||||
format!("include = \"{}\"", path),
|
||||
applicability,
|
||||
);
|
||||
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items);
|
||||
*at = ast::Attribute {
|
||||
kind: ast::AttrKind::Normal(
|
||||
AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span), tokens: None },
|
||||
None,
|
||||
),
|
||||
span: at.span,
|
||||
id: at.id,
|
||||
style: at.style,
|
||||
};
|
||||
} else {
|
||||
noop_visit_attribute(at, self)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_id(&mut self, id: &mut ast::NodeId) {
|
||||
if self.monotonic {
|
||||
debug_assert_eq!(*id, ast::DUMMY_NODE_ID);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#![feature(bool_to_option)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(destructuring_assignment)]
|
||||
#![feature(format_args_capture)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_internals)]
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ use smallvec::{smallvec, SmallVec};
|
|||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_span::symbol::Ident;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::mem;
|
||||
|
|
@ -615,7 +616,11 @@ fn inner_parse_loop<'root, 'tt>(
|
|||
|
||||
/// Use the given sequence of token trees (`ms`) as a matcher. Match the token
|
||||
/// stream from the given `parser` against it and return the match.
|
||||
pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> NamedParseResult {
|
||||
pub(super) fn parse_tt(
|
||||
parser: &mut Cow<'_, Parser<'_>>,
|
||||
ms: &[TokenTree],
|
||||
macro_name: Ident,
|
||||
) -> NamedParseResult {
|
||||
// A queue of possible matcher positions. We initialize it with the matcher position in which
|
||||
// the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then
|
||||
// processes all of these possible matcher positions and produces possible next positions into
|
||||
|
|
@ -711,7 +716,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
|
|||
return Error(
|
||||
parser.token.span,
|
||||
format!(
|
||||
"local ambiguity: multiple parsing options: {}",
|
||||
"local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}",
|
||||
match next_items.len() {
|
||||
0 => format!("built-in NTs {}.", nts),
|
||||
1 => format!("built-in NTs {} or 1 other option.", nts),
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ fn generic_extension<'cx>(
|
|||
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
|
||||
let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut());
|
||||
|
||||
match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) {
|
||||
match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt, name) {
|
||||
Success(named_matches) => {
|
||||
// The matcher was `Success(..)`ful.
|
||||
// Merge the gated spans from parsing the matcher with the pre-existing ones.
|
||||
|
|
@ -338,7 +338,7 @@ fn generic_extension<'cx>(
|
|||
_ => continue,
|
||||
};
|
||||
if let Success(_) =
|
||||
parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt)
|
||||
parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt, name)
|
||||
{
|
||||
if comma_span.is_dummy() {
|
||||
err.note("you might be missing a comma");
|
||||
|
|
@ -432,7 +432,7 @@ pub fn compile_declarative_macro(
|
|||
];
|
||||
|
||||
let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
|
||||
let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
|
||||
let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram, def.ident) {
|
||||
Success(m) => m,
|
||||
Failure(token, msg) => {
|
||||
let s = parse_failure_msg(&token);
|
||||
|
|
@ -467,6 +467,7 @@ pub fn compile_declarative_macro(
|
|||
&sess.parse_sess,
|
||||
def.id,
|
||||
features,
|
||||
edition,
|
||||
)
|
||||
.pop()
|
||||
.unwrap();
|
||||
|
|
@ -492,6 +493,7 @@ pub fn compile_declarative_macro(
|
|||
&sess.parse_sess,
|
||||
def.id,
|
||||
features,
|
||||
edition,
|
||||
)
|
||||
.pop()
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ use rustc_feature::Features;
|
|||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
|
||||
use rustc_span::Span;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{Span, SyntaxContext};
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
||||
|
|
@ -32,6 +33,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
|
|||
/// - `sess`: the parsing session. Any errors will be emitted to this session.
|
||||
/// - `node_id`: the NodeId of the macro we are parsing.
|
||||
/// - `features`: language features so we can do feature gating.
|
||||
/// - `edition`: the edition of the crate defining the macro
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
|
|
@ -42,6 +44,7 @@ pub(super) fn parse(
|
|||
sess: &ParseSess,
|
||||
node_id: NodeId,
|
||||
features: &Features,
|
||||
edition: Edition,
|
||||
) -> Vec<TokenTree> {
|
||||
// Will contain the final collection of `self::TokenTree`
|
||||
let mut result = Vec::new();
|
||||
|
|
@ -52,7 +55,7 @@ pub(super) fn parse(
|
|||
while let Some(tree) = trees.next() {
|
||||
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
|
||||
// parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
|
||||
let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features);
|
||||
let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features, edition);
|
||||
match tree {
|
||||
TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
|
||||
let span = match trees.next() {
|
||||
|
|
@ -64,7 +67,19 @@ pub(super) fn parse(
|
|||
|
||||
let kind =
|
||||
token::NonterminalKind::from_symbol(frag.name, || {
|
||||
span.edition()
|
||||
// FIXME(#85708) - once we properly decode a foreign
|
||||
// crate's `SyntaxContext::root`, then we can replace
|
||||
// this with just `span.edition()`. A
|
||||
// `SyntaxContext::root()` from the current crate will
|
||||
// have the edition of the current crate, and a
|
||||
// `SyntaxxContext::root()` from a foreign crate will
|
||||
// have the edition of that crate (which we manually
|
||||
// retrieve via the `edition` parameter).
|
||||
if span.ctxt() == SyntaxContext::root() {
|
||||
edition
|
||||
} else {
|
||||
span.edition()
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(
|
||||
|| {
|
||||
|
|
@ -117,6 +132,7 @@ pub(super) fn parse(
|
|||
/// - `expect_matchers`: same as for `parse` (see above).
|
||||
/// - `sess`: the parsing session. Any errors will be emitted to this session.
|
||||
/// - `features`: language features so we can do feature gating.
|
||||
/// - `edition` - the edition of the crate defining the macro
|
||||
fn parse_tree(
|
||||
tree: tokenstream::TokenTree,
|
||||
outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
|
||||
|
|
@ -124,6 +140,7 @@ fn parse_tree(
|
|||
sess: &ParseSess,
|
||||
node_id: NodeId,
|
||||
features: &Features,
|
||||
edition: Edition,
|
||||
) -> TokenTree {
|
||||
// Depending on what `tree` is, we could be parsing different parts of a macro
|
||||
match tree {
|
||||
|
|
@ -151,7 +168,7 @@ fn parse_tree(
|
|||
sess.span_diagnostic.span_err(span.entire(), &msg);
|
||||
}
|
||||
// Parse the contents of the sequence itself
|
||||
let sequence = parse(tts, expect_matchers, sess, node_id, features);
|
||||
let sequence = parse(tts, expect_matchers, sess, node_id, features, edition);
|
||||
// Get the Kleene operator and optional separator
|
||||
let (separator, kleene) =
|
||||
parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
|
||||
|
|
@ -204,7 +221,7 @@ fn parse_tree(
|
|||
span,
|
||||
Lrc::new(Delimited {
|
||||
delim,
|
||||
tts: parse(tts, expect_matchers, sess, node_id, features),
|
||||
tts: parse(tts, expect_matchers, sess, node_id, features, edition),
|
||||
}),
|
||||
),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@ declare_features! (
|
|||
(active, f16c_target_feature, "1.36.0", Some(44839), None),
|
||||
(active, riscv_target_feature, "1.45.0", Some(44839), None),
|
||||
(active, ermsb_target_feature, "1.49.0", Some(44839), None),
|
||||
(active, bpf_target_feature, "1.54.0", Some(44839), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates (target features)
|
||||
|
|
@ -370,9 +371,6 @@ declare_features! (
|
|||
/// Allows `#[doc(masked)]`.
|
||||
(active, doc_masked, "1.21.0", Some(44027), None),
|
||||
|
||||
/// Allows `#[doc(include = "some-file")]`.
|
||||
(active, external_doc, "1.22.0", Some(44732), None),
|
||||
|
||||
/// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
|
||||
(active, crate_visibility_modifier, "1.23.0", Some(53120), None),
|
||||
|
||||
|
|
@ -665,6 +663,9 @@ declare_features! (
|
|||
/// Allows unnamed fields of struct and union type
|
||||
(active, unnamed_fields, "1.53.0", Some(49804), None),
|
||||
|
||||
/// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns.
|
||||
(active, more_qualified_paths, "1.54.0", Some(80080), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -568,10 +568,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)),
|
||||
rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
|
||||
rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
|
||||
rustc_attr!(
|
||||
TEST, rustc_dirty, AssumedUsed,
|
||||
template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_clean, AssumedUsed,
|
||||
template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
|
||||
|
|
|
|||
|
|
@ -140,6 +140,10 @@ declare_features! (
|
|||
(removed, const_fn, "1.54.0", Some(57563), None,
|
||||
Some("split into finer-grained feature gates")),
|
||||
|
||||
/// Allows `#[doc(include = "some-file")]`.
|
||||
(removed, external_doc, "1.54.0", Some(44732), None,
|
||||
Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: removed features
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -94,15 +94,6 @@ impl DefPathTable {
|
|||
.iter_enumerated()
|
||||
.map(move |(index, key)| (index, key, &self.def_path_hashes[index]))
|
||||
}
|
||||
|
||||
pub fn all_def_path_hashes_and_def_ids(
|
||||
&self,
|
||||
krate: CrateNum,
|
||||
) -> impl Iterator<Item = (DefPathHash, DefId)> + '_ {
|
||||
self.def_path_hashes
|
||||
.iter_enumerated()
|
||||
.map(move |(index, hash)| (*hash, DefId { krate, index }))
|
||||
}
|
||||
}
|
||||
|
||||
/// The definition table containing node definitions.
|
||||
|
|
@ -306,6 +297,7 @@ impl Definitions {
|
|||
self.table.index_to_key.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn def_key(&self, id: LocalDefId) -> DefKey {
|
||||
self.table.def_key(id.local_def_index)
|
||||
}
|
||||
|
|
@ -439,6 +431,14 @@ impl Definitions {
|
|||
pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
|
||||
self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> {
|
||||
self.table
|
||||
.def_path_hash_to_index
|
||||
.get(&hash)
|
||||
.map(|&local_def_index| LocalDefId { local_def_index })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ignore-tidy-filelength
|
||||
use crate::def::{CtorKind, DefKind, Res};
|
||||
use crate::def_id::DefId;
|
||||
crate use crate::hir_id::HirId;
|
||||
crate use crate::hir_id::{HirId, ItemLocalId};
|
||||
use crate::{itemlikevisit, LangItem};
|
||||
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
|
|
@ -10,6 +10,7 @@ use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObject
|
|||
pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
|
||||
pub use rustc_ast::{CaptureBy, Movability, Mutability};
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
|
@ -658,7 +659,9 @@ pub struct Crate<'hir> {
|
|||
/// they are declared in the static array generated by proc_macro_harness.
|
||||
pub proc_macros: Vec<HirId>,
|
||||
|
||||
pub trait_map: BTreeMap<HirId, Vec<TraitCandidate>>,
|
||||
/// Map indicating what traits are in scope for places where this
|
||||
/// is relevant; generated by resolve.
|
||||
pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>,
|
||||
|
||||
/// Collected attributes from HIR nodes.
|
||||
pub attrs: BTreeMap<HirId, &'hir [Attribute]>,
|
||||
|
|
@ -2485,6 +2488,7 @@ pub enum FnRetTy<'hir> {
|
|||
}
|
||||
|
||||
impl FnRetTy<'_> {
|
||||
#[inline]
|
||||
pub fn span(&self) -> Span {
|
||||
match *self {
|
||||
Self::DefaultReturn(span) => span,
|
||||
|
|
|
|||
|
|
@ -3,12 +3,10 @@
|
|||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
|
||||
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(const_panic)]
|
||||
#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_step)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crate::hir::{
|
|||
TraitItem, TraitItemId, Ty, VisibilityKind,
|
||||
};
|
||||
use crate::hir_id::{HirId, ItemLocalId};
|
||||
use rustc_span::def_id::{DefPathHash, LocalDefId};
|
||||
use rustc_span::def_id::DefPathHash;
|
||||
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
|
|
@ -21,7 +21,6 @@ pub trait HashStableContext:
|
|||
fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
|
||||
fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
|
||||
fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F);
|
||||
fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash;
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
|
||||
|
|
@ -29,7 +28,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
|
|||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
|
||||
let def_path_hash = hcx.local_def_path_hash(self.owner);
|
||||
let def_path_hash = self.owner.to_stable_hash_key(hcx);
|
||||
(def_path_hash, self.local_id)
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +38,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemId {
|
|||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
|
||||
hcx.local_def_path_hash(self.def_id)
|
||||
self.def_id.to_stable_hash_key(hcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +47,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for TraitItemId {
|
|||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
|
||||
hcx.local_def_path_hash(self.def_id)
|
||||
self.def_id.to_stable_hash_key(hcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +56,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ImplItemId {
|
|||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
|
||||
hcx.local_def_path_hash(self.def_id)
|
||||
self.def_id.to_stable_hash_key(hcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +65,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ForeignItemId
|
|||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
|
||||
hcx.local_def_path_hash(self.def_id)
|
||||
self.def_id.to_stable_hash_key(hcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
//! Debugging code to test fingerprints computed for query results.
|
||||
//! For each node marked with `#[rustc_clean]` or `#[rustc_dirty]`,
|
||||
//! we will compare the fingerprint from the current and from the previous
|
||||
//! Debugging code to test fingerprints computed for query results. For each node marked with
|
||||
//! `#[rustc_clean]` we will compare the fingerprint from the current and from the previous
|
||||
//! compilation session as appropriate:
|
||||
//!
|
||||
//! - `#[rustc_clean(cfg="rev2", except="typeck")]` if we are
|
||||
|
|
@ -30,7 +29,6 @@ use std::iter::FromIterator;
|
|||
use std::vec::Vec;
|
||||
|
||||
const EXCEPT: Symbol = sym::except;
|
||||
const LABEL: Symbol = sym::label;
|
||||
const CFG: Symbol = sym::cfg;
|
||||
|
||||
// Base and Extra labels to build up the labels
|
||||
|
|
@ -101,6 +99,12 @@ const LABELS_FN_IN_TRAIT: &[&[&str]] =
|
|||
/// For generic cases like inline-assembly, modules, etc.
|
||||
const LABELS_HIR_ONLY: &[&[&str]] = &[BASE_HIR];
|
||||
|
||||
/// Impl `DepNode`s.
|
||||
const LABELS_TRAIT: &[&[&str]] = &[
|
||||
BASE_HIR,
|
||||
&[label_strs::associated_item_def_ids, label_strs::predicates_of, label_strs::generics_of],
|
||||
];
|
||||
|
||||
/// Impl `DepNode`s.
|
||||
const LABELS_IMPL: &[&[&str]] = &[BASE_HIR, BASE_IMPL];
|
||||
|
||||
|
|
@ -122,22 +126,12 @@ struct Assertion {
|
|||
dirty: Labels,
|
||||
}
|
||||
|
||||
impl Assertion {
|
||||
fn from_clean_labels(labels: Labels) -> Assertion {
|
||||
Assertion { clean: labels, dirty: Labels::default() }
|
||||
}
|
||||
|
||||
fn from_dirty_labels(labels: Labels) -> Assertion {
|
||||
Assertion { clean: Labels::default(), dirty: labels }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
|
||||
if !tcx.sess.opts.debugging_opts.query_dep_graph {
|
||||
return;
|
||||
}
|
||||
|
||||
// can't add `#[rustc_dirty]` etc without opting in to this feature
|
||||
// can't add `#[rustc_clean]` etc without opting in to this feature
|
||||
if !tcx.features().rustc_attrs {
|
||||
return;
|
||||
}
|
||||
|
|
@ -147,11 +141,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
|
|||
let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, checked_attrs: Default::default() };
|
||||
krate.visit_all_item_likes(&mut dirty_clean_visitor);
|
||||
|
||||
let mut all_attrs = FindAllAttrs {
|
||||
tcx,
|
||||
attr_names: &[sym::rustc_dirty, sym::rustc_clean],
|
||||
found_attrs: vec![],
|
||||
};
|
||||
let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
|
||||
intravisit::walk_crate(&mut all_attrs, krate);
|
||||
|
||||
// Note that we cannot use the existing "unused attribute"-infrastructure
|
||||
|
|
@ -169,37 +159,20 @@ pub struct DirtyCleanVisitor<'tcx> {
|
|||
impl DirtyCleanVisitor<'tcx> {
|
||||
/// Possibly "deserialize" the attribute into a clean/dirty assertion
|
||||
fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> {
|
||||
let is_clean = if self.tcx.sess.check_name(attr, sym::rustc_dirty) {
|
||||
false
|
||||
} else if self.tcx.sess.check_name(attr, sym::rustc_clean) {
|
||||
true
|
||||
} else {
|
||||
if !self.tcx.sess.check_name(attr, sym::rustc_clean) {
|
||||
// skip: not rustc_clean/dirty
|
||||
return None;
|
||||
};
|
||||
}
|
||||
if !check_config(self.tcx, attr) {
|
||||
// skip: not the correct `cfg=`
|
||||
return None;
|
||||
}
|
||||
let assertion = if let Some(labels) = self.labels(attr) {
|
||||
if is_clean {
|
||||
Assertion::from_clean_labels(labels)
|
||||
} else {
|
||||
Assertion::from_dirty_labels(labels)
|
||||
}
|
||||
} else {
|
||||
self.assertion_auto(item_id, attr, is_clean)
|
||||
};
|
||||
let assertion = self.assertion_auto(item_id, attr);
|
||||
Some(assertion)
|
||||
}
|
||||
|
||||
/// Gets the "auto" assertion on pre-validated attr, along with the `except` labels.
|
||||
fn assertion_auto(
|
||||
&mut self,
|
||||
item_id: LocalDefId,
|
||||
attr: &Attribute,
|
||||
is_clean: bool,
|
||||
) -> Assertion {
|
||||
fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion {
|
||||
let (name, mut auto) = self.auto_labels(item_id, attr);
|
||||
let except = self.except(attr);
|
||||
for e in except.iter() {
|
||||
|
|
@ -211,21 +184,7 @@ impl DirtyCleanVisitor<'tcx> {
|
|||
self.tcx.sess.span_fatal(attr.span, &msg);
|
||||
}
|
||||
}
|
||||
if is_clean {
|
||||
Assertion { clean: auto, dirty: except }
|
||||
} else {
|
||||
Assertion { clean: except, dirty: auto }
|
||||
}
|
||||
}
|
||||
|
||||
fn labels(&self, attr: &Attribute) -> Option<Labels> {
|
||||
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
|
||||
if item.has_name(LABEL) {
|
||||
let value = expect_associated_value(self.tcx, &item);
|
||||
return Some(self.resolve_labels(&item, value));
|
||||
}
|
||||
}
|
||||
None
|
||||
Assertion { clean: auto, dirty: except }
|
||||
}
|
||||
|
||||
/// `except=` attribute value
|
||||
|
|
@ -288,20 +247,7 @@ impl DirtyCleanVisitor<'tcx> {
|
|||
HirItem::Union(..) => ("ItemUnion", LABELS_ADT),
|
||||
|
||||
// Represents a Trait Declaration
|
||||
// FIXME(michaelwoerister): trait declaration is buggy because sometimes some of
|
||||
// the depnodes don't exist (because they legitimately didn't need to be
|
||||
// calculated)
|
||||
//
|
||||
// michaelwoerister and vitiral came up with a possible solution,
|
||||
// to just do this before every query
|
||||
// ```
|
||||
// ::rustc_middle::ty::query::plumbing::force_from_dep_node(tcx, dep_node)
|
||||
// ```
|
||||
//
|
||||
// However, this did not seem to work effectively and more bugs were hit.
|
||||
// Nebie @vitiral gave up :)
|
||||
//
|
||||
//HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT),
|
||||
HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT),
|
||||
|
||||
// An implementation, eg `impl<A> Trait for Foo { .. }`
|
||||
HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL),
|
||||
|
|
@ -434,33 +380,21 @@ impl ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
|
||||
/// for a `cfg="foo"` attribute and check whether we have a cfg
|
||||
/// flag called `foo`.
|
||||
///
|
||||
/// Also make sure that the `label` and `except` fields do not
|
||||
/// both exist.
|
||||
/// Given a `#[rustc_clean]` attribute, scan for a `cfg="foo"` attribute and check whether we have
|
||||
/// a cfg flag called `foo`.
|
||||
fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
|
||||
debug!("check_config(attr={:?})", attr);
|
||||
let config = &tcx.sess.parse_sess.config;
|
||||
debug!("check_config: config={:?}", config);
|
||||
let (mut cfg, mut except, mut label) = (None, false, false);
|
||||
let mut cfg = None;
|
||||
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
|
||||
if item.has_name(CFG) {
|
||||
let value = expect_associated_value(tcx, &item);
|
||||
debug!("check_config: searching for cfg {:?}", value);
|
||||
cfg = Some(config.contains(&(value, None)));
|
||||
} else if !item.has_name(EXCEPT) {
|
||||
tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty()));
|
||||
}
|
||||
if item.has_name(LABEL) {
|
||||
label = true;
|
||||
}
|
||||
if item.has_name(EXCEPT) {
|
||||
except = true;
|
||||
}
|
||||
}
|
||||
|
||||
if label && except {
|
||||
tcx.sess.span_fatal(attr.span, "must specify only one of: `label`, `except`");
|
||||
}
|
||||
|
||||
match cfg {
|
||||
|
|
@ -483,21 +417,18 @@ fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
// A visitor that collects all #[rustc_dirty]/#[rustc_clean] attributes from
|
||||
// A visitor that collects all #[rustc_clean] attributes from
|
||||
// the HIR. It is used to verify that we really ran checks for all annotated
|
||||
// nodes.
|
||||
pub struct FindAllAttrs<'a, 'tcx> {
|
||||
pub struct FindAllAttrs<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
attr_names: &'a [Symbol],
|
||||
found_attrs: Vec<&'tcx Attribute>,
|
||||
}
|
||||
|
||||
impl FindAllAttrs<'_, 'tcx> {
|
||||
impl FindAllAttrs<'tcx> {
|
||||
fn is_active_attr(&mut self, attr: &Attribute) -> bool {
|
||||
for attr_name in self.attr_names {
|
||||
if self.tcx.sess.check_name(attr, *attr_name) && check_config(self.tcx, attr) {
|
||||
return true;
|
||||
}
|
||||
if self.tcx.sess.check_name(attr, sym::rustc_clean) && check_config(self.tcx, attr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
|
|
@ -506,17 +437,14 @@ impl FindAllAttrs<'_, 'tcx> {
|
|||
fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet<ast::AttrId>) {
|
||||
for attr in &self.found_attrs {
|
||||
if !checked_attrs.contains(&attr.id) {
|
||||
self.tcx.sess.span_err(
|
||||
attr.span,
|
||||
"found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute",
|
||||
);
|
||||
self.tcx.sess.span_err(attr.span, "found unchecked `#[rustc_clean]` attribute");
|
||||
checked_attrs.insert(attr.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl intravisit::Visitor<'tcx> for FindAllAttrs<'_, 'tcx> {
|
||||
impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
//! Code to save/load the dep-graph from files.
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::definitions::DefPathTable;
|
||||
use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::query::OnDiskCache;
|
||||
use rustc_serialize::opaque::Decoder;
|
||||
|
|
@ -196,10 +195,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
|
|||
/// If we are not in incremental compilation mode, returns `None`.
|
||||
/// Otherwise, tries to load the query result cache from disk,
|
||||
/// creating an empty cache if it could not be loaded.
|
||||
pub fn load_query_result_cache<'a>(
|
||||
sess: &'a Session,
|
||||
def_path_table: &DefPathTable,
|
||||
) -> Option<OnDiskCache<'a>> {
|
||||
pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option<OnDiskCache<'a>> {
|
||||
if sess.opts.incremental.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -212,7 +208,7 @@ pub fn load_query_result_cache<'a>(
|
|||
sess.is_nightly_build(),
|
||||
) {
|
||||
LoadResult::Ok { data: (bytes, start_pos) } => {
|
||||
Some(OnDiskCache::new(sess, bytes, start_pos, def_path_table))
|
||||
Some(OnDiskCache::new(sess, bytes, start_pos))
|
||||
}
|
||||
_ => Some(OnDiskCache::new_empty(sess.source_map())),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ pub fn build_dep_graph(
|
|||
}
|
||||
|
||||
Some(DepGraph::new(
|
||||
&sess.prof,
|
||||
prev_graph,
|
||||
prev_work_products,
|
||||
encoder,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
#![feature(allow_internal_unstable)]
|
||||
#![feature(bench_black_box)]
|
||||
#![feature(const_panic)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(test)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(trusted_step)]
|
||||
|
||||
pub mod bit_set;
|
||||
pub mod vec;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ impl Idx for u32 {
|
|||
/// `u32::MAX`. You can also customize things like the `Debug` impl,
|
||||
/// what traits are derived, and so forth via the macro.
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable(step_trait, rustc_attrs)]
|
||||
#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)]
|
||||
macro_rules! newtype_index {
|
||||
// ---- public rules ----
|
||||
|
||||
|
|
|
|||
|
|
@ -660,7 +660,12 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
|
||||
fn push_outlives(
|
||||
&mut self,
|
||||
sup: ty::Region<'tcx>,
|
||||
sub: ty::Region<'tcx>,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
) {
|
||||
self.obligations.push(Obligation {
|
||||
cause: self.cause.clone(),
|
||||
param_env: self.param_env,
|
||||
|
|
|
|||
|
|
@ -371,9 +371,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
match dir {
|
||||
EqTo => self.equate(a_is_expected).relate(a_ty, b_ty),
|
||||
SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty),
|
||||
SupertypeOf => {
|
||||
self.sub(a_is_expected).relate_with_variance(ty::Contravariant, a_ty, b_ty)
|
||||
}
|
||||
SupertypeOf => self.sub(a_is_expected).relate_with_variance(
|
||||
ty::Contravariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
a_ty,
|
||||
b_ty,
|
||||
),
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
|
|
@ -574,6 +577,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
|
@ -737,7 +741,12 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||
if self.tcx().lazy_normalization() =>
|
||||
{
|
||||
assert_eq!(promoted, None);
|
||||
let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?;
|
||||
let substs = self.relate_with_variance(
|
||||
ty::Variance::Invariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
substs,
|
||||
substs,
|
||||
)?;
|
||||
Ok(self.tcx().mk_const(ty::Const {
|
||||
ty: c.ty,
|
||||
val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
|
||||
|
|
@ -831,6 +840,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
|
|||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
_variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
|
@ -965,7 +975,12 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
|
|||
if self.tcx().lazy_normalization() =>
|
||||
{
|
||||
assert_eq!(promoted, None);
|
||||
let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?;
|
||||
let substs = self.relate_with_variance(
|
||||
ty::Variance::Invariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
substs,
|
||||
substs,
|
||||
)?;
|
||||
Ok(self.tcx().mk_const(ty::Const {
|
||||
ty: c.ty,
|
||||
val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
|
|||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
_: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{Item, ItemKind, Node};
|
||||
use rustc_middle::dep_graph::DepContext;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::{
|
||||
self,
|
||||
|
|
@ -524,7 +525,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
|
||||
Ok(vec![self.tcx.original_crate_name(cnum).to_string()])
|
||||
Ok(vec![self.tcx.crate_name(cnum).to_string()])
|
||||
}
|
||||
fn path_qualified(
|
||||
self,
|
||||
|
|
@ -1965,7 +1966,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
|
||||
}
|
||||
FailureCode::Error0308(failure_str) => {
|
||||
struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
|
||||
if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
|
||||
trace.values
|
||||
{
|
||||
// If a tuple of length one was expected and the found expression has
|
||||
// parentheses around it, perhaps the user meant to write `(expr,)` to
|
||||
// build a tuple (issue #86100)
|
||||
match (expected.kind(), found.kind()) {
|
||||
(ty::Tuple(_), ty::Tuple(_)) => {}
|
||||
(ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
|
||||
if let Some(code) =
|
||||
code.strip_prefix('(').and_then(|s| s.strip_suffix(')'))
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"use a trailing comma to create a tuple with one element",
|
||||
format!("({},)", code),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
err
|
||||
}
|
||||
FailureCode::Error0644(failure_str) => {
|
||||
struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> {
|
|||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
|
@ -96,7 +97,7 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> {
|
|||
// When higher-ranked types are involved, computing the LUB is
|
||||
// very challenging, switch to invariance. This is obviously
|
||||
// overly conservative but works ok in practice.
|
||||
self.relate_with_variance(ty::Variance::Invariant, a, b)?;
|
||||
self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
|
|||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
|
@ -96,7 +97,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
|
|||
// When higher-ranked types are involved, computing the LUB is
|
||||
// very challenging, switch to invariance. This is obviously
|
||||
// overly conservative but works ok in practice.
|
||||
self.relate_with_variance(ty::Variance::Invariant, a, b)?;
|
||||
self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ where
|
|||
/// - Bivariant means that it doesn't matter.
|
||||
ambient_variance: ty::Variance,
|
||||
|
||||
ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
|
||||
|
||||
/// When we pass through a set of binders (e.g., when looking into
|
||||
/// a `fn` type), we push a new bound region scope onto here. This
|
||||
/// will contain the instantiated region for each region in those
|
||||
|
|
@ -78,7 +80,12 @@ pub trait TypeRelatingDelegate<'tcx> {
|
|||
/// satisfied for the two types to be related. `sub` and `sup` may
|
||||
/// be regions from the type or new variables created through the
|
||||
/// delegate.
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
|
||||
fn push_outlives(
|
||||
&mut self,
|
||||
sup: ty::Region<'tcx>,
|
||||
sub: ty::Region<'tcx>,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
);
|
||||
|
||||
fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
|
||||
|
||||
|
|
@ -138,7 +145,14 @@ where
|
|||
delegate: D,
|
||||
ambient_variance: ty::Variance,
|
||||
) -> Self {
|
||||
Self { infcx, delegate, ambient_variance, a_scopes: vec![], b_scopes: vec![] }
|
||||
Self {
|
||||
infcx,
|
||||
delegate,
|
||||
ambient_variance,
|
||||
ambient_variance_info: ty::VarianceDiagInfo::default(),
|
||||
a_scopes: vec![],
|
||||
b_scopes: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn ambient_covariance(&self) -> bool {
|
||||
|
|
@ -239,10 +253,15 @@ where
|
|||
|
||||
/// Push a new outlives requirement into our output set of
|
||||
/// constraints.
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
|
||||
fn push_outlives(
|
||||
&mut self,
|
||||
sup: ty::Region<'tcx>,
|
||||
sub: ty::Region<'tcx>,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
) {
|
||||
debug!("push_outlives({:?}: {:?})", sup, sub);
|
||||
|
||||
self.delegate.push_outlives(sup, sub);
|
||||
self.delegate.push_outlives(sup, sub, info);
|
||||
}
|
||||
|
||||
/// Relate a projection type and some value type lazily. This will always
|
||||
|
|
@ -490,6 +509,7 @@ where
|
|||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
|
@ -497,6 +517,7 @@ where
|
|||
|
||||
let old_ambient_variance = self.ambient_variance;
|
||||
self.ambient_variance = self.ambient_variance.xform(variance);
|
||||
self.ambient_variance_info = self.ambient_variance_info.clone().xform(info);
|
||||
|
||||
debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance);
|
||||
|
||||
|
|
@ -574,12 +595,12 @@ where
|
|||
|
||||
if self.ambient_covariance() {
|
||||
// Covariance: a <= b. Hence, `b: a`.
|
||||
self.push_outlives(v_b, v_a);
|
||||
self.push_outlives(v_b, v_a, self.ambient_variance_info.clone());
|
||||
}
|
||||
|
||||
if self.ambient_contravariance() {
|
||||
// Contravariant: b <= a. Hence, `a: b`.
|
||||
self.push_outlives(v_a, v_b);
|
||||
self.push_outlives(v_a, v_b, self.ambient_variance_info.clone());
|
||||
}
|
||||
|
||||
Ok(a)
|
||||
|
|
@ -835,6 +856,7 @@ where
|
|||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
|
|||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
|
|
|
|||
|
|
@ -16,14 +16,12 @@
|
|||
#![feature(bool_to_option)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(const_panic)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(never_type)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_step)]
|
||||
#![recursion_limit = "512"] // For rustdoc
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
#![feature(bool_to_option)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(internal_output_capture)]
|
||||
#![feature(nll)]
|
||||
#![feature(generator_trait)]
|
||||
#![feature(generators)]
|
||||
#![feature(once_cell)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ use rustc_ast::mut_visit::MutVisitor;
|
|||
use rustc_ast::{self as ast, visit};
|
||||
use rustc_codegen_ssa::back::link::emit_metadata;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::parallel;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
|
||||
use rustc_errors::{ErrorReported, PResult};
|
||||
use rustc_expand::base::ExtCtxt;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
|
|
@ -47,7 +47,9 @@ use std::cell::RefCell;
|
|||
use std::ffi::OsString;
|
||||
use std::io::{self, BufWriter, Write};
|
||||
use std::lazy::SyncLazy;
|
||||
use std::marker::PhantomPinned;
|
||||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::{env, fs, iter};
|
||||
|
||||
|
|
@ -85,11 +87,83 @@ fn count_nodes(krate: &ast::Crate) -> usize {
|
|||
counter.count
|
||||
}
|
||||
|
||||
declare_box_region_type!(
|
||||
pub BoxedResolver,
|
||||
for(),
|
||||
(&mut Resolver<'_>) -> (Result<ast::Crate>, ResolverOutputs)
|
||||
);
|
||||
pub use boxed_resolver::BoxedResolver;
|
||||
mod boxed_resolver {
|
||||
use super::*;
|
||||
|
||||
pub struct BoxedResolver(Pin<Box<BoxedResolverInner>>);
|
||||
|
||||
struct BoxedResolverInner {
|
||||
session: Lrc<Session>,
|
||||
resolver_arenas: Option<ResolverArenas<'static>>,
|
||||
resolver: Option<Resolver<'static>>,
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
// Note: Drop order is important to prevent dangling references. Resolver must be dropped first,
|
||||
// then resolver_arenas and finally session.
|
||||
impl Drop for BoxedResolverInner {
|
||||
fn drop(&mut self) {
|
||||
self.resolver.take();
|
||||
self.resolver_arenas.take();
|
||||
}
|
||||
}
|
||||
|
||||
impl BoxedResolver {
|
||||
pub(super) fn new<F>(session: Lrc<Session>, make_resolver: F) -> Result<(ast::Crate, Self)>
|
||||
where
|
||||
F: for<'a> FnOnce(
|
||||
&'a Session,
|
||||
&'a ResolverArenas<'a>,
|
||||
) -> Result<(ast::Crate, Resolver<'a>)>,
|
||||
{
|
||||
let mut boxed_resolver = Box::new(BoxedResolverInner {
|
||||
session,
|
||||
resolver_arenas: Some(Resolver::arenas()),
|
||||
resolver: None,
|
||||
_pin: PhantomPinned,
|
||||
});
|
||||
// SAFETY: `make_resolver` takes a resolver arena with an arbitrary lifetime and
|
||||
// returns a resolver with the same lifetime as the arena. We ensure that the arena
|
||||
// outlives the resolver in the drop impl and elsewhere so these transmutes are sound.
|
||||
unsafe {
|
||||
let (crate_, resolver) = make_resolver(
|
||||
std::mem::transmute::<&Session, &Session>(&boxed_resolver.session),
|
||||
std::mem::transmute::<&ResolverArenas<'_>, &ResolverArenas<'_>>(
|
||||
boxed_resolver.resolver_arenas.as_ref().unwrap(),
|
||||
),
|
||||
)?;
|
||||
boxed_resolver.resolver = Some(resolver);
|
||||
Ok((crate_, BoxedResolver(Pin::new_unchecked(boxed_resolver))))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn access<F: for<'a> FnOnce(&mut Resolver<'a>) -> R, R>(&mut self, f: F) -> R {
|
||||
// SAFETY: The resolver doesn't need to be pinned.
|
||||
let mut resolver = unsafe {
|
||||
self.0.as_mut().map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver)
|
||||
};
|
||||
f((&mut *resolver).as_mut().unwrap())
|
||||
}
|
||||
|
||||
pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs {
|
||||
match Rc::try_unwrap(resolver) {
|
||||
Ok(resolver) => {
|
||||
let mut resolver = resolver.into_inner();
|
||||
// SAFETY: The resolver doesn't need to be pinned.
|
||||
let mut resolver = unsafe {
|
||||
resolver
|
||||
.0
|
||||
.as_mut()
|
||||
.map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver)
|
||||
};
|
||||
resolver.take().unwrap().into_outputs()
|
||||
}
|
||||
Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
|
||||
/// syntax expansion, secondary `cfg` expansion, synthesis of a test
|
||||
|
|
@ -111,41 +185,16 @@ pub fn configure_and_expand(
|
|||
// its contents but the results of name resolution on those contents. Hopefully we'll push
|
||||
// this back at some point.
|
||||
let crate_name = crate_name.to_string();
|
||||
let (result, resolver) = BoxedResolver::new(static move |mut action| {
|
||||
let _ = action;
|
||||
let sess = &*sess;
|
||||
let resolver_arenas = Resolver::arenas();
|
||||
let res = configure_and_expand_inner(
|
||||
BoxedResolver::new(sess, move |sess, resolver_arenas| {
|
||||
configure_and_expand_inner(
|
||||
sess,
|
||||
&lint_store,
|
||||
krate,
|
||||
&crate_name,
|
||||
&resolver_arenas,
|
||||
&*metadata_loader,
|
||||
);
|
||||
let mut resolver = match res {
|
||||
Err(v) => {
|
||||
yield BoxedResolver::initial_yield(Err(v));
|
||||
panic!()
|
||||
}
|
||||
Ok((krate, resolver)) => {
|
||||
action = yield BoxedResolver::initial_yield(Ok(krate));
|
||||
resolver
|
||||
}
|
||||
};
|
||||
box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver), action);
|
||||
resolver.into_outputs()
|
||||
});
|
||||
result.map(|k| (k, resolver))
|
||||
}
|
||||
|
||||
impl BoxedResolver {
|
||||
pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs {
|
||||
match Rc::try_unwrap(resolver) {
|
||||
Ok(resolver) => resolver.into_inner().complete(),
|
||||
Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()),
|
||||
}
|
||||
}
|
||||
metadata_loader,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn register_plugins<'a>(
|
||||
|
|
@ -231,11 +280,11 @@ fn pre_expansion_lint(
|
|||
|
||||
fn configure_and_expand_inner<'a>(
|
||||
sess: &'a Session,
|
||||
lint_store: &'a LintStore,
|
||||
lint_store: &LintStore,
|
||||
mut krate: ast::Crate,
|
||||
crate_name: &str,
|
||||
resolver_arenas: &'a ResolverArenas<'a>,
|
||||
metadata_loader: &'a MetadataLoaderDyn,
|
||||
metadata_loader: Box<MetadataLoaderDyn>,
|
||||
) -> Result<(ast::Crate, Resolver<'a>)> {
|
||||
tracing::trace!("configure_and_expand_inner");
|
||||
pre_expansion_lint(sess, lint_store, &krate, crate_name);
|
||||
|
|
@ -765,9 +814,7 @@ pub fn create_global_ctxt<'tcx>(
|
|||
) -> QueryContext<'tcx> {
|
||||
let sess = &compiler.session();
|
||||
|
||||
let def_path_table = resolver_outputs.definitions.def_path_table();
|
||||
let query_result_on_disk_cache =
|
||||
rustc_incremental::load_query_result_cache(sess, def_path_table);
|
||||
let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
|
||||
|
||||
let codegen_backend = compiler.codegen_backend();
|
||||
let mut local_providers = *DEFAULT_QUERY_PROVIDERS;
|
||||
|
|
@ -795,7 +842,7 @@ pub fn create_global_ctxt<'tcx>(
|
|||
query_result_on_disk_cache,
|
||||
queries.as_dyn(),
|
||||
&crate_name,
|
||||
&outputs,
|
||||
outputs,
|
||||
)
|
||||
})
|
||||
});
|
||||
|
|
@ -981,7 +1028,7 @@ fn encode_and_write_metadata(
|
|||
.tempdir_in(out_filename.parent().unwrap())
|
||||
.unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
|
||||
let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
|
||||
let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir);
|
||||
let metadata_filename = emit_metadata(tcx.sess, &metadata.raw_data, &metadata_tmpdir);
|
||||
if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) {
|
||||
tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,8 +245,7 @@ impl<'tcx> Queries<'tcx> {
|
|||
self.prepare_outputs.compute(|| {
|
||||
let expansion_result = self.expansion()?;
|
||||
let (krate, boxed_resolver, _) = &*expansion_result.peek();
|
||||
let crate_name = self.crate_name()?;
|
||||
let crate_name = crate_name.peek();
|
||||
let crate_name = self.crate_name()?.peek();
|
||||
passes::prepare_outputs(
|
||||
self.session(),
|
||||
self.compiler,
|
||||
|
|
@ -343,32 +342,36 @@ impl<'tcx> Queries<'tcx> {
|
|||
}
|
||||
|
||||
pub fn linker(&'tcx self) -> Result<Linker> {
|
||||
let dep_graph = self.dep_graph()?;
|
||||
let prepare_outputs = self.prepare_outputs()?;
|
||||
let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
|
||||
let ongoing_codegen = self.ongoing_codegen()?;
|
||||
|
||||
let sess = self.session().clone();
|
||||
let codegen_backend = self.codegen_backend().clone();
|
||||
|
||||
let dep_graph = self.dep_graph()?.peek().clone();
|
||||
let prepare_outputs = self.prepare_outputs()?.take();
|
||||
let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
|
||||
let ongoing_codegen = self.ongoing_codegen()?.take();
|
||||
|
||||
Ok(Linker {
|
||||
sess,
|
||||
dep_graph: dep_graph.peek().clone(),
|
||||
prepare_outputs: prepare_outputs.take(),
|
||||
crate_hash,
|
||||
ongoing_codegen: ongoing_codegen.take(),
|
||||
codegen_backend,
|
||||
|
||||
dep_graph,
|
||||
prepare_outputs,
|
||||
crate_hash,
|
||||
ongoing_codegen,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Linker {
|
||||
// compilation inputs
|
||||
sess: Lrc<Session>,
|
||||
codegen_backend: Lrc<Box<dyn CodegenBackend>>,
|
||||
|
||||
// compilation outputs
|
||||
dep_graph: DepGraph,
|
||||
prepare_outputs: OutputFilenames,
|
||||
crate_hash: Svh,
|
||||
ongoing_codegen: Box<dyn Any>,
|
||||
codegen_backend: Lrc<Box<dyn CodegenBackend>>,
|
||||
}
|
||||
|
||||
impl Linker {
|
||||
|
|
|
|||
|
|
@ -252,7 +252,8 @@ fn test_lints_tracking_hash_different_construction_order() {
|
|||
(String::from("d"), Level::Forbid),
|
||||
];
|
||||
|
||||
assert_same_hash(&v1, &v2);
|
||||
// The hash should be order-dependent
|
||||
assert_different_hash(&v1, &v2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -491,9 +492,10 @@ fn test_native_libs_tracking_hash_different_order() {
|
|||
},
|
||||
];
|
||||
|
||||
assert_same_hash(&v1, &v2);
|
||||
assert_same_hash(&v1, &v3);
|
||||
assert_same_hash(&v2, &v3);
|
||||
// The hash should be order-dependent
|
||||
assert_different_hash(&v1, &v2);
|
||||
assert_different_hash(&v1, &v3);
|
||||
assert_different_hash(&v2, &v3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ use std::ops::DerefMut;
|
|||
use std::panic;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex, Once};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use tracing::info;
|
||||
|
||||
|
|
@ -76,7 +76,10 @@ pub fn create_session(
|
|||
let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
|
||||
make_codegen_backend(&sopts)
|
||||
} else {
|
||||
get_codegen_backend(&sopts)
|
||||
get_codegen_backend(
|
||||
&sopts.maybe_sysroot,
|
||||
sopts.debugging_opts.codegen_backend.as_ref().map(|name| &name[..]),
|
||||
)
|
||||
};
|
||||
|
||||
// target_override is documented to be called before init(), so this is okay
|
||||
|
|
@ -244,35 +247,34 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> {
|
||||
static INIT: Once = Once::new();
|
||||
/// Get the codegen backend based on the name and specified sysroot.
|
||||
///
|
||||
/// A name of `None` indicates that the default backend should be used.
|
||||
pub fn get_codegen_backend(
|
||||
maybe_sysroot: &Option<PathBuf>,
|
||||
backend_name: Option<&str>,
|
||||
) -> Box<dyn CodegenBackend> {
|
||||
static LOAD: SyncOnceCell<unsafe fn() -> Box<dyn CodegenBackend>> = SyncOnceCell::new();
|
||||
|
||||
static mut LOAD: fn() -> Box<dyn CodegenBackend> = || unreachable!();
|
||||
|
||||
INIT.call_once(|| {
|
||||
let load = LOAD.get_or_init(|| {
|
||||
#[cfg(feature = "llvm")]
|
||||
const DEFAULT_CODEGEN_BACKEND: &str = "llvm";
|
||||
|
||||
#[cfg(not(feature = "llvm"))]
|
||||
const DEFAULT_CODEGEN_BACKEND: &str = "cranelift";
|
||||
|
||||
let codegen_name = sopts
|
||||
.debugging_opts
|
||||
.codegen_backend
|
||||
.as_ref()
|
||||
.map(|name| &name[..])
|
||||
.unwrap_or(DEFAULT_CODEGEN_BACKEND);
|
||||
|
||||
let backend = match codegen_name {
|
||||
match backend_name.unwrap_or(DEFAULT_CODEGEN_BACKEND) {
|
||||
filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
|
||||
codegen_name => get_builtin_codegen_backend(&sopts.maybe_sysroot, codegen_name),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
LOAD = backend;
|
||||
#[cfg(feature = "llvm")]
|
||||
"llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
|
||||
backend_name => get_codegen_sysroot(maybe_sysroot, backend_name),
|
||||
}
|
||||
});
|
||||
unsafe { LOAD() }
|
||||
|
||||
// SAFETY: In case of a builtin codegen backend this is safe. In case of an external codegen
|
||||
// backend we hope that the backend links against the same rustc_driver version. If this is not
|
||||
// the case, we get UB.
|
||||
unsafe { load() }
|
||||
}
|
||||
|
||||
// This is used for rustdoc, but it uses similar machinery to codegen backend
|
||||
|
|
@ -390,17 +392,6 @@ fn sysroot_candidates() -> Vec<PathBuf> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_builtin_codegen_backend(
|
||||
maybe_sysroot: &Option<PathBuf>,
|
||||
backend_name: &str,
|
||||
) -> fn() -> Box<dyn CodegenBackend> {
|
||||
match backend_name {
|
||||
#[cfg(feature = "llvm")]
|
||||
"llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
|
||||
_ => get_codegen_sysroot(maybe_sysroot, backend_name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_codegen_sysroot(
|
||||
maybe_sysroot: &Option<PathBuf>,
|
||||
backend_name: &str,
|
||||
|
|
|
|||
|
|
@ -489,7 +489,7 @@ fn has_doc(sess: &Session, attr: &ast::Attribute) -> bool {
|
|||
|
||||
if let Some(list) = attr.meta_item_list() {
|
||||
for meta in list {
|
||||
if meta.has_name(sym::include) || meta.has_name(sym::hidden) {
|
||||
if meta.has_name(sym::hidden) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -334,8 +334,14 @@ impl LintStore {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks the validity of lint names derived from the command line
|
||||
pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) {
|
||||
/// Checks the validity of lint names derived from the command line. Returns
|
||||
/// true if the lint is valid, false otherwise.
|
||||
pub fn check_lint_name_cmdline(
|
||||
&self,
|
||||
sess: &Session,
|
||||
lint_name: &str,
|
||||
level: Option<Level>,
|
||||
) -> bool {
|
||||
let db = match self.check_lint_name(lint_name, None) {
|
||||
CheckLintNameResult::Ok(_) => None,
|
||||
CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
|
||||
|
|
@ -361,18 +367,23 @@ impl LintStore {
|
|||
};
|
||||
|
||||
if let Some(mut db) = db {
|
||||
let msg = format!(
|
||||
"requested on the command line with `{} {}`",
|
||||
match level {
|
||||
Level::Allow => "-A",
|
||||
Level::Warn => "-W",
|
||||
Level::Deny => "-D",
|
||||
Level::Forbid => "-F",
|
||||
},
|
||||
lint_name
|
||||
);
|
||||
db.note(&msg);
|
||||
if let Some(level) = level {
|
||||
let msg = format!(
|
||||
"requested on the command line with `{} {}`",
|
||||
match level {
|
||||
Level::Allow => "-A",
|
||||
Level::Warn => "-W",
|
||||
Level::Deny => "-D",
|
||||
Level::Forbid => "-F",
|
||||
},
|
||||
lint_name
|
||||
);
|
||||
db.note(&msg);
|
||||
}
|
||||
db.emit();
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -922,7 +933,7 @@ impl<'tcx> LateContext<'tcx> {
|
|||
}
|
||||
|
||||
fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
|
||||
Ok(vec![self.tcx.original_crate_name(cnum)])
|
||||
Ok(vec![self.tcx.crate_name(cnum)])
|
||||
}
|
||||
|
||||
fn path_qualified(
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ impl<'s> LintLevelsBuilder<'s> {
|
|||
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
|
||||
|
||||
for &(ref lint_name, level) in &sess.opts.lint_opts {
|
||||
store.check_lint_name_cmdline(sess, &lint_name, level);
|
||||
store.check_lint_name_cmdline(sess, &lint_name, Some(level));
|
||||
let orig_level = level;
|
||||
|
||||
// If the cap is less than this specified level, e.g., if we've got
|
||||
|
|
@ -109,6 +109,16 @@ impl<'s> LintLevelsBuilder<'s> {
|
|||
}
|
||||
}
|
||||
|
||||
for lint_name in &sess.opts.force_warns {
|
||||
let valid = store.check_lint_name_cmdline(sess, lint_name, None);
|
||||
if valid {
|
||||
let lints = store
|
||||
.find_lints(lint_name)
|
||||
.unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids"));
|
||||
self.sets.force_warns.extend(&lints);
|
||||
}
|
||||
}
|
||||
|
||||
self.sets.list.push(LintSet::CommandLine { specs });
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +152,9 @@ impl<'s> LintLevelsBuilder<'s> {
|
|||
LintLevelSource::Default => false,
|
||||
LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol),
|
||||
LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
|
||||
LintLevelSource::ForceWarn(_symbol) => {
|
||||
bug!("forced warn lint returned a forbid lint level")
|
||||
}
|
||||
};
|
||||
debug!(
|
||||
"fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
|
||||
|
|
@ -166,6 +179,7 @@ impl<'s> LintLevelsBuilder<'s> {
|
|||
LintLevelSource::CommandLine(_, _) => {
|
||||
diag_builder.note("`forbid` lint level was set on command line");
|
||||
}
|
||||
_ => bug!("forced warn lint returned a forbid lint level"),
|
||||
}
|
||||
diag_builder.emit();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,8 +36,6 @@
|
|||
#![feature(iter_zip)]
|
||||
#![feature(never_type)]
|
||||
#![feature(nll)]
|
||||
#![feature(half_open_range_patterns)]
|
||||
#![feature(exclusive_range_pattern)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue