mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-24 07:44:10 +00:00
Auto merge of #73528 - Manishearth:rollup-7djz8nd, r=Manishearth
Rollup of 16 pull requests Successful merges: - #71420 (Specialization is unsound) - #71899 (Refactor `try_find` a little) - #72689 (add str to common types) - #72791 (update coerce docs and unify relevant tests) - #72934 (forbid mutable references in all constant contexts except for const-fns) - #73027 (Make `need_type_info_err` more conservative) - #73347 (Diagnose use of incompatible sanitizers) - #73359 (shim.rs: avoid creating `Call` terminators calling `Self`) - #73399 (Clean up E0668 explanation) - #73436 (Clean up E0670 explanation) - #73440 (Add src/librustdoc as an alias for src/tools/rustdoc) - #73442 (pretty/mir: const value enums with no variants) - #73452 (Unify region variables when projecting associated types) - #73458 (Use alloc::Layout in DroplessArena API) - #73484 (Update the doc for std::prelude to the correct behavior) - #73506 (Bump Rustfmt and RLS) Failed merges: r? @ghost
This commit is contained in:
commit
033013cab3
142
Cargo.lock
142
Cargo.lock
@ -2780,9 +2780,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "racer"
|
||||
version = "2.1.34"
|
||||
version = "2.1.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc9caecf1286a3ed28d3ae35207a178ba12e58de95540781e5c6cba05e0f0833"
|
||||
checksum = "421174f19211ba9e5fda34aa0cbc292188aae8e0cfbff4aebbae23f1a416bfb3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap",
|
||||
@ -3207,43 +3207,38 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-arena"
|
||||
version = "659.0.0"
|
||||
name = "rustc-ap-rustc_arena"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdaf0295fc40b10ec1091aad1a1760b4bb3b4e7c4f77d543d1a2e9d50a01e6b1"
|
||||
checksum = "0c6683b49209f8b132bec33dc6b6c8f9958c8c94eb3586d4cb495e092b61c1da"
|
||||
dependencies = [
|
||||
"rustc-ap-rustc_data_structures",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-graphviz"
|
||||
version = "659.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8028e8cdb4eb71810d0c22a5a5e1e3106c81123be63ce7f044b6d4ac100d8941"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_ast"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16e9e502bb3a5568433db1cf2fb1f1e1074934636069cf744ad7c77b58e1428e"
|
||||
checksum = "5b21784d92fb2d584800f528866f00fe814f73abda794f406bfd1fbb2f1ca7f7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"log",
|
||||
"rustc-ap-rustc_data_structures",
|
||||
"rustc-ap-rustc_index",
|
||||
"rustc-ap-rustc_lexer",
|
||||
"rustc-ap-rustc_macros",
|
||||
"rustc-ap-rustc_serialize",
|
||||
"rustc-ap-rustc_span",
|
||||
"rustc-ap-serialize",
|
||||
"scoped-tls",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_ast_passes"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faf35ffecab28f97f7ac01cf6a13afaca6408529d15eb95f317a43b2ffb88933"
|
||||
checksum = "820c46fde7ef1df0432073090d775f097b7279ca75ea34ba954081ce4b884d4c"
|
||||
dependencies = [
|
||||
"itertools 0.8.0",
|
||||
"log",
|
||||
@ -3260,20 +3255,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_ast_pretty"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3684ed43dc552f1e030e3f7a5a300a7a834bdda4e9e00ab80284be4220d8c603"
|
||||
checksum = "013db7dd198fe95962d2cefa5bd0b350cf2028af77c169b17b4baa9c3bbf77d1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rustc-ap-rustc_ast",
|
||||
"rustc-ap-rustc_span",
|
||||
"rustc-ap-rustc_target",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_attr"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31b413927daa666983b3b49227f9ac218aa29254546abdb585f20cd71c391870"
|
||||
checksum = "35b5a85c90eb341eec543600ffdd9e262da5ea72a73a23ae4ca2f4ab8cd1a188"
|
||||
dependencies = [
|
||||
"rustc-ap-rustc_ast",
|
||||
"rustc-ap-rustc_ast_pretty",
|
||||
@ -3281,17 +3277,17 @@ dependencies = [
|
||||
"rustc-ap-rustc_errors",
|
||||
"rustc-ap-rustc_feature",
|
||||
"rustc-ap-rustc_macros",
|
||||
"rustc-ap-rustc_serialize",
|
||||
"rustc-ap-rustc_session",
|
||||
"rustc-ap-rustc_span",
|
||||
"rustc-ap-serialize",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_data_structures"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b1c6069e5c522657f1c6f5ab33074e097092f48e804cc896d337e319aacbd60"
|
||||
checksum = "b92e4c6cb6c43ee9031a71709dc12853b358253c2b41d12a26379994fab625e0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
@ -3303,10 +3299,11 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"measureme",
|
||||
"once_cell",
|
||||
"parking_lot 0.10.2",
|
||||
"rustc-ap-graphviz",
|
||||
"rustc-ap-rustc_graphviz",
|
||||
"rustc-ap-rustc_index",
|
||||
"rustc-ap-serialize",
|
||||
"rustc-ap-rustc_serialize",
|
||||
"rustc-hash",
|
||||
"rustc-rayon",
|
||||
"rustc-rayon-core",
|
||||
@ -3318,16 +3315,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_errors"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c374e89b3c9714869ef86076942155383804ba6778c26be2169d324563c31f9"
|
||||
checksum = "6b0aa79423260c1b9e2f856e144e040f606b0f5d43644408375becf9d7bcdf86"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.6.1",
|
||||
"annotate-snippets 0.8.0",
|
||||
"atty",
|
||||
"log",
|
||||
"rustc-ap-rustc_data_structures",
|
||||
"rustc-ap-rustc_serialize",
|
||||
"rustc-ap-rustc_span",
|
||||
"rustc-ap-serialize",
|
||||
"termcolor",
|
||||
"termize",
|
||||
"unicode-width",
|
||||
@ -3336,9 +3333,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_expand"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "259d2a7aa7a12f3c99a4ce4123643ec065f1a26f8e89be1f9bedd9757ea53fdc"
|
||||
checksum = "c07d76ba2a1b7d4325a2ed21d6345ccebd89ddc6666a1535a6edd489fb4cbc11"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rustc-ap-rustc_ast",
|
||||
@ -3350,17 +3347,17 @@ dependencies = [
|
||||
"rustc-ap-rustc_feature",
|
||||
"rustc-ap-rustc_lexer",
|
||||
"rustc-ap-rustc_parse",
|
||||
"rustc-ap-rustc_serialize",
|
||||
"rustc-ap-rustc_session",
|
||||
"rustc-ap-rustc_span",
|
||||
"rustc-ap-serialize",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_feature"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0296fbc29b629d5ae2ebee1bbf0407bb22de04d26d87216c20899b79579ccb3"
|
||||
checksum = "1bbd625705c1db42a0c7503736292813d7b76ada5da20578fb55c63228c80ab5"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"rustc-ap-rustc_data_structures",
|
||||
@ -3369,34 +3366,40 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_fs_util"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34734f6cc681399630acd836a14207c6b5b9671a290cc7cad0354b0a4d71b3c9"
|
||||
checksum = "34cca6e2942fa0b059c582437ead666d5bcf20fa7c242599e2bbea9b609f29ae"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_graphviz"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13d6a029b81f5e02da85763f82c135507f278a4a0c776432c728520563059529"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_index"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1e4508753d71d3523209c2ca5086db15a1413e71ebf17ad5412bb7ced5e44c2"
|
||||
checksum = "bae50852d303e230b2781c994513788136dc6c2fe4ebe032959f0b990a425767"
|
||||
dependencies = [
|
||||
"rustc-ap-serialize",
|
||||
"rustc-ap-rustc_serialize",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_lexer"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42b9fcd8407e322908a721262fbc0b35b5f3c35bb173a26dd1e0070bde336e33"
|
||||
checksum = "b7186e74aa2d31bf0e2454325fefcdf0a3da77d9344134592144b9e40d45b15d"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_macros"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d104115a689367d2e0bcd99f37e0ebd6b9c8c78bab0d9cbea5bae86323601b5"
|
||||
checksum = "4fc1add04e9d2301164118660ee0bc3266e9a7b1973fc2303fdbe002a12e5401"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.3",
|
||||
"quote 1.0.2",
|
||||
@ -3406,9 +3409,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_parse"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afaaab91853fc5a3916785ccae727a4433359d9787c260d42b96a2265fe5b287"
|
||||
checksum = "9cd7fc4968bd60084f2fa4f280fa450b0cf98660a7983d6b93a7ae41b6d1d322"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"log",
|
||||
@ -3424,10 +3427,20 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_session"
|
||||
version = "659.0.0"
|
||||
name = "rustc-ap-rustc_serialize"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86e756a57ce6ce1b868e35e64a7e10ab28d49ece80d7c661b07aff5afc6e5d2d"
|
||||
checksum = "00bf4c110271d9a2b7dfd2c6eb82e56fd80606a8bad6c102e158c54e44044046"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_session"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "431cf962de71d4c03fb877d54f331ec36eca77350b0539017abc40a4410d6501"
|
||||
dependencies = [
|
||||
"getopts",
|
||||
"log",
|
||||
@ -3437,26 +3450,25 @@ dependencies = [
|
||||
"rustc-ap-rustc_errors",
|
||||
"rustc-ap-rustc_feature",
|
||||
"rustc-ap-rustc_fs_util",
|
||||
"rustc-ap-rustc_index",
|
||||
"rustc-ap-rustc_serialize",
|
||||
"rustc-ap-rustc_span",
|
||||
"rustc-ap-rustc_target",
|
||||
"rustc-ap-serialize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_span"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21031c3396ee452f4c6e994b67513a633055c57c86d00336afd9d63149518f34"
|
||||
checksum = "b912039640597624f4bcb75f1e1fcfa5710267d715a7f73a6336baef341b23d1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"log",
|
||||
"md-5",
|
||||
"rustc-ap-arena",
|
||||
"rustc-ap-rustc_arena",
|
||||
"rustc-ap-rustc_data_structures",
|
||||
"rustc-ap-rustc_index",
|
||||
"rustc-ap-rustc_macros",
|
||||
"rustc-ap-serialize",
|
||||
"rustc-ap-rustc_serialize",
|
||||
"scoped-tls",
|
||||
"sha-1",
|
||||
"unicode-width",
|
||||
@ -3464,27 +3476,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-rustc_target"
|
||||
version = "659.0.0"
|
||||
version = "664.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff21badfbead5b0050391eaad8840f2e4fcb03b6b0fc6006f447443529e9ae6e"
|
||||
checksum = "51347a9dadc5ad0b5916cc12d42624b31955285ad13745dbe72f0140038b84e9"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"log",
|
||||
"rustc-ap-rustc_data_structures",
|
||||
"rustc-ap-rustc_index",
|
||||
"rustc-ap-rustc_macros",
|
||||
"rustc-ap-rustc_serialize",
|
||||
"rustc-ap-rustc_span",
|
||||
"rustc-ap-serialize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-ap-serialize"
|
||||
version = "659.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "768b5a305669d934522712bc13502962edfde5128ea63b9e7db4000410be1dc6"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4278,6 +4280,7 @@ dependencies = [
|
||||
name = "rustc_session"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"getopts",
|
||||
"log",
|
||||
"num_cpus",
|
||||
@ -4481,16 +4484,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustfmt-nightly"
|
||||
version = "1.4.15"
|
||||
version = "1.4.18"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.6.1",
|
||||
"anyhow",
|
||||
"bytecount",
|
||||
"cargo_metadata 0.8.0",
|
||||
"derive-new",
|
||||
"diff",
|
||||
"dirs",
|
||||
"env_logger 0.6.2",
|
||||
"failure",
|
||||
"getopts",
|
||||
"ignore",
|
||||
"itertools 0.8.0",
|
||||
@ -4512,6 +4515,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"structopt",
|
||||
"term 0.6.0",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
|
@ -481,7 +481,7 @@ impl Step for Rustdoc {
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/tools/rustdoc")
|
||||
run.path("src/tools/rustdoc").path("src/librustdoc")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
|
@ -12,8 +12,7 @@ This feature allows for use of one of following sanitizers:
|
||||
* [ThreadSanitizer][clang-tsan] a fast data race detector.
|
||||
|
||||
To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`,
|
||||
`-Zsanitizer=memory` or `-Zsanitizer=thread`. Only a single sanitizer can be
|
||||
enabled at a time.
|
||||
`-Zsanitizer=memory` or `-Zsanitizer=thread`.
|
||||
|
||||
# AddressSanitizer
|
||||
|
||||
|
@ -2265,7 +2265,7 @@ pub trait Iterator {
|
||||
}
|
||||
|
||||
/// Applies function to the elements of iterator and returns
|
||||
/// the first non-none result or the first error.
|
||||
/// the first true result or the first error.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -2286,19 +2286,26 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
|
||||
fn try_find<F, E, R>(&mut self, mut f: F) -> Result<Option<Self::Item>, E>
|
||||
fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(&Self::Item) -> R,
|
||||
R: Try<Ok = bool, Error = E>,
|
||||
R: Try<Ok = bool>,
|
||||
{
|
||||
self.try_fold((), move |(), x| match f(&x).into_result() {
|
||||
#[inline]
|
||||
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> LoopState<(), Result<T, R::Error>>
|
||||
where
|
||||
F: FnMut(&T) -> R,
|
||||
R: Try<Ok = bool>,
|
||||
{
|
||||
move |(), x| match f(&x).into_result() {
|
||||
Ok(false) => LoopState::Continue(()),
|
||||
Ok(true) => LoopState::Break(Ok(x)),
|
||||
Err(x) => LoopState::Break(Err(x)),
|
||||
})
|
||||
.break_value()
|
||||
.transpose()
|
||||
}
|
||||
}
|
||||
|
||||
self.try_fold((), check(f)).break_value().transpose()
|
||||
}
|
||||
|
||||
/// Searches for an element in an iterator, returning its index.
|
||||
|
@ -19,7 +19,7 @@
|
||||
#![feature(raw)]
|
||||
#![feature(sort_internals)]
|
||||
#![feature(slice_partition_at_index)]
|
||||
#![feature(specialization)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(step_trait)]
|
||||
#![feature(step_trait_ext)]
|
||||
#![feature(str_internals)]
|
||||
|
@ -22,6 +22,7 @@ extern crate alloc;
|
||||
use rustc_data_structures::cold_path;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use std::alloc::Layout;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cmp;
|
||||
use std::intrinsics;
|
||||
@ -363,13 +364,15 @@ impl DroplessArena {
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates a byte slice with specified size and alignment from the
|
||||
/// current memory chunk. Returns `None` if there is no free space left to
|
||||
/// satisfy the request.
|
||||
/// Allocates a byte slice with specified layout from the current memory
|
||||
/// chunk. Returns `None` if there is no free space left to satisfy the
|
||||
/// request.
|
||||
#[inline]
|
||||
fn alloc_raw_without_grow(&self, bytes: usize, align: usize) -> Option<*mut u8> {
|
||||
fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> {
|
||||
let ptr = self.ptr.get() as usize;
|
||||
let end = self.end.get() as usize;
|
||||
let align = layout.align();
|
||||
let bytes = layout.size();
|
||||
// The allocation request fits into the current chunk iff:
|
||||
//
|
||||
// let aligned = align_to(ptr, align);
|
||||
@ -390,15 +393,15 @@ impl DroplessArena {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn alloc_raw(&self, bytes: usize, align: usize) -> *mut u8 {
|
||||
assert!(bytes != 0);
|
||||
pub fn alloc_raw(&self, layout: Layout) -> *mut u8 {
|
||||
assert!(layout.size() != 0);
|
||||
loop {
|
||||
if let Some(a) = self.alloc_raw_without_grow(bytes, align) {
|
||||
if let Some(a) = self.alloc_raw_without_grow(layout) {
|
||||
break a;
|
||||
}
|
||||
// No free space left. Allocate a new chunk to satisfy the request.
|
||||
// On failure the grow will panic or abort.
|
||||
self.grow(bytes);
|
||||
self.grow(layout.size());
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,7 +409,7 @@ impl DroplessArena {
|
||||
pub fn alloc<T>(&self, object: T) -> &mut T {
|
||||
assert!(!mem::needs_drop::<T>());
|
||||
|
||||
let mem = self.alloc_raw(mem::size_of::<T>(), mem::align_of::<T>()) as *mut T;
|
||||
let mem = self.alloc_raw(Layout::for_value::<T>(&object)) as *mut T;
|
||||
|
||||
unsafe {
|
||||
// Write into uninitialized memory.
|
||||
@ -431,7 +434,7 @@ impl DroplessArena {
|
||||
assert!(mem::size_of::<T>() != 0);
|
||||
assert!(!slice.is_empty());
|
||||
|
||||
let mem = self.alloc_raw(slice.len() * mem::size_of::<T>(), mem::align_of::<T>()) as *mut T;
|
||||
let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T;
|
||||
|
||||
unsafe {
|
||||
mem.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
|
||||
@ -477,8 +480,8 @@ impl DroplessArena {
|
||||
if len == 0 {
|
||||
return &mut [];
|
||||
}
|
||||
let size = len.checked_mul(mem::size_of::<T>()).unwrap();
|
||||
let mem = self.alloc_raw(size, mem::align_of::<T>()) as *mut T;
|
||||
|
||||
let mem = self.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
|
||||
unsafe { self.write_from_iter(iter, len, mem) }
|
||||
}
|
||||
(_, _) => {
|
||||
@ -491,9 +494,8 @@ impl DroplessArena {
|
||||
// the content of the SmallVec
|
||||
unsafe {
|
||||
let len = vec.len();
|
||||
let start_ptr = self
|
||||
.alloc_raw(len * mem::size_of::<T>(), mem::align_of::<T>())
|
||||
as *mut T;
|
||||
let start_ptr =
|
||||
self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T;
|
||||
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||
vec.set_len(0);
|
||||
slice::from_raw_parts_mut(start_ptr, len)
|
||||
@ -537,7 +539,7 @@ pub struct DropArena {
|
||||
impl DropArena {
|
||||
#[inline]
|
||||
pub unsafe fn alloc<T>(&self, object: T) -> &mut T {
|
||||
let mem = self.arena.alloc_raw(mem::size_of::<T>(), mem::align_of::<T>()) as *mut T;
|
||||
let mem = self.arena.alloc_raw(Layout::new::<T>()) as *mut T;
|
||||
// Write into uninitialized memory.
|
||||
ptr::write(mem, object);
|
||||
let result = &mut *mem;
|
||||
@ -557,10 +559,7 @@ impl DropArena {
|
||||
}
|
||||
let len = vec.len();
|
||||
|
||||
let start_ptr = self
|
||||
.arena
|
||||
.alloc_raw(len.checked_mul(mem::size_of::<T>()).unwrap(), mem::align_of::<T>())
|
||||
as *mut T;
|
||||
let start_ptr = self.arena.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
|
||||
|
||||
let mut destructors = self.destructors.borrow_mut();
|
||||
// Reserve space for the destructors so we can't panic while adding them
|
||||
|
@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::{OptLevel, Sanitizer};
|
||||
use rustc_session::config::{OptLevel, SanitizerSet};
|
||||
use rustc_session::Session;
|
||||
|
||||
use crate::attributes;
|
||||
@ -45,27 +45,17 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
|
||||
|
||||
/// Apply LLVM sanitize attributes.
|
||||
#[inline]
|
||||
pub fn sanitize(cx: &CodegenCx<'ll, '_>, codegen_fn_flags: CodegenFnAttrFlags, llfn: &'ll Value) {
|
||||
if let Some(ref sanitizer) = cx.tcx.sess.opts.debugging_opts.sanitizer {
|
||||
match *sanitizer {
|
||||
Sanitizer::Address => {
|
||||
if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
|
||||
pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll Value) {
|
||||
let enabled = cx.tcx.sess.opts.debugging_opts.sanitizer - no_sanitize;
|
||||
if enabled.contains(SanitizerSet::ADDRESS) {
|
||||
llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
|
||||
}
|
||||
}
|
||||
Sanitizer::Memory => {
|
||||
if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
|
||||
if enabled.contains(SanitizerSet::MEMORY) {
|
||||
llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn);
|
||||
}
|
||||
}
|
||||
Sanitizer::Thread => {
|
||||
if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
|
||||
if enabled.contains(SanitizerSet::THREAD) {
|
||||
llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
|
||||
}
|
||||
}
|
||||
Sanitizer::Leak => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
|
||||
@ -123,9 +113,14 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
|
||||
// Currently stack probes seem somewhat incompatible with the address
|
||||
// sanitizer and thread sanitizer. With asan we're already protected from
|
||||
// stack overflow anyway so we don't really need stack probes regardless.
|
||||
match cx.sess().opts.debugging_opts.sanitizer {
|
||||
Some(Sanitizer::Address | Sanitizer::Thread) => return,
|
||||
_ => {}
|
||||
if cx
|
||||
.sess()
|
||||
.opts
|
||||
.debugging_opts
|
||||
.sanitizer
|
||||
.intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// probestack doesn't play nice either with `-C profile-generate`.
|
||||
@ -296,7 +291,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
|
||||
Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
|
||||
}
|
||||
sanitize(cx, codegen_fn_attrs.flags, llfn);
|
||||
sanitize(cx, codegen_fn_attrs.no_sanitize, llfn);
|
||||
|
||||
// Always annotate functions with the target-cpu they are compiled for.
|
||||
// Without this, ThinLTO won't inline Rust functions into Clang generated
|
||||
|
@ -21,7 +21,7 @@ use rustc_fs_util::{link_or_copy, path_to_c_string};
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath};
|
||||
use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::InnerSpan;
|
||||
use rustc_target::spec::{CodeModel, RelocModel};
|
||||
@ -394,12 +394,13 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
|
||||
let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
|
||||
// Sanitizer instrumentation is only inserted during the pre-link optimization stage.
|
||||
let sanitizer_options = if !is_lto {
|
||||
config.sanitizer.as_ref().map(|s| llvm::SanitizerOptions {
|
||||
sanitize_memory: *s == Sanitizer::Memory,
|
||||
sanitize_thread: *s == Sanitizer::Thread,
|
||||
sanitize_address: *s == Sanitizer::Address,
|
||||
sanitize_recover: config.sanitizer_recover.contains(s),
|
||||
Some(llvm::SanitizerOptions {
|
||||
sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS),
|
||||
sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS),
|
||||
sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
|
||||
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
|
||||
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
|
||||
sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@ -600,26 +601,19 @@ pub(crate) unsafe fn optimize(
|
||||
}
|
||||
|
||||
unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {
|
||||
let sanitizer = match &config.sanitizer {
|
||||
None => return,
|
||||
Some(s) => s,
|
||||
};
|
||||
|
||||
let recover = config.sanitizer_recover.contains(sanitizer);
|
||||
match sanitizer {
|
||||
Sanitizer::Address => {
|
||||
if config.sanitizer.contains(SanitizerSet::ADDRESS) {
|
||||
let recover = config.sanitizer_recover.contains(SanitizerSet::ADDRESS);
|
||||
passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover));
|
||||
passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover));
|
||||
}
|
||||
Sanitizer::Memory => {
|
||||
if config.sanitizer.contains(SanitizerSet::MEMORY) {
|
||||
let track_origins = config.sanitizer_memory_track_origins as c_int;
|
||||
let recover = config.sanitizer_recover.contains(SanitizerSet::MEMORY);
|
||||
passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover));
|
||||
}
|
||||
Sanitizer::Thread => {
|
||||
if config.sanitizer.contains(SanitizerSet::THREAD) {
|
||||
passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
|
||||
}
|
||||
Sanitizer::Leak => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn codegen(
|
||||
|
@ -29,12 +29,12 @@ use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_middle::dep_graph;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::middle::cstore::EncodedMetadata;
|
||||
use rustc_middle::middle::exported_symbols;
|
||||
use rustc_middle::mir::mono::{Linkage, Visibility};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_session::config::{DebugInfo, SanitizerSet};
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
use std::ffi::CString;
|
||||
@ -132,7 +132,7 @@ pub fn compile_codegen_unit(
|
||||
// If this codegen unit contains the main function, also create the
|
||||
// wrapper here
|
||||
if let Some(entry) = maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx) {
|
||||
attributes::sanitize(&cx, CodegenFnAttrFlags::empty(), entry);
|
||||
attributes::sanitize(&cx, SanitizerSet::empty(), entry);
|
||||
}
|
||||
|
||||
// Run replace-all-uses-with for statics that need it
|
||||
|
@ -206,7 +206,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
let len = s.as_str().len();
|
||||
let cs = consts::ptrcast(
|
||||
self.const_cstr(s, false),
|
||||
self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self)),
|
||||
self.type_ptr_to(self.layout_of(self.tcx.types.str_).llvm_type(self)),
|
||||
);
|
||||
(cs, self.const_usize(len as u64))
|
||||
}
|
||||
|
@ -439,11 +439,12 @@ pub enum OptStage {
|
||||
/// LLVMRustSanitizerOptions
|
||||
#[repr(C)]
|
||||
pub struct SanitizerOptions {
|
||||
pub sanitize_memory: bool,
|
||||
pub sanitize_thread: bool,
|
||||
pub sanitize_address: bool,
|
||||
pub sanitize_recover: bool,
|
||||
pub sanitize_address_recover: bool,
|
||||
pub sanitize_memory: bool,
|
||||
pub sanitize_memory_recover: bool,
|
||||
pub sanitize_memory_track_origins: c_int,
|
||||
pub sanitize_thread: bool,
|
||||
}
|
||||
|
||||
/// LLVMRelocMode
|
||||
|
@ -4,7 +4,7 @@ use rustc_hir::def_id::CrateNum;
|
||||
use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib};
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
|
||||
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, Sanitizer};
|
||||
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet};
|
||||
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
|
||||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_session::utils::NativeLibKind;
|
||||
@ -766,23 +766,26 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
|
||||
}
|
||||
}
|
||||
|
||||
fn link_sanitizer_runtime(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
|
||||
let sanitizer = match &sess.opts.debugging_opts.sanitizer {
|
||||
Some(s) => s,
|
||||
None => return,
|
||||
};
|
||||
|
||||
fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
|
||||
if crate_type != CrateType::Executable {
|
||||
return;
|
||||
}
|
||||
let sanitizer = sess.opts.debugging_opts.sanitizer;
|
||||
if sanitizer.contains(SanitizerSet::ADDRESS) {
|
||||
link_sanitizer_runtime(sess, linker, "asan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::LEAK) {
|
||||
link_sanitizer_runtime(sess, linker, "lsan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::MEMORY) {
|
||||
link_sanitizer_runtime(sess, linker, "msan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::THREAD) {
|
||||
link_sanitizer_runtime(sess, linker, "tsan");
|
||||
}
|
||||
}
|
||||
|
||||
let name = match sanitizer {
|
||||
Sanitizer::Address => "asan",
|
||||
Sanitizer::Leak => "lsan",
|
||||
Sanitizer::Memory => "msan",
|
||||
Sanitizer::Thread => "tsan",
|
||||
};
|
||||
|
||||
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
|
||||
let default_sysroot = filesearch::get_or_default_sysroot();
|
||||
let default_tlib =
|
||||
filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple());
|
||||
@ -1555,9 +1558,10 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
if sess.target.target.options.is_like_fuchsia && crate_type == CrateType::Executable {
|
||||
let prefix = match sess.opts.debugging_opts.sanitizer {
|
||||
Some(Sanitizer::Address) => "asan/",
|
||||
_ => "",
|
||||
let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
|
||||
"asan/"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
|
||||
}
|
||||
@ -1581,7 +1585,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
||||
}
|
||||
|
||||
// OBJECT-FILES-YES, AUDIT-ORDER
|
||||
link_sanitizer_runtime(sess, crate_type, cmd);
|
||||
link_sanitizers(sess, crate_type, cmd);
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// Linker plugins should be specified early in the list of arguments
|
||||
|
@ -15,7 +15,7 @@ use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::{SymbolName, TyCtxt};
|
||||
use rustc_session::config::{CrateType, Sanitizer};
|
||||
use rustc_session::config::{CrateType, SanitizerSet};
|
||||
|
||||
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
|
||||
crates_export_threshold(&tcx.sess.crate_types())
|
||||
@ -204,7 +204,7 @@ fn exported_symbols_provider_local(
|
||||
}));
|
||||
}
|
||||
|
||||
if let Some(Sanitizer::Memory) = tcx.sess.opts.debugging_opts.sanitizer {
|
||||
if tcx.sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::MEMORY) {
|
||||
// Similar to profiling, preserve weak msan symbol during LTO.
|
||||
const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
|
||||
|
||||
|
@ -29,7 +29,7 @@ use rustc_middle::middle::exported_symbols::SymbolExportLevel;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::cgu_reuse_tracker::CguReuseTracker;
|
||||
use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType};
|
||||
use rustc_session::config::{Passes, Sanitizer, SwitchWithOptPath};
|
||||
use rustc_session::config::{Passes, SanitizerSet, SwitchWithOptPath};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
@ -86,8 +86,8 @@ pub struct ModuleConfig {
|
||||
pub pgo_gen: SwitchWithOptPath,
|
||||
pub pgo_use: Option<PathBuf>,
|
||||
|
||||
pub sanitizer: Option<Sanitizer>,
|
||||
pub sanitizer_recover: Vec<Sanitizer>,
|
||||
pub sanitizer: SanitizerSet,
|
||||
pub sanitizer_recover: SanitizerSet,
|
||||
pub sanitizer_memory_track_origins: usize,
|
||||
|
||||
// Flags indicating which outputs to produce.
|
||||
@ -195,10 +195,10 @@ impl ModuleConfig {
|
||||
),
|
||||
pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None),
|
||||
|
||||
sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer.clone(), None),
|
||||
sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer, SanitizerSet::empty()),
|
||||
sanitizer_recover: if_regular!(
|
||||
sess.opts.debugging_opts.sanitizer_recover.clone(),
|
||||
vec![]
|
||||
sess.opts.debugging_opts.sanitizer_recover,
|
||||
SanitizerSet::empty()
|
||||
),
|
||||
sanitizer_memory_track_origins: if_regular!(
|
||||
sess.opts.debugging_opts.sanitizer_memory_track_origins,
|
||||
|
@ -444,6 +444,7 @@ E0760: include_str!("./error_codes/E0760.md"),
|
||||
E0761: include_str!("./error_codes/E0761.md"),
|
||||
E0762: include_str!("./error_codes/E0762.md"),
|
||||
E0763: include_str!("./error_codes/E0763.md"),
|
||||
E0764: include_str!("./error_codes/E0764.md"),
|
||||
;
|
||||
// E0006, // merged with E0005
|
||||
// E0008, // cannot bind by-move into a pattern guard
|
||||
|
@ -1,11 +1,7 @@
|
||||
Malformed inline assembly rejected by LLVM.
|
||||
|
||||
LLVM checks the validity of the constraints and the assembly string passed to
|
||||
it. This error implies that LLVM seems something wrong with the inline
|
||||
assembly call.
|
||||
Erroneous code example:
|
||||
|
||||
In particular, it can happen if you forgot the closing bracket of a register
|
||||
constraint (see issue #51430):
|
||||
```compile_fail,E0668
|
||||
#![feature(llvm_asm)]
|
||||
|
||||
@ -17,3 +13,10 @@ fn main() {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
LLVM checks the validity of the constraints and the assembly string passed to
|
||||
it. This error implies that LLVM seems something wrong with the inline
|
||||
assembly call.
|
||||
|
||||
In particular, it can happen if you forgot the closing bracket of a register
|
||||
constraint (see issue #51430), like in the previous code example.
|
||||
|
@ -1,6 +1,6 @@
|
||||
Rust 2015 does not permit the use of `async fn`.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0670
|
||||
async fn foo() {}
|
||||
|
39
src/librustc_error_codes/error_codes/E0764.md
Normal file
39
src/librustc_error_codes/error_codes/E0764.md
Normal file
@ -0,0 +1,39 @@
|
||||
Mutable references (`&mut`) can only be used in constant functions, not statics
|
||||
or constants. This limitation exists to prevent the creation of constants that
|
||||
have a mutable reference in their final value. If you had a constant of `&mut
|
||||
i32` type, you could modify the value through that reference, making the
|
||||
constant essentially mutable. While there could be a more fine-grained scheme
|
||||
in the future that allows mutable references if they are not "leaked" to the
|
||||
final value, a more conservative approach was chosen for now. `const fn` do not
|
||||
have this problem, as the borrow checker will prevent the `const fn` from
|
||||
returning new mutable references.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0764
|
||||
#![feature(const_fn)]
|
||||
#![feature(const_mut_refs)]
|
||||
|
||||
fn main() {
|
||||
const OH_NO: &'static mut usize = &mut 1; // error!
|
||||
}
|
||||
```
|
||||
|
||||
Remember: you cannot use a function call inside a constant or static. However,
|
||||
you can totally use it in constant functions:
|
||||
|
||||
```
|
||||
#![feature(const_fn)]
|
||||
#![feature(const_mut_refs)]
|
||||
|
||||
const fn foo(x: usize) -> usize {
|
||||
let mut y = 1;
|
||||
let z = &mut y;
|
||||
*z += x;
|
||||
y
|
||||
}
|
||||
|
||||
fn main() {
|
||||
const FOO: usize = foo(10); // ok!
|
||||
}
|
||||
```
|
@ -596,4 +596,5 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
|
||||
sym::raw_dylib,
|
||||
sym::const_trait_impl,
|
||||
sym::const_trait_bound_opt_out,
|
||||
sym::specialization,
|
||||
];
|
||||
|
@ -314,18 +314,19 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
ty::ReVar(vid) => {
|
||||
let r = self
|
||||
let resolved_vid = self
|
||||
.infcx
|
||||
.unwrap()
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_var(self.tcx, vid);
|
||||
.opportunistic_resolve_var(vid);
|
||||
debug!(
|
||||
"canonical: region var found with vid {:?}, \
|
||||
opportunistically resolved to {:?}",
|
||||
vid, r
|
||||
);
|
||||
let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
|
||||
self.canonicalize_region_mode.canonicalize_free_region(self, r)
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,17 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
|
||||
if let (None, Some(ty)) =
|
||||
(self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
|
||||
{
|
||||
// FIXME: There's a trade-off here - we can either check that our target span
|
||||
// is contained in `local.span` or not. If we choose to check containment
|
||||
// we can avoid some spurious suggestions (see #72690), but we lose
|
||||
// the ability to report on things like:
|
||||
//
|
||||
// ```
|
||||
// let x = vec![];
|
||||
// ```
|
||||
//
|
||||
// because the target span will be in the macro expansion of `vec![]`.
|
||||
// At present we choose not to check containment.
|
||||
self.found_local_pattern = Some(&*local.pat);
|
||||
self.found_node_ty = Some(ty);
|
||||
}
|
||||
@ -99,10 +110,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
|
||||
if let (None, Some(ty)) =
|
||||
(self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
|
||||
{
|
||||
if self.target_span.contains(param.pat.span) {
|
||||
self.found_arg_pattern = Some(&*param.pat);
|
||||
self.found_node_ty = Some(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
intravisit::walk_body(self, body);
|
||||
}
|
||||
|
||||
|
@ -50,10 +50,10 @@ pub struct RegionConstraintStorage<'tcx> {
|
||||
/// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this
|
||||
/// table. You can then call `opportunistic_resolve_var` early
|
||||
/// which will map R1 and R2 to some common region (i.e., either
|
||||
/// R1 or R2). This is important when dropck and other such code
|
||||
/// is iterating to a fixed point, because otherwise we sometimes
|
||||
/// would wind up with a fresh stream of region variables that
|
||||
/// have been equated but appear distinct.
|
||||
/// R1 or R2). This is important when fulfillment, dropck and other such
|
||||
/// code is iterating to a fixed point, because otherwise we sometimes
|
||||
/// would wind up with a fresh stream of region variables that have been
|
||||
/// equated but appear distinct.
|
||||
pub(super) unification_table: ut::UnificationTableStorage<ty::RegionVid>,
|
||||
|
||||
/// a flag set to true when we perform any unifications; this is used
|
||||
@ -714,13 +714,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opportunistic_resolve_var(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
rid: RegionVid,
|
||||
) -> ty::Region<'tcx> {
|
||||
let vid = self.unification_table().probe_value(rid).min_vid;
|
||||
tcx.mk_region(ty::ReVar(vid))
|
||||
pub fn opportunistic_resolve_var(&mut self, rid: RegionVid) -> ty::RegionVid {
|
||||
self.unification_table().probe_value(rid).min_vid
|
||||
}
|
||||
|
||||
fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> {
|
||||
|
@ -46,51 +46,56 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The opportunistic type and region resolver is similar to the
|
||||
/// opportunistic type resolver, but also opportunistically resolves
|
||||
/// regions. It is useful for canonicalization.
|
||||
pub struct OpportunisticTypeAndRegionResolver<'a, 'tcx> {
|
||||
/// The opportunistic region resolver opportunistically resolves regions
|
||||
/// variables to the variable with the least variable id. It is used when
|
||||
/// normlizing projections to avoid hitting the recursion limit by creating
|
||||
/// many versions of a predicate for types that in the end have to unify.
|
||||
///
|
||||
/// If you want to resolve type and const variables as well, call
|
||||
/// [InferCtxt::resolve_vars_if_possible] first.
|
||||
pub struct OpportunisticRegionResolver<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> OpportunisticTypeAndRegionResolver<'a, 'tcx> {
|
||||
impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> {
|
||||
pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
|
||||
OpportunisticTypeAndRegionResolver { infcx }
|
||||
OpportunisticRegionResolver { infcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver<'a, 'tcx> {
|
||||
impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if !t.needs_infer() {
|
||||
if !t.has_infer_regions() {
|
||||
t // micro-optimize -- if there is nothing in this type that this fold affects...
|
||||
} else {
|
||||
let t0 = self.infcx.shallow_resolve(t);
|
||||
t0.super_fold_with(self)
|
||||
t.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match *r {
|
||||
ty::ReVar(rid) => self
|
||||
ty::ReVar(rid) => {
|
||||
let resolved = self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_var(self.tcx(), rid),
|
||||
.opportunistic_resolve_var(rid);
|
||||
self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved))
|
||||
}
|
||||
_ => r,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
if !ct.needs_infer() {
|
||||
if !ct.has_infer_regions() {
|
||||
ct // micro-optimize -- if there is nothing in this const that this fold affects...
|
||||
} else {
|
||||
let c0 = self.infcx.shallow_resolve(ct);
|
||||
c0.super_fold_with(self)
|
||||
ct.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,9 @@ use rustc_session::config::Strip;
|
||||
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
|
||||
use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
|
||||
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
|
||||
use rustc_session::config::{Externs, OutputType, OutputTypes, Sanitizer, SymbolManglingVersion};
|
||||
use rustc_session::config::{
|
||||
Externs, OutputType, OutputTypes, SanitizerSet, SymbolManglingVersion,
|
||||
};
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_session::search_paths::SearchPath;
|
||||
use rustc_session::utils::NativeLibKind;
|
||||
@ -569,9 +571,9 @@ fn test_debugging_options_tracking_hash() {
|
||||
tracked!(relro_level, Some(RelroLevel::Full));
|
||||
tracked!(report_delayed_bugs, true);
|
||||
tracked!(run_dsymutil, false);
|
||||
tracked!(sanitizer, Some(Sanitizer::Address));
|
||||
tracked!(sanitizer, SanitizerSet::ADDRESS);
|
||||
tracked!(sanitizer_memory_track_origins, 2);
|
||||
tracked!(sanitizer_recover, vec![Sanitizer::Address]);
|
||||
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
|
||||
tracked!(saturating_float_casts, Some(true));
|
||||
tracked!(share_generics, Some(true));
|
||||
tracked!(show_span, Some(String::from("abc")));
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::mir::mono::Linkage;
|
||||
use rustc_attr::{InlineAttr, OptimizeAttr};
|
||||
use rustc_session::config::SanitizerSet;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
|
||||
@ -30,6 +31,9 @@ pub struct CodegenFnAttrs {
|
||||
/// The `#[link_section = "..."]` attribute, or what executable section this
|
||||
/// should be placed in.
|
||||
pub link_section: Option<Symbol>,
|
||||
/// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which
|
||||
/// instrumentation should be disabled inside the annotated function.
|
||||
pub no_sanitize: SanitizerSet,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
@ -69,20 +73,12 @@ bitflags! {
|
||||
const FFI_RETURNS_TWICE = 1 << 10;
|
||||
/// `#[track_caller]`: allow access to the caller location
|
||||
const TRACK_CALLER = 1 << 11;
|
||||
/// `#[no_sanitize(address)]`: disables address sanitizer instrumentation
|
||||
const NO_SANITIZE_ADDRESS = 1 << 12;
|
||||
/// `#[no_sanitize(memory)]`: disables memory sanitizer instrumentation
|
||||
const NO_SANITIZE_MEMORY = 1 << 13;
|
||||
/// `#[no_sanitize(thread)]`: disables thread sanitizer instrumentation
|
||||
const NO_SANITIZE_THREAD = 1 << 14;
|
||||
/// All `#[no_sanitize(...)]` attributes.
|
||||
const NO_SANITIZE_ANY = Self::NO_SANITIZE_ADDRESS.bits | Self::NO_SANITIZE_MEMORY.bits | Self::NO_SANITIZE_THREAD.bits;
|
||||
/// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
|
||||
/// declaration.
|
||||
const FFI_PURE = 1 << 15;
|
||||
const FFI_PURE = 1 << 12;
|
||||
/// #[ffi_const]: applies clang's `const` attribute to a foreign function
|
||||
/// declaration.
|
||||
const FFI_CONST = 1 << 16;
|
||||
const FFI_CONST = 1 << 13;
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,6 +94,7 @@ impl CodegenFnAttrs {
|
||||
target_features: vec![],
|
||||
linkage: None,
|
||||
link_section: None,
|
||||
no_sanitize: SanitizerSet::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,6 +244,6 @@ pub enum ClosureOutlivesSubject<'tcx> {
|
||||
/// The constituent parts of an ADT or array.
|
||||
#[derive(Copy, Clone, Debug, HashStable)]
|
||||
pub struct DestructuredConst<'tcx> {
|
||||
pub variant: VariantIdx,
|
||||
pub variant: Option<VariantIdx>,
|
||||
pub fields: &'tcx [&'tcx ty::Const<'tcx>],
|
||||
}
|
||||
|
@ -143,6 +143,7 @@ pub struct CommonTypes<'tcx> {
|
||||
pub u128: Ty<'tcx>,
|
||||
pub f32: Ty<'tcx>,
|
||||
pub f64: Ty<'tcx>,
|
||||
pub str_: Ty<'tcx>,
|
||||
pub never: Ty<'tcx>,
|
||||
pub self_param: Ty<'tcx>,
|
||||
|
||||
@ -816,6 +817,7 @@ impl<'tcx> CommonTypes<'tcx> {
|
||||
u128: mk(Uint(ast::UintTy::U128)),
|
||||
f32: mk(Float(ast::FloatTy::F32)),
|
||||
f64: mk(Float(ast::FloatTy::F64)),
|
||||
str_: mk(Str),
|
||||
self_param: mk(ty::Param(ty::ParamTy { index: 0, name: kw::SelfUpper })),
|
||||
|
||||
trait_object_dummy_self: mk(Infer(ty::FreshTy(0))),
|
||||
@ -2108,6 +2110,13 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Same a `self.mk_region(kind)`, but avoids accessing the interners if
|
||||
/// `*r == kind`.
|
||||
#[inline]
|
||||
pub fn reuse_or_mk_region(self, r: Region<'tcx>, kind: RegionKind) -> Region<'tcx> {
|
||||
if *r == kind { r } else { self.mk_region(kind) }
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
#[inline]
|
||||
pub fn mk_ty(&self, st: TyKind<'tcx>) -> Ty<'tcx> {
|
||||
@ -2149,14 +2158,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mk_str(self) -> Ty<'tcx> {
|
||||
self.mk_ty(Str)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mk_static_str(self) -> Ty<'tcx> {
|
||||
self.mk_imm_ref(self.lifetimes.re_static, self.mk_str())
|
||||
self.mk_imm_ref(self.lifetimes.re_static, self.types.str_)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -87,6 +87,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
|
||||
fn has_param_types_or_consts(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
|
||||
}
|
||||
fn has_infer_regions(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_RE_INFER)
|
||||
}
|
||||
fn has_infer_types(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_TY_INFER)
|
||||
}
|
||||
|
@ -9,6 +9,11 @@ use rustc_macros::HashStable;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
/// A monomorphized `InstanceDef`.
|
||||
///
|
||||
/// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type
|
||||
/// simply couples a potentially generic `InstanceDef` with some substs, and codegen and const eval
|
||||
/// will do all required substitution as they run.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
#[derive(HashStable, Lift)]
|
||||
pub struct Instance<'tcx> {
|
||||
@ -18,10 +23,26 @@ pub struct Instance<'tcx> {
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub enum InstanceDef<'tcx> {
|
||||
/// A user-defined callable item.
|
||||
///
|
||||
/// This includes:
|
||||
/// - `fn` items
|
||||
/// - closures
|
||||
/// - generators
|
||||
Item(DefId),
|
||||
|
||||
/// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI).
|
||||
///
|
||||
/// Alongside `Virtual`, this is the only `InstanceDef` that does not have its own callable MIR.
|
||||
/// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the
|
||||
/// caller.
|
||||
Intrinsic(DefId),
|
||||
|
||||
/// `<T as Trait>::method` where `method` receives unsizeable `self: Self`.
|
||||
/// `<T as Trait>::method` where `method` receives unsizeable `self: Self` (part of the
|
||||
/// `unsized_locals` feature).
|
||||
///
|
||||
/// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` -
|
||||
/// and dereference the argument to call the original function.
|
||||
VtableShim(DefId),
|
||||
|
||||
/// `fn()` pointer where the function itself cannot be turned into a pointer.
|
||||
@ -37,7 +58,8 @@ pub enum InstanceDef<'tcx> {
|
||||
/// (the definition of the function itself).
|
||||
ReifyShim(DefId),
|
||||
|
||||
/// `<fn() as FnTrait>::call_*`
|
||||
/// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
|
||||
///
|
||||
/// `DefId` is `FnTrait::call_*`.
|
||||
///
|
||||
/// NB: the (`fn` pointer) type must currently be monomorphic to avoid double substitution
|
||||
@ -45,19 +67,22 @@ pub enum InstanceDef<'tcx> {
|
||||
// FIXME(#69925) support polymorphic MIR shim bodies properly instead.
|
||||
FnPtrShim(DefId, Ty<'tcx>),
|
||||
|
||||
/// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly
|
||||
/// codegen'd as virtual calls.
|
||||
/// Dynamic dispatch to `<dyn Trait as Trait>::fn`.
|
||||
///
|
||||
/// NB: if this is reified to a `fn` pointer, a `ReifyShim` is used
|
||||
/// (see `ReifyShim` above for more details on that).
|
||||
/// This `InstanceDef` does not have callable MIR. Calls to `Virtual` instances must be
|
||||
/// codegen'd as virtual calls through the vtable.
|
||||
///
|
||||
/// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more
|
||||
/// details on that).
|
||||
Virtual(DefId, usize),
|
||||
|
||||
/// `<[mut closure] as FnOnce>::call_once`
|
||||
ClosureOnceShim {
|
||||
call_once: DefId,
|
||||
},
|
||||
/// `<[FnMut closure] as FnOnce>::call_once`.
|
||||
///
|
||||
/// The `DefId` is the ID of the `call_once` method in `FnOnce`.
|
||||
ClosureOnceShim { call_once: DefId },
|
||||
|
||||
/// `core::ptr::drop_in_place::<T>`.
|
||||
///
|
||||
/// The `DefId` is for `core::ptr::drop_in_place`.
|
||||
/// The `Option<Ty<'tcx>>` is either `Some(T)`, or `None` for empty drop
|
||||
/// glue.
|
||||
@ -67,7 +92,12 @@ pub enum InstanceDef<'tcx> {
|
||||
// FIXME(#69925) support polymorphic MIR shim bodies properly instead.
|
||||
DropGlue(DefId, Option<Ty<'tcx>>),
|
||||
|
||||
///`<T as Clone>::clone` shim.
|
||||
/// Compiler-generated `<T as Clone>::clone` implementation.
|
||||
///
|
||||
/// For all types that automatically implement `Copy`, a trivial `Clone` impl is provided too.
|
||||
/// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`.
|
||||
///
|
||||
/// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl.
|
||||
///
|
||||
/// NB: the type must currently be monomorphic to avoid double substitution
|
||||
/// problems with the MIR shim bodies. `Instance::resolve` enforces this.
|
||||
|
@ -2001,6 +2001,8 @@ where
|
||||
}
|
||||
|
||||
let fields = match this.ty.kind {
|
||||
ty::Adt(def, _) if def.variants.is_empty() =>
|
||||
bug!("for_variant called on zero-variant enum"),
|
||||
ty::Adt(def, _) => def.variants[variant_index].fields.len(),
|
||||
_ => bug!(),
|
||||
};
|
||||
|
@ -2,7 +2,8 @@ use crate::arena::Arena;
|
||||
|
||||
use rustc_serialize::{Encodable, Encoder};
|
||||
|
||||
use std::cmp::{self, Ordering};
|
||||
use std::alloc::Layout;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter;
|
||||
@ -43,17 +44,9 @@ impl<T: Copy> List<T> {
|
||||
assert!(mem::size_of::<T>() != 0);
|
||||
assert!(!slice.is_empty());
|
||||
|
||||
// Align up the size of the len (usize) field
|
||||
let align = mem::align_of::<T>();
|
||||
let align_mask = align - 1;
|
||||
let offset = mem::size_of::<usize>();
|
||||
let offset = (offset + align_mask) & !align_mask;
|
||||
|
||||
let size = offset + slice.len() * mem::size_of::<T>();
|
||||
|
||||
let mem = arena
|
||||
.dropless
|
||||
.alloc_raw(size, cmp::max(mem::align_of::<T>(), mem::align_of::<usize>()));
|
||||
let (layout, _offset) =
|
||||
Layout::new::<usize>().extend(Layout::for_value::<[T]>(slice)).unwrap();
|
||||
let mem = arena.dropless.alloc_raw(layout);
|
||||
unsafe {
|
||||
let result = &mut *(mem as *mut List<T>);
|
||||
// Write the length
|
||||
|
@ -2352,6 +2352,7 @@ impl<'tcx> AdtDef {
|
||||
/// Alternatively, if there is no explicit discriminant, returns the
|
||||
/// inferred discriminant directly.
|
||||
pub fn discriminant_def_for_variant(&self, variant_index: VariantIdx) -> (Option<DefId>, u32) {
|
||||
assert!(!self.variants.is_empty());
|
||||
let mut explicit_index = variant_index.as_u32();
|
||||
let expr_did;
|
||||
loop {
|
||||
|
@ -1177,8 +1177,13 @@ pub trait PrettyPrinter<'tcx>:
|
||||
}
|
||||
p!(write(")"));
|
||||
}
|
||||
ty::Adt(def, substs) if def.variants.is_empty() => {
|
||||
p!(print_value_path(def.did, substs));
|
||||
}
|
||||
ty::Adt(def, substs) => {
|
||||
let variant_def = &def.variants[contents.variant];
|
||||
let variant_id =
|
||||
contents.variant.expect("destructed const of adt without variant id");
|
||||
let variant_def = &def.variants[variant_id];
|
||||
p!(print_value_path(variant_def.def_id, substs));
|
||||
|
||||
match variant_def.ctor_kind {
|
||||
|
@ -2099,6 +2099,9 @@ impl<'tcx> TyS<'tcx> {
|
||||
variant_index: VariantIdx,
|
||||
) -> Option<Discr<'tcx>> {
|
||||
match self.kind {
|
||||
TyKind::Adt(adt, _) if adt.variants.is_empty() => {
|
||||
bug!("discriminant_for_variant called on zero variant enum");
|
||||
}
|
||||
TyKind::Adt(adt, _) if adt.is_enum() => {
|
||||
Some(adt.discriminant_for_variant(tcx, variant_index))
|
||||
}
|
||||
|
@ -30,8 +30,10 @@ pub(crate) fn const_caller_location(
|
||||
ConstValue::Scalar(loc_place.ptr)
|
||||
}
|
||||
|
||||
// this function uses `unwrap` copiously, because an already validated constant
|
||||
// must have valid fields and can thus never fail outside of compiler bugs
|
||||
/// This function uses `unwrap` copiously, because an already validated constant
|
||||
/// must have valid fields and can thus never fail outside of compiler bugs. However, it is
|
||||
/// invoked from the pretty printer, where it can receive enums with no variants and e.g.
|
||||
/// `read_discriminant` needs to be able to handle that.
|
||||
pub(crate) fn destructure_const<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
@ -41,17 +43,21 @@ pub(crate) fn destructure_const<'tcx>(
|
||||
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
|
||||
let op = ecx.eval_const_to_op(val, None).unwrap();
|
||||
|
||||
let variant = ecx.read_discriminant(op).unwrap().1;
|
||||
|
||||
// We go to `usize` as we cannot allocate anything bigger anyway.
|
||||
let field_count = match val.ty.kind {
|
||||
ty::Array(_, len) => usize::try_from(len.eval_usize(tcx, param_env)).unwrap(),
|
||||
ty::Adt(def, _) => def.variants[variant].fields.len(),
|
||||
ty::Tuple(substs) => substs.len(),
|
||||
let (field_count, variant, down) = match val.ty.kind {
|
||||
ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
|
||||
ty::Adt(def, _) if def.variants.is_empty() => {
|
||||
return mir::DestructuredConst { variant: None, fields: tcx.arena.alloc_slice(&[]) };
|
||||
}
|
||||
ty::Adt(def, _) => {
|
||||
let variant = ecx.read_discriminant(op).unwrap().1;
|
||||
let down = ecx.operand_downcast(op, variant).unwrap();
|
||||
(def.variants[variant].fields.len(), Some(variant), down)
|
||||
}
|
||||
ty::Tuple(substs) => (substs.len(), None, op),
|
||||
_ => bug!("cannot destructure constant {:?}", val),
|
||||
};
|
||||
|
||||
let down = ecx.operand_downcast(op, variant).unwrap();
|
||||
let fields_iter = (0..field_count).map(|i| {
|
||||
let field_op = ecx.operand_field(down, i).unwrap();
|
||||
let val = op_to_const(&ecx, field_op);
|
||||
|
@ -32,13 +32,9 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
|
||||
|
||||
let mut result = match instance {
|
||||
ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
|
||||
ty::InstanceDef::VtableShim(def_id) => build_call_shim(
|
||||
tcx,
|
||||
instance,
|
||||
Some(Adjustment::DerefMove),
|
||||
CallKind::Direct(def_id),
|
||||
None,
|
||||
),
|
||||
ty::InstanceDef::VtableShim(def_id) => {
|
||||
build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None)
|
||||
}
|
||||
ty::InstanceDef::FnPtrShim(def_id, ty) => {
|
||||
// FIXME(eddyb) support generating shims for a "shallow type",
|
||||
// e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
|
||||
@ -60,7 +56,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
|
||||
let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
|
||||
let arg_tys = sig.inputs();
|
||||
|
||||
build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect, Some(arg_tys))
|
||||
build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty), Some(arg_tys))
|
||||
}
|
||||
// We are generating a call back to our def-id, which the
|
||||
// codegen backend knows to turn to an actual call, be it
|
||||
@ -134,15 +130,28 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum Adjustment {
|
||||
/// Pass the receiver as-is.
|
||||
Identity,
|
||||
|
||||
/// We get passed `&[mut] self` and call the target with `*self`.
|
||||
///
|
||||
/// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it
|
||||
/// (for `VtableShim`, which effectively is passed `&own Self`).
|
||||
Deref,
|
||||
DerefMove,
|
||||
|
||||
/// We get passed `self: Self` and call the target with `&mut self`.
|
||||
///
|
||||
/// In this case we need to ensure that the `Self` is dropped after the call, as the callee
|
||||
/// won't do it for us.
|
||||
RefMut,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum CallKind {
|
||||
Indirect,
|
||||
enum CallKind<'tcx> {
|
||||
/// Call the `FnPtr` that was passed as the receiver.
|
||||
Indirect(Ty<'tcx>),
|
||||
|
||||
/// Call a known `FnDef`.
|
||||
Direct(DefId),
|
||||
}
|
||||
|
||||
@ -662,7 +671,7 @@ fn build_call_shim<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: ty::InstanceDef<'tcx>,
|
||||
rcvr_adjustment: Option<Adjustment>,
|
||||
call_kind: CallKind,
|
||||
call_kind: CallKind<'tcx>,
|
||||
untuple_args: Option<&[Ty<'tcx>]>,
|
||||
) -> Body<'tcx> {
|
||||
debug!(
|
||||
@ -675,6 +684,29 @@ fn build_call_shim<'tcx>(
|
||||
let sig = tcx.fn_sig(def_id);
|
||||
let mut sig = tcx.erase_late_bound_regions(&sig);
|
||||
|
||||
if let CallKind::Indirect(fnty) = call_kind {
|
||||
// `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
|
||||
// can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from
|
||||
// the implemented `FnX` trait.
|
||||
|
||||
// Apply the opposite adjustment to the MIR input.
|
||||
let mut inputs_and_output = sig.inputs_and_output.to_vec();
|
||||
|
||||
// Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the
|
||||
// fn arguments. `Self` may be passed via (im)mutable reference or by-value.
|
||||
assert_eq!(inputs_and_output.len(), 3);
|
||||
|
||||
// `Self` is always the original fn type `ty`. The MIR call terminator is only defined for
|
||||
// `FnDef` and `FnPtr` callees, not the `Self` type param.
|
||||
let self_arg = &mut inputs_and_output[0];
|
||||
*self_arg = match rcvr_adjustment.unwrap() {
|
||||
Adjustment::Identity => fnty,
|
||||
Adjustment::Deref => tcx.mk_imm_ptr(fnty),
|
||||
Adjustment::RefMut => tcx.mk_mut_ptr(fnty),
|
||||
};
|
||||
sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
|
||||
}
|
||||
|
||||
// FIXME(eddyb) avoid having this snippet both here and in
|
||||
// `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
|
||||
if let ty::InstanceDef::VtableShim(..) = instance {
|
||||
@ -701,8 +733,7 @@ fn build_call_shim<'tcx>(
|
||||
|
||||
let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
|
||||
Adjustment::Identity => Operand::Move(rcvr_place()),
|
||||
Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())), // Can't copy `&mut`
|
||||
Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())),
|
||||
Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())),
|
||||
Adjustment::RefMut => {
|
||||
// let rcvr = &mut rcvr;
|
||||
let ref_rcvr = local_decls.push(
|
||||
@ -728,7 +759,10 @@ fn build_call_shim<'tcx>(
|
||||
});
|
||||
|
||||
let (callee, mut args) = match call_kind {
|
||||
CallKind::Indirect => (rcvr.unwrap(), vec![]),
|
||||
// `FnPtr` call has no receiver. Args are untupled below.
|
||||
CallKind::Indirect(_) => (rcvr.unwrap(), vec![]),
|
||||
|
||||
// `FnDef` call with optional receiver.
|
||||
CallKind::Direct(def_id) => {
|
||||
let ty = tcx.type_of(def_id);
|
||||
(
|
||||
|
@ -205,22 +205,34 @@ impl NonConstOp for CellBorrow {
|
||||
#[derive(Debug)]
|
||||
pub struct MutBorrow;
|
||||
impl NonConstOp for MutBorrow {
|
||||
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
|
||||
// Forbid everywhere except in const fn
|
||||
ccx.const_kind() == hir::ConstContext::ConstFn
|
||||
&& ccx.tcx.features().enabled(Self::feature_gate().unwrap())
|
||||
}
|
||||
|
||||
fn feature_gate() -> Option<Symbol> {
|
||||
Some(sym::const_mut_refs)
|
||||
}
|
||||
|
||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||
let mut err = feature_err(
|
||||
let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn {
|
||||
feature_err(
|
||||
&ccx.tcx.sess.parse_sess,
|
||||
sym::const_mut_refs,
|
||||
span,
|
||||
&format!(
|
||||
"references in {}s may only refer \
|
||||
to immutable values",
|
||||
ccx.const_kind()
|
||||
),
|
||||
);
|
||||
err.span_label(span, format!("{}s require immutable values", ccx.const_kind()));
|
||||
&format!("mutable references are not allowed in {}s", ccx.const_kind()),
|
||||
)
|
||||
} else {
|
||||
struct_span_err!(
|
||||
ccx.tcx.sess,
|
||||
span,
|
||||
E0764,
|
||||
"mutable references are not allowed in {}s",
|
||||
ccx.const_kind(),
|
||||
)
|
||||
};
|
||||
err.span_label(span, "`&mut` is only allowed in `const fn`".to_string());
|
||||
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"References in statics and constants may only refer \
|
||||
|
@ -9,7 +9,6 @@ use rustc_middle::mir::visit::*;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::subst::{Subst, SubstsRef};
|
||||
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_session::config::Sanitizer;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use super::simplify::{remove_dead_blocks, CfgSimplifier};
|
||||
@ -232,25 +231,9 @@ impl Inliner<'tcx> {
|
||||
|
||||
// Avoid inlining functions marked as no_sanitize if sanitizer is enabled,
|
||||
// since instrumentation might be enabled and performed on the caller.
|
||||
match self.tcx.sess.opts.debugging_opts.sanitizer {
|
||||
Some(Sanitizer::Address) => {
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
|
||||
if self.tcx.sess.opts.debugging_opts.sanitizer.intersects(codegen_fn_attrs.no_sanitize) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Some(Sanitizer::Memory) => {
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Some(Sanitizer::Thread) => {
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Some(Sanitizer::Leak) => {}
|
||||
None => {}
|
||||
}
|
||||
|
||||
let hinted = match codegen_fn_attrs.inline {
|
||||
// Just treat inline(always) as a hint for now,
|
||||
|
@ -9,7 +9,6 @@ use rustc_middle::{
|
||||
},
|
||||
ty::{self, ParamEnv, TyCtxt},
|
||||
};
|
||||
use rustc_span::def_id::DefId;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum EdgeKind {
|
||||
@ -24,15 +23,14 @@ pub struct Validator {
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for Validator {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
|
||||
let def_id = source.def_id();
|
||||
let param_env = tcx.param_env(def_id);
|
||||
TypeChecker { when: &self.when, def_id, body, tcx, param_env }.visit_body(body);
|
||||
let param_env = tcx.param_env(source.def_id());
|
||||
TypeChecker { when: &self.when, source, body, tcx, param_env }.visit_body(body);
|
||||
}
|
||||
}
|
||||
|
||||
struct TypeChecker<'a, 'tcx> {
|
||||
when: &'a str,
|
||||
def_id: DefId,
|
||||
source: MirSource<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
@ -47,7 +45,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
span,
|
||||
&format!(
|
||||
"broken MIR in {:?} ({}) at {:?}:\n{}",
|
||||
self.def_id,
|
||||
self.source.instance,
|
||||
self.when,
|
||||
location,
|
||||
msg.as_ref()
|
||||
|
@ -800,7 +800,11 @@ impl<'tcx> Constructor<'tcx> {
|
||||
assert!(!adt.is_enum());
|
||||
VariantIdx::new(0)
|
||||
}
|
||||
ConstantValue(c) => cx.tcx.destructure_const(cx.param_env.and(c)).variant,
|
||||
ConstantValue(c) => cx
|
||||
.tcx
|
||||
.destructure_const(cx.param_env.and(c))
|
||||
.variant
|
||||
.expect("destructed const of adt without variant id"),
|
||||
_ => bug!("bad constructor {:?} for adt {:?}", self, adt),
|
||||
}
|
||||
}
|
||||
|
@ -275,7 +275,9 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
||||
PatKind::Variant {
|
||||
adt_def,
|
||||
substs,
|
||||
variant_index: destructured.variant,
|
||||
variant_index: destructured
|
||||
.variant
|
||||
.expect("destructed const of adt without variant id"),
|
||||
subpatterns: field_pats(destructured.fields),
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ name = "rustc_session"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.2.1"
|
||||
getopts = "0.2"
|
||||
log = "0.4"
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
|
@ -10,6 +10,7 @@ use crate::{early_error, early_warn, Session};
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::impl_stable_hash_via_hash;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
|
||||
use rustc_target::spec::{Target, TargetTriple};
|
||||
|
||||
@ -37,35 +38,55 @@ pub struct Config {
|
||||
pub ptr_width: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Sanitizer {
|
||||
Address,
|
||||
Leak,
|
||||
Memory,
|
||||
Thread,
|
||||
bitflags! {
|
||||
#[derive(Default, RustcEncodable, RustcDecodable)]
|
||||
pub struct SanitizerSet: u8 {
|
||||
const ADDRESS = 1 << 0;
|
||||
const LEAK = 1 << 1;
|
||||
const MEMORY = 1 << 2;
|
||||
const THREAD = 1 << 3;
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Sanitizer {
|
||||
/// Formats a sanitizer set as a comma separated list of sanitizers' names.
|
||||
impl fmt::Display for SanitizerSet {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Sanitizer::Address => "address".fmt(f),
|
||||
Sanitizer::Leak => "leak".fmt(f),
|
||||
Sanitizer::Memory => "memory".fmt(f),
|
||||
Sanitizer::Thread => "thread".fmt(f),
|
||||
let mut first = true;
|
||||
for s in *self {
|
||||
let name = match s {
|
||||
SanitizerSet::ADDRESS => "address",
|
||||
SanitizerSet::LEAK => "leak",
|
||||
SanitizerSet::MEMORY => "memory",
|
||||
SanitizerSet::THREAD => "thread",
|
||||
_ => panic!("unrecognized sanitizer {:?}", s),
|
||||
};
|
||||
if !first {
|
||||
f.write_str(",")?;
|
||||
}
|
||||
f.write_str(name)?;
|
||||
first = false;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Sanitizer {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Sanitizer, ()> {
|
||||
match s {
|
||||
"address" => Ok(Sanitizer::Address),
|
||||
"leak" => Ok(Sanitizer::Leak),
|
||||
"memory" => Ok(Sanitizer::Memory),
|
||||
"thread" => Ok(Sanitizer::Thread),
|
||||
_ => Err(()),
|
||||
impl IntoIterator for SanitizerSet {
|
||||
type Item = SanitizerSet;
|
||||
type IntoIter = std::vec::IntoIter<SanitizerSet>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
[SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|&s| self.contains(s))
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for SanitizerSet {
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.bits().hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
@ -726,10 +747,12 @@ pub fn default_configuration(sess: &Session) -> CrateConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(s) = &sess.opts.debugging_opts.sanitizer {
|
||||
|
||||
for s in sess.opts.debugging_opts.sanitizer {
|
||||
let symbol = Symbol::intern(&s.to_string());
|
||||
ret.insert((sym::sanitize, Some(symbol)));
|
||||
}
|
||||
|
||||
if sess.opts.debug_assertions {
|
||||
ret.insert((Symbol::intern("debug_assertions"), None));
|
||||
}
|
||||
@ -1995,7 +2018,7 @@ impl PpMode {
|
||||
crate mod dep_tracking {
|
||||
use super::{
|
||||
CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
|
||||
OutputTypes, Passes, Sanitizer, SourceFileHashAlgorithm, SwitchWithOptPath,
|
||||
OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath,
|
||||
SymbolManglingVersion,
|
||||
};
|
||||
use crate::lint;
|
||||
@ -2069,8 +2092,7 @@ crate mod dep_tracking {
|
||||
impl_dep_tracking_hash_via_hash!(UnstableFeatures);
|
||||
impl_dep_tracking_hash_via_hash!(OutputTypes);
|
||||
impl_dep_tracking_hash_via_hash!(NativeLibKind);
|
||||
impl_dep_tracking_hash_via_hash!(Sanitizer);
|
||||
impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
|
||||
impl_dep_tracking_hash_via_hash!(SanitizerSet);
|
||||
impl_dep_tracking_hash_via_hash!(CFGuard);
|
||||
impl_dep_tracking_hash_via_hash!(TargetTriple);
|
||||
impl_dep_tracking_hash_via_hash!(Edition);
|
||||
@ -2085,7 +2107,6 @@ crate mod dep_tracking {
|
||||
impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
|
||||
impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
|
||||
impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
|
||||
impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
|
||||
|
||||
impl<T1, T2> DepTrackingHash for (T1, T2)
|
||||
where
|
||||
|
@ -1,6 +1,9 @@
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(or_patterns)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
||||
pub mod cgu_reuse_tracker;
|
||||
pub mod utils;
|
||||
#[macro_use]
|
||||
|
@ -248,8 +248,7 @@ macro_rules! options {
|
||||
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
|
||||
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
|
||||
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
|
||||
pub const parse_sanitizer: &str = "one of: `address`, `leak`, `memory` or `thread`";
|
||||
pub const parse_sanitizer_list: &str = "comma separated list of sanitizers";
|
||||
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `leak`, `memory` or `thread`";
|
||||
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
|
||||
pub const parse_cfguard: &str = "either `disabled`, `nochecks`, or `checks`";
|
||||
pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
|
||||
@ -459,24 +458,15 @@ macro_rules! options {
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
|
||||
if let Some(Ok(s)) = v.map(str::parse) {
|
||||
*slot = Some(s);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool {
|
||||
fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
|
||||
if let Some(v) = v {
|
||||
for s in v.split(',').map(str::parse) {
|
||||
if let Ok(s) = s {
|
||||
if !slot.contains(&s) {
|
||||
slot.push(s);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
for s in v.split(',') {
|
||||
*slot |= match s {
|
||||
"address" => SanitizerSet::ADDRESS,
|
||||
"leak" => SanitizerSet::LEAK,
|
||||
"memory" => SanitizerSet::MEMORY,
|
||||
"thread" => SanitizerSet::THREAD,
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
true
|
||||
@ -974,11 +964,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
// soon.
|
||||
run_dsymutil: bool = (true, parse_bool, [TRACKED],
|
||||
"if on Mac, run `dsymutil` and delete intermediate object files (default: yes)"),
|
||||
sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
|
||||
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
||||
"use a sanitizer"),
|
||||
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
|
||||
"enable origins tracking in MemorySanitizer"),
|
||||
sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
|
||||
sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
||||
"enable recovery for selected sanitizers"),
|
||||
saturating_float_casts: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"make float->int casts UB-free: numbers outside the integer type's range are clipped to \
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::cgu_reuse_tracker::CguReuseTracker;
|
||||
use crate::code_stats::CodeStats;
|
||||
pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
|
||||
use crate::config::{self, CrateType, OutputType, PrintRequest, Sanitizer, SwitchWithOptPath};
|
||||
use crate::config::{self, CrateType, OutputType, PrintRequest, SanitizerSet, SwitchWithOptPath};
|
||||
use crate::filesearch;
|
||||
use crate::lint;
|
||||
use crate::parse::ParseSess;
|
||||
@ -650,14 +650,9 @@ impl Session {
|
||||
}
|
||||
pub fn fewer_names(&self) -> bool {
|
||||
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
|
||||
|| self.opts.output_types.contains_key(&OutputType::Bitcode);
|
||||
|
||||
// Address sanitizer and memory sanitizer use alloca name when reporting an issue.
|
||||
let more_names = match self.opts.debugging_opts.sanitizer {
|
||||
Some(Sanitizer::Address) => true,
|
||||
Some(Sanitizer::Memory) => true,
|
||||
_ => more_names,
|
||||
};
|
||||
|| self.opts.output_types.contains_key(&OutputType::Bitcode)
|
||||
// AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
|
||||
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
|
||||
|
||||
self.opts.debugging_opts.fewer_names || !more_names
|
||||
}
|
||||
@ -1020,12 +1015,10 @@ impl Session {
|
||||
|
||||
/// Checks if LLVM lifetime markers should be emitted.
|
||||
pub fn emit_lifetime_markers(&self) -> bool {
|
||||
match self.opts.debugging_opts.sanitizer {
|
||||
self.opts.optimize != config::OptLevel::No
|
||||
// AddressSanitizer uses lifetimes to detect use after scope bugs.
|
||||
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
|
||||
Some(Sanitizer::Address | Sanitizer::Memory) => true,
|
||||
_ => self.opts.optimize != config::OptLevel::No,
|
||||
}
|
||||
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1356,34 +1349,37 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
||||
);
|
||||
}
|
||||
|
||||
// Sanitizers can only be used on some tested platforms.
|
||||
if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
|
||||
const ASAN_SUPPORTED_TARGETS: &[&str] = &[
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"x86_64-apple-darwin",
|
||||
"x86_64-fuchsia",
|
||||
"aarch64-fuchsia",
|
||||
];
|
||||
const TSAN_SUPPORTED_TARGETS: &[&str] =
|
||||
&["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
|
||||
const LSAN_SUPPORTED_TARGETS: &[&str] =
|
||||
&["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
|
||||
const ASAN_SUPPORTED_TARGETS: &[&str] =
|
||||
&["aarch64-fuchsia", "x86_64-apple-darwin", "x86_64-fuchsia", "x86_64-unknown-linux-gnu"];
|
||||
const LSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
|
||||
const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
|
||||
const TSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
|
||||
|
||||
let supported_targets = match *sanitizer {
|
||||
Sanitizer::Address => ASAN_SUPPORTED_TARGETS,
|
||||
Sanitizer::Thread => TSAN_SUPPORTED_TARGETS,
|
||||
Sanitizer::Leak => LSAN_SUPPORTED_TARGETS,
|
||||
Sanitizer::Memory => MSAN_SUPPORTED_TARGETS,
|
||||
// Sanitizers can only be used on some tested platforms.
|
||||
for s in sess.opts.debugging_opts.sanitizer {
|
||||
let supported_targets = match s {
|
||||
SanitizerSet::ADDRESS => ASAN_SUPPORTED_TARGETS,
|
||||
SanitizerSet::LEAK => LSAN_SUPPORTED_TARGETS,
|
||||
SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS,
|
||||
SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS,
|
||||
_ => panic!("unrecognized sanitizer {}", s),
|
||||
};
|
||||
|
||||
if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
|
||||
sess.err(&format!(
|
||||
"{:?}Sanitizer only works with the `{}` target",
|
||||
sanitizer,
|
||||
supported_targets.join("` or `")
|
||||
"`-Zsanitizer={}` only works with targets: {}",
|
||||
s,
|
||||
supported_targets.join(", ")
|
||||
));
|
||||
}
|
||||
let conflicting = sess.opts.debugging_opts.sanitizer - s;
|
||||
if !conflicting.is_empty() {
|
||||
sess.err(&format!(
|
||||
"`-Zsanitizer={}` is incompatible with `-Zsanitizer={}`",
|
||||
s, conflicting,
|
||||
));
|
||||
// Don't report additional errors.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem};
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
@ -1146,7 +1147,7 @@ fn confirm_candidate<'cx, 'tcx>(
|
||||
) -> Progress<'tcx> {
|
||||
debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
|
||||
|
||||
match candidate {
|
||||
let mut progress = match candidate {
|
||||
ProjectionTyCandidate::ParamEnv(poly_projection)
|
||||
| ProjectionTyCandidate::TraitDef(poly_projection) => {
|
||||
confirm_param_env_candidate(selcx, obligation, poly_projection)
|
||||
@ -1155,7 +1156,16 @@ fn confirm_candidate<'cx, 'tcx>(
|
||||
ProjectionTyCandidate::Select(impl_source) => {
|
||||
confirm_select_candidate(selcx, obligation, obligation_trait_ref, impl_source)
|
||||
}
|
||||
};
|
||||
// When checking for cycle during evaluation, we compare predicates with
|
||||
// "syntactic" equality. Since normalization generally introduces a type
|
||||
// with new region variables, we need to resolve them to existing variables
|
||||
// when possible for this to work. See `auto-trait-projection-recursion.rs`
|
||||
// for a case where this matters.
|
||||
if progress.ty.has_infer_regions() {
|
||||
progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty);
|
||||
}
|
||||
progress
|
||||
}
|
||||
|
||||
fn confirm_select_candidate<'cx, 'tcx>(
|
||||
|
@ -302,7 +302,7 @@ pub fn get_vtable_index_of_object_method<N>(
|
||||
) -> usize {
|
||||
// Count number of methods preceding the one we are selecting and
|
||||
// add them to the total offset.
|
||||
// Skip over associated types and constants.
|
||||
// Skip over associated types and constants, as those aren't stored in the vtable.
|
||||
let mut entries = object.vtable_base;
|
||||
for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() {
|
||||
if trait_item.def_id == method_def_id {
|
||||
|
@ -2787,7 +2787,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
hir::PrimTy::Int(it) => tcx.mk_mach_int(it),
|
||||
hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit),
|
||||
hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft),
|
||||
hir::PrimTy::Str => tcx.mk_str(),
|
||||
hir::PrimTy::Str => tcx.types.str_,
|
||||
}
|
||||
}
|
||||
Res::Err => {
|
||||
|
@ -10,45 +10,30 @@
|
||||
//!
|
||||
//! Note that if we are expecting a reference, we will *reborrow*
|
||||
//! even if the argument provided was already a reference. This is
|
||||
//! useful for freezing mut/const things (that is, when the expected is &T
|
||||
//! but you have &const T or &mut T) and also for avoiding the linearity
|
||||
//! useful for freezing mut things (that is, when the expected type is &T
|
||||
//! but you have &mut T) and also for avoiding the linearity
|
||||
//! of mut things (when the expected is &mut T and you have &mut T). See
|
||||
//! the various `src/test/ui/coerce-reborrow-*.rs` tests for
|
||||
//! the various `src/test/ui/coerce/*.rs` tests for
|
||||
//! examples of where this is useful.
|
||||
//!
|
||||
//! ## Subtle note
|
||||
//!
|
||||
//! When deciding what type coercions to consider, we do not attempt to
|
||||
//! resolve any type variables we may encounter. This is because `b`
|
||||
//! represents the expected type "as the user wrote it", meaning that if
|
||||
//! the user defined a generic function like
|
||||
//! When infering the generic arguments of functions, the argument
|
||||
//! order is relevant, which can lead to the following edge case:
|
||||
//!
|
||||
//! fn foo<A>(a: A, b: A) { ... }
|
||||
//! ```rust
|
||||
//! fn foo<T>(a: T, b: T) {
|
||||
//! // ...
|
||||
//! }
|
||||
//!
|
||||
//! and then we wrote `foo(&1, @2)`, we will not auto-borrow
|
||||
//! either argument. In older code we went to some lengths to
|
||||
//! resolve the `b` variable, which could mean that we'd
|
||||
//! auto-borrow later arguments but not earlier ones, which
|
||||
//! seems very confusing.
|
||||
//! foo(&7i32, &mut 7i32);
|
||||
//! // This compiles, as we first infer `T` to be `&i32`,
|
||||
//! // and then coerce `&mut 7i32` to `&7i32`.
|
||||
//!
|
||||
//! ## Subtler note
|
||||
//!
|
||||
//! However, right now, if the user manually specifies the
|
||||
//! values for the type variables, as so:
|
||||
//!
|
||||
//! foo::<&int>(@1, @2)
|
||||
//!
|
||||
//! then we *will* auto-borrow, because we can't distinguish this from a
|
||||
//! function that declared `&int`. This is inconsistent but it's easiest
|
||||
//! at the moment. The right thing to do, I think, is to consider the
|
||||
//! *unsubstituted* type when deciding whether to auto-borrow, but the
|
||||
//! *substituted* type when considering the bounds and so forth. But most
|
||||
//! of our methods don't give access to the unsubstituted type, and
|
||||
//! rightly so because they'd be error-prone. So maybe the thing to do is
|
||||
//! to actually determine the kind of coercions that should occur
|
||||
//! separately and pass them in. Or maybe it's ok as is. Anyway, it's
|
||||
//! sort of a minor point so I've opted to leave it for later -- after all,
|
||||
//! we may want to adjust precisely when coercions occur.
|
||||
//! foo(&mut 7i32, &7i32);
|
||||
//! // This does not compile, as we first infer `T` to be `&mut i32`
|
||||
//! // and are then unable to coerce `&7i32` to `&mut i32`.
|
||||
//! ```
|
||||
|
||||
use crate::astconv::AstConv;
|
||||
use crate::check::FnCtxt;
|
||||
@ -96,6 +81,8 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> {
|
||||
|
||||
type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
|
||||
|
||||
/// Coercing a mutable reference to an immutable works, while
|
||||
/// coercing `&T` to `&mut T` should be forbidden.
|
||||
fn coerce_mutbls<'tcx>(
|
||||
from_mutbl: hir::Mutability,
|
||||
to_mutbl: hir::Mutability,
|
||||
|
@ -40,6 +40,7 @@ use rustc_middle::ty::util::Discr;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
|
||||
use rustc_session::config::SanitizerSet;
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
@ -2450,11 +2451,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
||||
if let Some(list) = attr.meta_item_list() {
|
||||
for item in list.iter() {
|
||||
if item.check_name(sym::address) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_ADDRESS;
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
|
||||
} else if item.check_name(sym::memory) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_MEMORY;
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
|
||||
} else if item.check_name(sym::thread) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_THREAD;
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
|
||||
} else {
|
||||
tcx.sess
|
||||
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
|
||||
@ -2554,7 +2555,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
||||
}
|
||||
}
|
||||
|
||||
if codegen_fn_attrs.flags.intersects(CodegenFnAttrFlags::NO_SANITIZE_ANY) {
|
||||
if !codegen_fn_attrs.no_sanitize.is_empty() {
|
||||
if codegen_fn_attrs.inline == InlineAttr::Always {
|
||||
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
|
||||
let hir_id = tcx.hir().as_local_hir_id(id.expect_local());
|
||||
|
@ -10,22 +10,6 @@
|
||||
//! things, particularly traits, which are used in almost every single Rust
|
||||
//! program.
|
||||
//!
|
||||
//! On a technical level, Rust inserts
|
||||
//!
|
||||
//! ```
|
||||
//! # #[allow(unused_extern_crates)]
|
||||
//! extern crate std;
|
||||
//! ```
|
||||
//!
|
||||
//! into the crate root of every crate, and
|
||||
//!
|
||||
//! ```
|
||||
//! # #[allow(unused_imports)]
|
||||
//! use std::prelude::v1::*;
|
||||
//! ```
|
||||
//!
|
||||
//! into every module.
|
||||
//!
|
||||
//! # Other preludes
|
||||
//!
|
||||
//! Preludes can be seen as a pattern to make using multiple types more
|
||||
|
@ -717,11 +717,12 @@ enum class LLVMRustOptStage {
|
||||
};
|
||||
|
||||
struct LLVMRustSanitizerOptions {
|
||||
bool SanitizeMemory;
|
||||
bool SanitizeThread;
|
||||
bool SanitizeAddress;
|
||||
bool SanitizeRecover;
|
||||
bool SanitizeAddressRecover;
|
||||
bool SanitizeMemory;
|
||||
bool SanitizeMemoryRecover;
|
||||
int SanitizeMemoryTrackOrigins;
|
||||
bool SanitizeThread;
|
||||
};
|
||||
|
||||
extern "C" void
|
||||
@ -808,7 +809,7 @@ LLVMRustOptimizeWithNewPassManager(
|
||||
if (SanitizerOptions->SanitizeMemory) {
|
||||
MemorySanitizerOptions Options(
|
||||
SanitizerOptions->SanitizeMemoryTrackOrigins,
|
||||
SanitizerOptions->SanitizeRecover,
|
||||
SanitizerOptions->SanitizeMemoryRecover,
|
||||
/*CompileKernel=*/false);
|
||||
#if LLVM_VERSION_GE(10, 0)
|
||||
PipelineStartEPCallbacks.push_back([Options](ModulePassManager &MPM) {
|
||||
@ -842,14 +843,14 @@ LLVMRustOptimizeWithNewPassManager(
|
||||
OptimizerLastEPCallbacks.push_back(
|
||||
[SanitizerOptions](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
|
||||
FPM.addPass(AddressSanitizerPass(
|
||||
/*CompileKernel=*/false, SanitizerOptions->SanitizeRecover,
|
||||
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
|
||||
/*UseAfterScope=*/true));
|
||||
}
|
||||
);
|
||||
PipelineStartEPCallbacks.push_back(
|
||||
[SanitizerOptions](ModulePassManager &MPM) {
|
||||
MPM.addPass(ModuleAddressSanitizerPass(
|
||||
/*CompileKernel=*/false, SanitizerOptions->SanitizeRecover));
|
||||
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ fn main() {
|
||||
[(); { for _ in 0usize.. {}; 0}];
|
||||
//~^ ERROR `for` is not allowed in a `const`
|
||||
//~| ERROR calls in constants are limited to constant functions
|
||||
//~| ERROR references in constants may only refer to immutable values
|
||||
//~| ERROR mutable references are not allowed in constants
|
||||
//~| ERROR calls in constants are limited to constant functions
|
||||
//~| ERROR evaluation of constant value failed
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// compile-fail
|
||||
|
||||
#![feature(specialization)]
|
||||
//~^ WARN the feature `specialization` is incomplete
|
||||
|
||||
pub trait Foo {
|
||||
fn foo();
|
||||
|
15
src/test/mir-opt/fn-ptr-shim.rs
Normal file
15
src/test/mir-opt/fn-ptr-shim.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// compile-flags: -Zmir-opt-level=0 -Zvalidate-mir
|
||||
|
||||
// Tests that the `<fn() as Fn>` shim does not create a `Call` terminator with a `Self` callee
|
||||
// (as only `FnDef` and `FnPtr` callees are allowed in MIR).
|
||||
|
||||
// EMIT_MIR rustc.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
|
||||
fn main() {
|
||||
call(noop as fn());
|
||||
}
|
||||
|
||||
fn noop() {}
|
||||
|
||||
fn call<F: Fn()>(f: F) {
|
||||
f();
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
// MIR for `std::ops::Fn::call` before AddMovesForPackedDrops
|
||||
|
||||
fn std::ops::Fn::call(_1: *const fn(), _2: Args) -> <Self as std::ops::FnOnce<Args>>::Output {
|
||||
let mut _0: <Self as std::ops::FnOnce<Args>>::Output; // return place in scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL
|
||||
|
||||
bb0: {
|
||||
_0 = move (*_1)() -> bb1; // scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL
|
||||
}
|
||||
|
||||
bb1: {
|
||||
return; // scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL
|
||||
}
|
||||
}
|
21
src/test/mir-opt/issue-72181-1.rs
Normal file
21
src/test/mir-opt/issue-72181-1.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// compile-flags: -Z mir-opt-level=1
|
||||
// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags.
|
||||
|
||||
#![feature(never_type)]
|
||||
#![allow(unused, invalid_value)]
|
||||
|
||||
enum Void {}
|
||||
|
||||
// EMIT_MIR rustc.f.mir_map.0.mir
|
||||
fn f(v: Void) -> ! {
|
||||
match v {}
|
||||
}
|
||||
|
||||
// EMIT_MIR rustc.main.mir_map.0.mir
|
||||
fn main() {
|
||||
let v: Void = unsafe {
|
||||
std::mem::transmute::<(), Void>(())
|
||||
};
|
||||
|
||||
f(v);
|
||||
}
|
37
src/test/mir-opt/issue-72181-1/rustc.f.mir_map.0.mir
Normal file
37
src/test/mir-opt/issue-72181-1/rustc.f.mir_map.0.mir
Normal file
@ -0,0 +1,37 @@
|
||||
// MIR for `f` 0 mir_map
|
||||
|
||||
fn f(_1: Void) -> ! {
|
||||
debug v => _1; // in scope 0 at $DIR/issue-72181-1.rs:10:6: 10:7
|
||||
let mut _0: !; // return place in scope 0 at $DIR/issue-72181-1.rs:10:18: 10:19
|
||||
let mut _2: !; // in scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
|
||||
let mut _3: !; // in scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
|
||||
StorageLive(_3); // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
|
||||
FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12
|
||||
unreachable; // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181-1.rs:10:1: 12:2
|
||||
}
|
||||
|
||||
bb2: {
|
||||
unreachable; // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_3); // scope 0 at $DIR/issue-72181-1.rs:11:14: 11:15
|
||||
unreachable; // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:12:1: 12:2
|
||||
goto -> bb5; // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2
|
||||
}
|
||||
|
||||
bb5: {
|
||||
return; // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2
|
||||
}
|
||||
}
|
67
src/test/mir-opt/issue-72181-1/rustc.main.mir_map.0.mir
Normal file
67
src/test/mir-opt/issue-72181-1/rustc.main.mir_map.0.mir
Normal file
@ -0,0 +1,67 @@
|
||||
// MIR for `main` 0 mir_map
|
||||
|
||||
| User Type Annotations
|
||||
| 0: Canonical { max_universe: U0, variables: [], value: Ty(Void) } at $DIR/issue-72181-1.rs:16:12: 16:16
|
||||
| 1: Canonical { max_universe: U0, variables: [], value: Ty(Void) } at $DIR/issue-72181-1.rs:16:12: 16:16
|
||||
|
|
||||
fn main() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/issue-72181-1.rs:15:11: 15:11
|
||||
let mut _1: !; // in scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2
|
||||
let _2: Void as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
|
||||
let mut _3: (); // in scope 0 at $DIR/issue-72181-1.rs:17:41: 17:43
|
||||
let _4: !; // in scope 0 at $DIR/issue-72181-1.rs:20:5: 20:9
|
||||
let mut _5: Void; // in scope 0 at $DIR/issue-72181-1.rs:20:7: 20:8
|
||||
scope 1 {
|
||||
debug v => _2; // in scope 1 at $DIR/issue-72181-1.rs:16:9: 16:10
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
|
||||
StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
|
||||
_3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
|
||||
_2 = const std::intrinsics::transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
|
||||
// ty::Const
|
||||
// + ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181-1.rs:17:9: 17:40
|
||||
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181-1.rs:15:1: 21:2
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_3); // scope 2 at $DIR/issue-72181-1.rs:17:43: 17:44
|
||||
FakeRead(ForLet, _2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
|
||||
AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-72181-1.rs:16:12: 16:16
|
||||
StorageLive(_4); // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
|
||||
StorageLive(_5); // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8
|
||||
_5 = move _2; // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8
|
||||
const f(move _5) -> bb1; // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
|
||||
// ty::Const
|
||||
// + ty: fn(Void) -> ! {f}
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181-1.rs:20:5: 20:6
|
||||
// + literal: Const { ty: fn(Void) -> ! {f}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_5); // scope 1 at $DIR/issue-72181-1.rs:20:8: 20:9
|
||||
StorageDead(_4); // scope 1 at $DIR/issue-72181-1.rs:20:9: 20:10
|
||||
StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:21:1: 21:2
|
||||
unreachable; // scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2
|
||||
}
|
||||
|
||||
bb4: {
|
||||
goto -> bb5; // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2
|
||||
}
|
||||
|
||||
bb5: {
|
||||
return; // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2
|
||||
}
|
||||
}
|
28
src/test/mir-opt/issue-72181.rs
Normal file
28
src/test/mir-opt/issue-72181.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// compile-flags: -Z mir-opt-level=1
|
||||
// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags.
|
||||
|
||||
use std::mem;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Never {}
|
||||
|
||||
union Foo {
|
||||
a: u64,
|
||||
b: Never
|
||||
}
|
||||
|
||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||
// EMIT_MIR rustc.foo.mir_map.0.mir
|
||||
fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 }
|
||||
|
||||
// EMIT_MIR rustc.bar.mir_map.0.mir
|
||||
fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x }
|
||||
|
||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||
// EMIT_MIR rustc.main.mir_map.0.mir
|
||||
fn main() {
|
||||
let _ = mem::size_of::<Foo>();
|
||||
|
||||
let f = [Foo { a: 42 }, Foo { a: 10 }];
|
||||
let _ = unsafe { f[0].a };
|
||||
}
|
25
src/test/mir-opt/issue-72181/32bit/rustc.bar.mir_map.0.mir
Normal file
25
src/test/mir-opt/issue-72181/32bit/rustc.bar.mir_map.0.mir
Normal file
@ -0,0 +1,25 @@
|
||||
// MIR for `bar` 0 mir_map
|
||||
|
||||
fn bar(_1: [(Never, u32); 1]) -> u32 {
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:19:40: 19:43
|
||||
let _2: u32; // in scope 0 at $DIR/issue-72181.rs:19:13: 19:14
|
||||
scope 1 {
|
||||
debug x => _2; // in scope 1 at $DIR/issue-72181.rs:19:13: 19:14
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
|
||||
_2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
|
||||
_0 = _2; // scope 1 at $DIR/issue-72181.rs:19:46: 19:47
|
||||
StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:19:48: 19:49
|
||||
goto -> bb2; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181.rs:19:1: 19:49
|
||||
}
|
||||
|
||||
bb2: {
|
||||
return; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
|
||||
}
|
||||
}
|
37
src/test/mir-opt/issue-72181/32bit/rustc.foo.mir_map.0.mir
Normal file
37
src/test/mir-opt/issue-72181/32bit/rustc.foo.mir_map.0.mir
Normal file
@ -0,0 +1,37 @@
|
||||
// MIR for `foo` 0 mir_map
|
||||
|
||||
fn foo(_1: [(Never, u32); 1]) -> u32 {
|
||||
debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:16:8: 16:10
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:16:34: 16:37
|
||||
let _2: usize; // in scope 0 at $DIR/issue-72181.rs:16:43: 16:44
|
||||
let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
|
||||
let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
|
||||
_2 = const 0usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
|
||||
// ty::Const
|
||||
// + ty: usize
|
||||
// + val: Value(Scalar(0x00000000))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:16:43: 16:44
|
||||
// + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) }
|
||||
_3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
|
||||
_4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
|
||||
assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181.rs:16:1: 16:49
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:16:40: 16:47
|
||||
StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:16:48: 16:49
|
||||
goto -> bb3; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
|
||||
}
|
||||
|
||||
bb3: {
|
||||
return; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
|
||||
}
|
||||
}
|
93
src/test/mir-opt/issue-72181/32bit/rustc.main.mir_map.0.mir
Normal file
93
src/test/mir-opt/issue-72181/32bit/rustc.main.mir_map.0.mir
Normal file
@ -0,0 +1,93 @@
|
||||
// MIR for `main` 0 mir_map
|
||||
|
||||
fn main() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:23:11: 23:11
|
||||
let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:24:13: 24:34
|
||||
let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:26:14: 26:27
|
||||
let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:26:29: 26:42
|
||||
let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:27:13: 27:30
|
||||
let _6: usize; // in scope 0 at $DIR/issue-72181.rs:27:24: 27:25
|
||||
let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
|
||||
let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
|
||||
scope 1 {
|
||||
let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
scope 2 {
|
||||
debug f => _2; // in scope 2 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
scope 3 {
|
||||
}
|
||||
scope 4 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
|
||||
_1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
|
||||
// ty::Const
|
||||
// + ty: fn() -> usize {std::mem::size_of::<Foo>}
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:24:13: 24:32
|
||||
// + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181.rs:23:1: 28:2
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:24:34: 24:35
|
||||
StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
|
||||
_3 = Foo { a: const 42u64 }; // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
|
||||
// ty::Const
|
||||
// + ty: u64
|
||||
// + val: Value(Scalar(0x000000000000002a))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:26:23: 26:25
|
||||
// + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) }
|
||||
StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
|
||||
_4 = Foo { a: const 10u64 }; // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
|
||||
// ty::Const
|
||||
// + ty: u64
|
||||
// + val: Value(Scalar(0x000000000000000a))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:26:38: 26:40
|
||||
// + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) }
|
||||
_2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43
|
||||
StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
|
||||
StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
|
||||
FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30
|
||||
StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
|
||||
_6 = const 0usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
|
||||
// ty::Const
|
||||
// + ty: usize
|
||||
// + val: Value(Scalar(0x00000000))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:27:24: 27:25
|
||||
// + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) }
|
||||
_7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
|
||||
_8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
|
||||
assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:27:22: 27:28
|
||||
StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
|
||||
StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
|
||||
_0 = const (); // scope 0 at $DIR/issue-72181.rs:23:11: 28:2
|
||||
// ty::Const
|
||||
// + ty: ()
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:23:11: 28:2
|
||||
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
|
||||
StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:28:1: 28:2
|
||||
goto -> bb4; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
|
||||
}
|
||||
|
||||
bb4: {
|
||||
return; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
|
||||
}
|
||||
}
|
25
src/test/mir-opt/issue-72181/64bit/rustc.bar.mir_map.0.mir
Normal file
25
src/test/mir-opt/issue-72181/64bit/rustc.bar.mir_map.0.mir
Normal file
@ -0,0 +1,25 @@
|
||||
// MIR for `bar` 0 mir_map
|
||||
|
||||
fn bar(_1: [(Never, u32); 1]) -> u32 {
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:19:40: 19:43
|
||||
let _2: u32; // in scope 0 at $DIR/issue-72181.rs:19:13: 19:14
|
||||
scope 1 {
|
||||
debug x => _2; // in scope 1 at $DIR/issue-72181.rs:19:13: 19:14
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
|
||||
_2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
|
||||
_0 = _2; // scope 1 at $DIR/issue-72181.rs:19:46: 19:47
|
||||
StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:19:48: 19:49
|
||||
goto -> bb2; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181.rs:19:1: 19:49
|
||||
}
|
||||
|
||||
bb2: {
|
||||
return; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
|
||||
}
|
||||
}
|
37
src/test/mir-opt/issue-72181/64bit/rustc.foo.mir_map.0.mir
Normal file
37
src/test/mir-opt/issue-72181/64bit/rustc.foo.mir_map.0.mir
Normal file
@ -0,0 +1,37 @@
|
||||
// MIR for `foo` 0 mir_map
|
||||
|
||||
fn foo(_1: [(Never, u32); 1]) -> u32 {
|
||||
debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:16:8: 16:10
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:16:34: 16:37
|
||||
let _2: usize; // in scope 0 at $DIR/issue-72181.rs:16:43: 16:44
|
||||
let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
|
||||
let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
|
||||
_2 = const 0usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
|
||||
// ty::Const
|
||||
// + ty: usize
|
||||
// + val: Value(Scalar(0x0000000000000000))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:16:43: 16:44
|
||||
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
|
||||
_3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
|
||||
_4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
|
||||
assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181.rs:16:1: 16:49
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:16:40: 16:47
|
||||
StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:16:48: 16:49
|
||||
goto -> bb3; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
|
||||
}
|
||||
|
||||
bb3: {
|
||||
return; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
|
||||
}
|
||||
}
|
93
src/test/mir-opt/issue-72181/64bit/rustc.main.mir_map.0.mir
Normal file
93
src/test/mir-opt/issue-72181/64bit/rustc.main.mir_map.0.mir
Normal file
@ -0,0 +1,93 @@
|
||||
// MIR for `main` 0 mir_map
|
||||
|
||||
fn main() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:23:11: 23:11
|
||||
let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:24:13: 24:34
|
||||
let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:26:14: 26:27
|
||||
let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:26:29: 26:42
|
||||
let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:27:13: 27:30
|
||||
let _6: usize; // in scope 0 at $DIR/issue-72181.rs:27:24: 27:25
|
||||
let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
|
||||
let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
|
||||
scope 1 {
|
||||
let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
scope 2 {
|
||||
debug f => _2; // in scope 2 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
scope 3 {
|
||||
}
|
||||
scope 4 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
|
||||
_1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
|
||||
// ty::Const
|
||||
// + ty: fn() -> usize {std::mem::size_of::<Foo>}
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:24:13: 24:32
|
||||
// + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181.rs:23:1: 28:2
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:24:34: 24:35
|
||||
StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
|
||||
_3 = Foo { a: const 42u64 }; // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
|
||||
// ty::Const
|
||||
// + ty: u64
|
||||
// + val: Value(Scalar(0x000000000000002a))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:26:23: 26:25
|
||||
// + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) }
|
||||
StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
|
||||
_4 = Foo { a: const 10u64 }; // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
|
||||
// ty::Const
|
||||
// + ty: u64
|
||||
// + val: Value(Scalar(0x000000000000000a))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:26:38: 26:40
|
||||
// + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) }
|
||||
_2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43
|
||||
StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
|
||||
StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
|
||||
FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
|
||||
StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30
|
||||
StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
|
||||
_6 = const 0usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
|
||||
// ty::Const
|
||||
// + ty: usize
|
||||
// + val: Value(Scalar(0x0000000000000000))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:27:24: 27:25
|
||||
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
|
||||
_7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
|
||||
_8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
|
||||
assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:27:22: 27:28
|
||||
StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
|
||||
StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
|
||||
_0 = const (); // scope 0 at $DIR/issue-72181.rs:23:11: 28:2
|
||||
// ty::Const
|
||||
// + ty: ()
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:23:11: 28:2
|
||||
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
|
||||
StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:28:1: 28:2
|
||||
goto -> bb4; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
|
||||
}
|
||||
|
||||
bb4: {
|
||||
return; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
|
||||
}
|
||||
}
|
25
src/test/mir-opt/issue-72181/rustc.bar.mir_map.0.mir
Normal file
25
src/test/mir-opt/issue-72181/rustc.bar.mir_map.0.mir
Normal file
@ -0,0 +1,25 @@
|
||||
// MIR for `bar` 0 mir_map
|
||||
|
||||
fn bar(_1: [(Never, u32); 1]) -> u32 {
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:18:40: 18:43
|
||||
let _2: u32; // in scope 0 at $DIR/issue-72181.rs:18:13: 18:14
|
||||
scope 1 {
|
||||
debug x => _2; // in scope 1 at $DIR/issue-72181.rs:18:13: 18:14
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:18:13: 18:14
|
||||
_2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:18:13: 18:14
|
||||
_0 = _2; // scope 1 at $DIR/issue-72181.rs:18:46: 18:47
|
||||
StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:18:48: 18:49
|
||||
goto -> bb2; // scope 0 at $DIR/issue-72181.rs:18:49: 18:49
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181.rs:18:1: 18:49
|
||||
}
|
||||
|
||||
bb2: {
|
||||
return; // scope 0 at $DIR/issue-72181.rs:18:49: 18:49
|
||||
}
|
||||
}
|
37
src/test/mir-opt/issue-72181/rustc.foo.mir_map.0.mir
Normal file
37
src/test/mir-opt/issue-72181/rustc.foo.mir_map.0.mir
Normal file
@ -0,0 +1,37 @@
|
||||
// MIR for `foo` 0 mir_map
|
||||
|
||||
fn foo(_1: [(Never, u32); 1]) -> u32 {
|
||||
debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:15:8: 15:10
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:15:34: 15:37
|
||||
let _2: usize; // in scope 0 at $DIR/issue-72181.rs:15:43: 15:44
|
||||
let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:15:40: 15:45
|
||||
let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:15:40: 15:45
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:15:43: 15:44
|
||||
_2 = const 0usize; // scope 0 at $DIR/issue-72181.rs:15:43: 15:44
|
||||
// ty::Const
|
||||
// + ty: usize
|
||||
// + val: Value(Scalar(0x0000000000000000))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:15:43: 15:44
|
||||
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
|
||||
_3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:15:40: 15:45
|
||||
_4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:15:40: 15:45
|
||||
assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:15:40: 15:45
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181.rs:15:1: 15:49
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:15:40: 15:47
|
||||
StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:15:48: 15:49
|
||||
goto -> bb3; // scope 0 at $DIR/issue-72181.rs:15:49: 15:49
|
||||
}
|
||||
|
||||
bb3: {
|
||||
return; // scope 0 at $DIR/issue-72181.rs:15:49: 15:49
|
||||
}
|
||||
}
|
93
src/test/mir-opt/issue-72181/rustc.main.mir_map.0.mir
Normal file
93
src/test/mir-opt/issue-72181/rustc.main.mir_map.0.mir
Normal file
@ -0,0 +1,93 @@
|
||||
// MIR for `main` 0 mir_map
|
||||
|
||||
fn main() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:21:11: 21:11
|
||||
let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:22:13: 22:34
|
||||
let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:24:14: 24:27
|
||||
let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:24:29: 24:42
|
||||
let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:25:13: 25:30
|
||||
let _6: usize; // in scope 0 at $DIR/issue-72181.rs:25:24: 25:25
|
||||
let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:25:22: 25:26
|
||||
let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:25:22: 25:26
|
||||
scope 1 {
|
||||
let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:24:9: 24:10
|
||||
scope 2 {
|
||||
debug f => _2; // in scope 2 at $DIR/issue-72181.rs:24:9: 24:10
|
||||
scope 3 {
|
||||
}
|
||||
scope 4 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:22:13: 22:34
|
||||
_1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:22:13: 22:34
|
||||
// ty::Const
|
||||
// + ty: fn() -> usize {std::mem::size_of::<Foo>}
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:22:13: 22:32
|
||||
// + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb1 (cleanup): {
|
||||
resume; // scope 0 at $DIR/issue-72181.rs:21:1: 26:2
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:22:34: 22:35
|
||||
StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:24:9: 24:10
|
||||
StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:24:14: 24:27
|
||||
_3 = Foo { a: const 42u64 }; // scope 1 at $DIR/issue-72181.rs:24:14: 24:27
|
||||
// ty::Const
|
||||
// + ty: u64
|
||||
// + val: Value(Scalar(0x000000000000002a))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:24:23: 24:25
|
||||
// + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) }
|
||||
StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:24:29: 24:42
|
||||
_4 = Foo { a: const 10u64 }; // scope 1 at $DIR/issue-72181.rs:24:29: 24:42
|
||||
// ty::Const
|
||||
// + ty: u64
|
||||
// + val: Value(Scalar(0x000000000000000a))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:24:38: 24:40
|
||||
// + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) }
|
||||
_2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:24:13: 24:43
|
||||
StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:24:42: 24:43
|
||||
StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:24:42: 24:43
|
||||
FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:24:9: 24:10
|
||||
StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:25:13: 25:30
|
||||
StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:25:24: 25:25
|
||||
_6 = const 0usize; // scope 4 at $DIR/issue-72181.rs:25:24: 25:25
|
||||
// ty::Const
|
||||
// + ty: usize
|
||||
// + val: Value(Scalar(0x0000000000000000))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:25:24: 25:25
|
||||
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
|
||||
_7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:25:22: 25:26
|
||||
_8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:25:22: 25:26
|
||||
assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:25:22: 25:26
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:25:22: 25:28
|
||||
StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:25:30: 25:31
|
||||
StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:25:30: 25:31
|
||||
_0 = const (); // scope 0 at $DIR/issue-72181.rs:21:11: 26:2
|
||||
// ty::Const
|
||||
// + ty: ()
|
||||
// + val: Value(Scalar(<ZST>))
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue-72181.rs:21:11: 26:2
|
||||
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
|
||||
StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:26:1: 26:2
|
||||
goto -> bb4; // scope 0 at $DIR/issue-72181.rs:26:2: 26:2
|
||||
}
|
||||
|
||||
bb4: {
|
||||
return; // scope 0 at $DIR/issue-72181.rs:26:2: 26:2
|
||||
}
|
||||
}
|
35
src/test/rustdoc/synthetic_auto/overflow.rs
Normal file
35
src/test/rustdoc/synthetic_auto/overflow.rs
Normal file
@ -0,0 +1,35 @@
|
||||
// Tests that we don't fail with an overflow error for certain
|
||||
// strange types
|
||||
// See https://github.com/rust-lang/rust/pull/72936#issuecomment-643676915
|
||||
|
||||
pub trait Interner {
|
||||
type InternedType;
|
||||
}
|
||||
|
||||
struct RustInterner<'tcx> {
|
||||
foo: &'tcx ()
|
||||
}
|
||||
|
||||
impl<'tcx> Interner for RustInterner<'tcx> {
|
||||
type InternedType = Box<TyData<Self>>;
|
||||
}
|
||||
|
||||
enum TyData<I: Interner> {
|
||||
FnDef(I::InternedType)
|
||||
}
|
||||
|
||||
struct VariableKind<I: Interner>(I::InternedType);
|
||||
|
||||
// @has overflow/struct.BoundVarsCollector.html
|
||||
// @has - '//code' "impl<'tcx> Send for BoundVarsCollector<'tcx>"
|
||||
pub struct BoundVarsCollector<'tcx> {
|
||||
val: VariableKind<RustInterner<'tcx>>
|
||||
}
|
||||
|
||||
fn is_send<T: Send>() {}
|
||||
|
||||
struct MyInterner<'tcx> {
|
||||
val: &'tcx ()
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,8 +1,8 @@
|
||||
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
|
||||
--> $DIR/project-fn-ret-invariant.rs:48:8
|
||||
--> $DIR/project-fn-ret-invariant.rs:48:4
|
||||
|
|
||||
LL | bar(foo, x)
|
||||
| ^^^
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 44:8...
|
||||
--> $DIR/project-fn-ret-invariant.rs:44:8
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Tests the interaction of associated type defaults and specialization.
|
||||
|
||||
#![feature(associated_type_defaults, specialization)]
|
||||
//~^ WARN the feature `specialization` is incomplete
|
||||
|
||||
trait Tr {
|
||||
type Ty = u8;
|
||||
|
@ -1,5 +1,14 @@
|
||||
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/defaults-specialization.rs:3:38
|
||||
|
|
||||
LL | #![feature(associated_type_defaults, specialization)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
|
||||
|
||||
error[E0053]: method `make` has an incompatible type for trait
|
||||
--> $DIR/defaults-specialization.rs:18:18
|
||||
--> $DIR/defaults-specialization.rs:19:18
|
||||
|
|
||||
LL | fn make() -> Self::Ty {
|
||||
| -------- type in trait
|
||||
@ -11,7 +20,7 @@ LL | fn make() -> u8 { 0 }
|
||||
found fn pointer `fn() -> u8`
|
||||
|
||||
error[E0053]: method `make` has an incompatible type for trait
|
||||
--> $DIR/defaults-specialization.rs:34:18
|
||||
--> $DIR/defaults-specialization.rs:35:18
|
||||
|
|
||||
LL | fn make() -> Self::Ty {
|
||||
| -------- type in trait
|
||||
@ -26,7 +35,7 @@ LL | fn make() -> bool { true }
|
||||
found fn pointer `fn() -> bool`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/defaults-specialization.rs:9:9
|
||||
--> $DIR/defaults-specialization.rs:10:9
|
||||
|
|
||||
LL | type Ty = u8;
|
||||
| ------------- associated type defaults can't be assumed inside the trait defining them
|
||||
@ -40,7 +49,7 @@ LL | 0u8
|
||||
found type `u8`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/defaults-specialization.rs:25:29
|
||||
--> $DIR/defaults-specialization.rs:26:29
|
||||
|
|
||||
LL | fn make() -> Self::Ty { 0u8 }
|
||||
| -------- ^^^ expected associated type, found `u8`
|
||||
@ -53,7 +62,7 @@ LL | fn make() -> Self::Ty { 0u8 }
|
||||
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/defaults-specialization.rs:43:29
|
||||
--> $DIR/defaults-specialization.rs:44:29
|
||||
|
|
||||
LL | default type Ty = bool;
|
||||
| ----------------------- expected this associated type
|
||||
@ -67,7 +76,7 @@ LL | fn make() -> Self::Ty { true }
|
||||
found type `bool`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/defaults-specialization.rs:86:32
|
||||
--> $DIR/defaults-specialization.rs:87:32
|
||||
|
|
||||
LL | let _: <B<()> as Tr>::Ty = 0u8;
|
||||
| ----------------- ^^^ expected associated type, found `u8`
|
||||
@ -77,13 +86,13 @@ LL | let _: <B<()> as Tr>::Ty = 0u8;
|
||||
= note: expected associated type `<B<()> as Tr>::Ty`
|
||||
found type `u8`
|
||||
help: a method is available that returns `<B<()> as Tr>::Ty`
|
||||
--> $DIR/defaults-specialization.rs:8:5
|
||||
--> $DIR/defaults-specialization.rs:9:5
|
||||
|
|
||||
LL | fn make() -> Self::Ty {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/defaults-specialization.rs:87:32
|
||||
--> $DIR/defaults-specialization.rs:88:32
|
||||
|
|
||||
LL | let _: <B<()> as Tr>::Ty = true;
|
||||
| ----------------- ^^^^ expected associated type, found `bool`
|
||||
@ -93,13 +102,13 @@ LL | let _: <B<()> as Tr>::Ty = true;
|
||||
= note: expected associated type `<B<()> as Tr>::Ty`
|
||||
found type `bool`
|
||||
help: a method is available that returns `<B<()> as Tr>::Ty`
|
||||
--> $DIR/defaults-specialization.rs:8:5
|
||||
--> $DIR/defaults-specialization.rs:9:5
|
||||
|
|
||||
LL | fn make() -> Self::Ty {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/defaults-specialization.rs:88:33
|
||||
--> $DIR/defaults-specialization.rs:89:33
|
||||
|
|
||||
LL | let _: <B2<()> as Tr>::Ty = 0u8;
|
||||
| ------------------ ^^^ expected associated type, found `u8`
|
||||
@ -109,13 +118,13 @@ LL | let _: <B2<()> as Tr>::Ty = 0u8;
|
||||
= note: expected associated type `<B2<()> as Tr>::Ty`
|
||||
found type `u8`
|
||||
help: a method is available that returns `<B2<()> as Tr>::Ty`
|
||||
--> $DIR/defaults-specialization.rs:8:5
|
||||
--> $DIR/defaults-specialization.rs:9:5
|
||||
|
|
||||
LL | fn make() -> Self::Ty {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/defaults-specialization.rs:89:33
|
||||
--> $DIR/defaults-specialization.rs:90:33
|
||||
|
|
||||
LL | let _: <B2<()> as Tr>::Ty = true;
|
||||
| ------------------ ^^^^ expected associated type, found `bool`
|
||||
@ -125,12 +134,12 @@ LL | let _: <B2<()> as Tr>::Ty = true;
|
||||
= note: expected associated type `<B2<()> as Tr>::Ty`
|
||||
found type `bool`
|
||||
help: a method is available that returns `<B2<()> as Tr>::Ty`
|
||||
--> $DIR/defaults-specialization.rs:8:5
|
||||
--> $DIR/defaults-specialization.rs:9:5
|
||||
|
|
||||
LL | fn make() -> Self::Ty {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
error: aborting due to 9 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0053, E0308.
|
||||
For more information about an error, try `rustc --explain E0053`.
|
||||
|
34
src/test/ui/auto-traits/auto-trait-projection-recursion.rs
Normal file
34
src/test/ui/auto-traits/auto-trait-projection-recursion.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// Checking the `Send` bound in `main` requires:
|
||||
//
|
||||
// checking <C<'static> as Y>::P: Send
|
||||
// which normalizes to Box<X<C<'?1>>>: Send
|
||||
// which needs X<C<'?1>>: Send
|
||||
// which needs <C<'?1> as Y>::P: Send
|
||||
//
|
||||
// At this point we used to normalize the predicate to `Box<X<C<'?2>>>: Send`
|
||||
// and continue in a loop where we created new region variables to the
|
||||
// recursion limit. To avoid this we now "canonicalize" region variables to
|
||||
// lowest unified region vid. This means we instead have to prove
|
||||
// `Box<X<C<'?1>>>: Send`, which we can because auto traits are coinductive.
|
||||
|
||||
// check-pass
|
||||
|
||||
// Avoid a really long error message if this regresses.
|
||||
#![recursion_limit="20"]
|
||||
|
||||
trait Y {
|
||||
type P;
|
||||
}
|
||||
|
||||
impl<'a> Y for C<'a> {
|
||||
type P = Box<X<C<'a>>>;
|
||||
}
|
||||
|
||||
struct C<'a>(&'a ());
|
||||
struct X<T: Y>(T::P);
|
||||
|
||||
fn is_send<S: Send>() {}
|
||||
|
||||
fn main() {
|
||||
is_send::<X<C<'static>>>();
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// Checks that immutable static items can't have mutable slices
|
||||
|
||||
static TEST: &'static mut [isize] = &mut [];
|
||||
//~^ ERROR references in statics may only refer to immutable values
|
||||
//~^ ERROR mutable references are not allowed in statics
|
||||
|
||||
pub fn main() { }
|
||||
|
@ -1,12 +1,9 @@
|
||||
error[E0658]: references in statics may only refer to immutable values
|
||||
error[E0764]: mutable references are not allowed in statics
|
||||
--> $DIR/check-static-immutable-mut-slices.rs:3:37
|
||||
|
|
||||
LL | static TEST: &'static mut [isize] = &mut [];
|
||||
| ^^^^^^^ statics require immutable values
|
||||
|
|
||||
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
| ^^^^^^^ `&mut` is only allowed in `const fn`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
For more information about this error, try `rustc --explain E0764`.
|
||||
|
@ -1,8 +1,8 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:27
|
||||
--> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:5
|
||||
|
|
||||
LL | with_closure(|x: u32, y| {});
|
||||
| ^ consider giving this closure parameter a type
|
||||
| ^^^^^^^^^^^^ cannot infer type for type parameter `B` declared on the function `with_closure`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,68 +0,0 @@
|
||||
// run-pass
|
||||
#![allow(unused_braces)]
|
||||
#![allow(dead_code)]
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
// Examples from the "deref coercions" RFC, at rust-lang/rfcs#241.
|
||||
|
||||
fn use_ref<T>(_: &T) {}
|
||||
fn use_mut<T>(_: &mut T) {}
|
||||
|
||||
fn use_rc<T>(t: Rc<T>) {
|
||||
use_ref(&*t); // what you have to write today
|
||||
use_ref(&t); // what you'd be able to write
|
||||
use_ref(&&&&&&t);
|
||||
use_ref(&mut &&&&&t);
|
||||
use_ref(&&&mut &&&t);
|
||||
}
|
||||
|
||||
fn use_mut_box<T>(mut t: &mut Box<T>) {
|
||||
use_mut(&mut *t); // what you have to write today
|
||||
use_mut(t); // what you'd be able to write
|
||||
use_mut(&mut &mut &mut t);
|
||||
|
||||
use_ref(&*t); // what you have to write today
|
||||
use_ref(t); // what you'd be able to write
|
||||
use_ref(&&&&&&t);
|
||||
use_ref(&mut &&&&&t);
|
||||
use_ref(&&&mut &&&t);
|
||||
}
|
||||
|
||||
fn use_nested<T>(t: &Box<T>) {
|
||||
use_ref(&**t); // what you have to write today
|
||||
use_ref(t); // what you'd be able to write (note: recursive deref)
|
||||
use_ref(&&&&&&t);
|
||||
use_ref(&mut &&&&&t);
|
||||
use_ref(&&&mut &&&t);
|
||||
}
|
||||
|
||||
fn use_slice(_: &[u8]) {}
|
||||
fn use_slice_mut(_: &mut [u8]) {}
|
||||
|
||||
fn use_vec(mut v: Vec<u8>) {
|
||||
use_slice_mut(&mut v[..]); // what you have to write today
|
||||
use_slice_mut(&mut v); // what you'd be able to write
|
||||
use_slice_mut(&mut &mut &mut v);
|
||||
|
||||
use_slice(&v[..]); // what you have to write today
|
||||
use_slice(&v); // what you'd be able to write
|
||||
use_slice(&&&&&&v);
|
||||
use_slice(&mut &&&&&v);
|
||||
use_slice(&&&mut &&&v);
|
||||
}
|
||||
|
||||
fn use_vec_ref(v: &Vec<u8>) {
|
||||
use_slice(&v[..]); // what you have to write today
|
||||
use_slice(v); // what you'd be able to write
|
||||
use_slice(&&&&&&v);
|
||||
use_slice(&mut &&&&&v);
|
||||
use_slice(&&&mut &&&v);
|
||||
}
|
||||
|
||||
fn use_op_rhs(s: &mut String) {
|
||||
*s += {&String::from(" ")};
|
||||
}
|
||||
|
||||
pub fn main() {}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user