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:
bors 2020-06-20 02:45:08 +00:00
commit 033013cab3
275 changed files with 2551 additions and 852 deletions

View File

@ -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",

View File

@ -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<'_>) {

View File

@ -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

View File

@ -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.

View File

@ -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)]

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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))
}

View File

@ -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

View File

@ -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

View File

@ -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"];

View File

@ -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,

View File

@ -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

View File

@ -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.

View File

@ -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() {}

View 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!
}
```

View File

@ -596,4 +596,5 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::raw_dylib,
sym::const_trait_impl,
sym::const_trait_bound_opt_out,
sym::specialization,
];

View File

@ -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)
}

View File

@ -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);
}

View File

@ -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> {

View File

@ -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)
}
}
}

View File

@ -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")));

View File

@ -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(),
}
}

View File

@ -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>],
}

View File

@ -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]

View File

@ -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)
}

View File

@ -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.

View File

@ -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!(),
};

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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))
}

View File

@ -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);

View File

@ -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);
(

View File

@ -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 \

View File

@ -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,

View File

@ -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()

View File

@ -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),
}
}

View File

@ -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),
}
}

View File

@ -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" }

View File

@ -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

View File

@ -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]

View File

@ -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 \

View File

@ -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;
}
}
}

View File

@ -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>(

View File

@ -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 {

View File

@ -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 => {

View File

@ -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,

View File

@ -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());

View File

@ -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

View File

@ -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));
}
);
}

View File

@ -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
}

View File

@ -1,6 +1,6 @@
// compile-fail
#![feature(specialization)]
//~^ WARN the feature `specialization` is incomplete
pub trait Foo {
fn foo();

View 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();
}

View File

@ -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
}
}

View 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);
}

View 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
}
}

View 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
}
}

View 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 };
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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() {}

View File

@ -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

View File

@ -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;

View File

@ -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`.

View 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>>>();
}

View File

@ -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() { }

View File

@ -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`.

View File

@ -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

View File

@ -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