1
Fork 0

Auto merge of #68248 - JohnTitor:rollup-x0kml5f, r=JohnTitor

Rollup of 12 pull requests

Successful merges:

 - #67784 (Reset Formatter flags on exit from pad_integral)
 - #67914 (Don't run const propagation on items with inconsistent bounds)
 - #68141 (use winapi for non-stdlib Windows bindings)
 - #68211 (Add failing example for E0170 explanation)
 - #68219 (Untangle ZST validation from integer validation and generalize it to all zsts)
 - #68222 (Update the wasi-libc bundled with libstd)
 - #68226 (Avoid calling tcx.hir().get() on CRATE_HIR_ID)
 - #68227 (Update to a version of cmake with windows arm64 support)
 - #68229 (Update iovec to a version with no winapi dependency)
 - #68230 (Update libssh2-sys to a version that can build for aarch64-pc-windows…)
 - #68231 (Better support for cross compilation on Windows.)
 - #68233 (Update compiler_builtins with changes to fix 128 bit integer remainder for aarch64 windows.)

Failed merges:

r? @ghost
This commit is contained in:
bors 2020-01-15 13:00:43 +00:00
commit 6d0bb91bcb
37 changed files with 305 additions and 309 deletions

View file

@ -207,6 +207,7 @@ dependencies = [
"serde_json", "serde_json",
"time", "time",
"toml", "toml",
"winapi 0.3.8",
] ]
[[package]] [[package]]
@ -520,9 +521,9 @@ dependencies = [
[[package]] [[package]]
name = "cmake" name = "cmake"
version = "0.1.38" version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96210eec534fc3fbfc0452a63769424eaa80205fda6cea98e5b61cb3d97bcec8" checksum = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62"
dependencies = [ dependencies = [
"cc", "cc",
] ]
@ -576,9 +577,9 @@ dependencies = [
[[package]] [[package]]
name = "compiler_builtins" name = "compiler_builtins"
version = "0.1.22" version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6f083abf9bb9005a27d2da62706f661245278cb7096da37ab27410eaf60f2c1" checksum = "b9975aefa63997ef75ca9cf013ff1bb81487aaa0b622c21053afd3b92979a7af"
dependencies = [ dependencies = [
"cc", "cc",
"rustc-std-workspace-core", "rustc-std-workspace-core",
@ -1587,12 +1588,11 @@ dependencies = [
[[package]] [[package]]
name = "iovec" name = "iovec"
version = "0.1.2" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
dependencies = [ dependencies = [
"libc", "libc",
"winapi 0.2.8",
] ]
[[package]] [[package]]
@ -1812,9 +1812,9 @@ dependencies = [
[[package]] [[package]]
name = "libssh2-sys" name = "libssh2-sys"
version = "0.2.11" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d" checksum = "36aa6e813339d3a063292b77091dfbbb6152ff9006a459895fa5bebed7d34f10"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -3497,6 +3497,7 @@ dependencies = [
"serialize", "serialize",
"smallvec 1.0.0", "smallvec 1.0.0",
"stable_deref_trait", "stable_deref_trait",
"winapi 0.3.8",
] ]
[[package]] [[package]]
@ -3524,6 +3525,7 @@ dependencies = [
"rustc_target", "rustc_target",
"serialize", "serialize",
"syntax", "syntax",
"winapi 0.3.8",
] ]
[[package]] [[package]]
@ -3543,6 +3545,7 @@ dependencies = [
"term_size", "term_size",
"termcolor", "termcolor",
"unicode-width", "unicode-width",
"winapi 0.3.8",
] ]
[[package]] [[package]]
@ -3654,6 +3657,7 @@ dependencies = [
"smallvec 1.0.0", "smallvec 1.0.0",
"syntax", "syntax",
"tempfile", "tempfile",
"winapi 0.3.8",
] ]
[[package]] [[package]]
@ -3723,6 +3727,7 @@ dependencies = [
"smallvec 1.0.0", "smallvec 1.0.0",
"stable_deref_trait", "stable_deref_trait",
"syntax", "syntax",
"winapi 0.3.8",
] ]
[[package]] [[package]]

View file

@ -49,5 +49,9 @@ lazy_static = "1.3.0"
time = "0.1" time = "0.1"
ignore = "0.4.10" ignore = "0.4.10"
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
features = ["fileapi", "ioapiset", "jobapi2", "handleapi", "winioctl"]
[dev-dependencies] [dev-dependencies]
pretty_assertions = "0.5" pretty_assertions = "0.5"

View file

@ -35,84 +35,16 @@ use std::io;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
type HANDLE = *mut u8; use winapi::shared::minwindef::{DWORD, FALSE, LPVOID};
type BOOL = i32; use winapi::um::errhandlingapi::SetErrorMode;
type DWORD = u32; use winapi::um::handleapi::{CloseHandle, DuplicateHandle};
type LPHANDLE = *mut HANDLE; use winapi::um::jobapi2::{AssignProcessToJobObject, CreateJobObjectW, SetInformationJobObject};
type LPVOID = *mut u8; use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcess};
type JOBOBJECTINFOCLASS = i32; use winapi::um::winbase::{BELOW_NORMAL_PRIORITY_CLASS, SEM_NOGPFAULTERRORBOX};
type SIZE_T = usize; use winapi::um::winnt::{
type LARGE_INTEGER = i64; JobObjectExtendedLimitInformation, DUPLICATE_SAME_ACCESS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
type UINT = u32; JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
type ULONG_PTR = usize; };
type ULONGLONG = u64;
const FALSE: BOOL = 0;
const DUPLICATE_SAME_ACCESS: DWORD = 0x2;
const PROCESS_DUP_HANDLE: DWORD = 0x40;
const JobObjectExtendedLimitInformation: JOBOBJECTINFOCLASS = 9;
const JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: DWORD = 0x2000;
const JOB_OBJECT_LIMIT_PRIORITY_CLASS: DWORD = 0x00000020;
const SEM_FAILCRITICALERRORS: UINT = 0x0001;
const SEM_NOGPFAULTERRORBOX: UINT = 0x0002;
const BELOW_NORMAL_PRIORITY_CLASS: DWORD = 0x00004000;
extern "system" {
fn CreateJobObjectW(lpJobAttributes: *mut u8, lpName: *const u8) -> HANDLE;
fn CloseHandle(hObject: HANDLE) -> BOOL;
fn GetCurrentProcess() -> HANDLE;
fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) -> HANDLE;
fn DuplicateHandle(
hSourceProcessHandle: HANDLE,
hSourceHandle: HANDLE,
hTargetProcessHandle: HANDLE,
lpTargetHandle: LPHANDLE,
dwDesiredAccess: DWORD,
bInheritHandle: BOOL,
dwOptions: DWORD,
) -> BOOL;
fn AssignProcessToJobObject(hJob: HANDLE, hProcess: HANDLE) -> BOOL;
fn SetInformationJobObject(
hJob: HANDLE,
JobObjectInformationClass: JOBOBJECTINFOCLASS,
lpJobObjectInformation: LPVOID,
cbJobObjectInformationLength: DWORD,
) -> BOOL;
fn SetErrorMode(mode: UINT) -> UINT;
}
#[repr(C)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
BasicLimitInformation: JOBOBJECT_BASIC_LIMIT_INFORMATION,
IoInfo: IO_COUNTERS,
ProcessMemoryLimit: SIZE_T,
JobMemoryLimit: SIZE_T,
PeakProcessMemoryUsed: SIZE_T,
PeakJobMemoryUsed: SIZE_T,
}
#[repr(C)]
struct IO_COUNTERS {
ReadOperationCount: ULONGLONG,
WriteOperationCount: ULONGLONG,
OtherOperationCount: ULONGLONG,
ReadTransferCount: ULONGLONG,
WriteTransferCount: ULONGLONG,
OtherTransferCount: ULONGLONG,
}
#[repr(C)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION {
PerProcessUserTimeLimit: LARGE_INTEGER,
PerJobUserTimeLimit: LARGE_INTEGER,
LimitFlags: DWORD,
MinimumWorkingsetSize: SIZE_T,
MaximumWorkingsetSize: SIZE_T,
ActiveProcessLimit: DWORD,
Affinity: ULONG_PTR,
PriorityClass: DWORD,
SchedulingClass: DWORD,
}
pub unsafe fn setup(build: &mut Build) { pub unsafe fn setup(build: &mut Build) {
// Enable the Windows Error Reporting dialog which msys disables, // Enable the Windows Error Reporting dialog which msys disables,

View file

@ -230,6 +230,8 @@ impl Step for Llvm {
cfg.define("CMAKE_SYSTEM_NAME", "NetBSD"); cfg.define("CMAKE_SYSTEM_NAME", "NetBSD");
} else if target.contains("freebsd") { } else if target.contains("freebsd") {
cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD"); cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD");
} else if target.contains("windows") {
cfg.define("CMAKE_SYSTEM_NAME", "Windows");
} }
cfg.define("LLVM_NATIVE_BUILD", builder.llvm_out(builder.config.build).join("build")); cfg.define("LLVM_NATIVE_BUILD", builder.llvm_out(builder.config.build).join("build"));

View file

@ -123,37 +123,24 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
// what can be found here: // what can be found here:
// //
// http://www.flexhex.com/docs/articles/hard-links.phtml // http://www.flexhex.com/docs/articles/hard-links.phtml
//
// Copied from std
#[cfg(windows)] #[cfg(windows)]
#[allow(nonstandard_style)]
fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> { fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> {
use std::ffi::OsStr; use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt; use std::os::windows::ffi::OsStrExt;
use std::ptr; use std::ptr;
const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; use winapi::shared::minwindef::{DWORD, WORD};
const GENERIC_WRITE: DWORD = 0x40000000; use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING};
const OPEN_EXISTING: DWORD = 3; use winapi::um::handleapi::CloseHandle;
const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000; use winapi::um::ioapiset::DeviceIoControl;
const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000; use winapi::um::winbase::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT};
const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4; use winapi::um::winioctl::FSCTL_SET_REPARSE_POINT;
const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003; use winapi::um::winnt::{
const FILE_SHARE_DELETE: DWORD = 0x4; FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_WRITE,
const FILE_SHARE_READ: DWORD = 0x1; IO_REPARSE_TAG_MOUNT_POINT, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, WCHAR,
const FILE_SHARE_WRITE: DWORD = 0x2; };
type BOOL = i32;
type DWORD = u32;
type HANDLE = *mut u8;
type LPCWSTR = *const u16;
type LPDWORD = *mut DWORD;
type LPOVERLAPPED = *mut u8;
type LPSECURITY_ATTRIBUTES = *mut u8;
type LPVOID = *mut u8;
type WCHAR = u16;
type WORD = u16;
#[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct REPARSE_MOUNTPOINT_DATA_BUFFER { struct REPARSE_MOUNTPOINT_DATA_BUFFER {
ReparseTag: DWORD, ReparseTag: DWORD,
@ -165,29 +152,6 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
ReparseTarget: WCHAR, ReparseTarget: WCHAR,
} }
extern "system" {
fn CreateFileW(
lpFileName: LPCWSTR,
dwDesiredAccess: DWORD,
dwShareMode: DWORD,
lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
dwCreationDisposition: DWORD,
dwFlagsAndAttributes: DWORD,
hTemplateFile: HANDLE,
) -> HANDLE;
fn DeviceIoControl(
hDevice: HANDLE,
dwIoControlCode: DWORD,
lpInBuffer: LPVOID,
nInBufferSize: DWORD,
lpOutBuffer: LPVOID,
nOutBufferSize: DWORD,
lpBytesReturned: LPDWORD,
lpOverlapped: LPOVERLAPPED,
) -> BOOL;
fn CloseHandle(hObject: HANDLE) -> BOOL;
}
fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> { fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
Ok(s.as_ref().encode_wide().chain(Some(0)).collect()) Ok(s.as_ref().encode_wide().chain(Some(0)).collect())
} }
@ -212,7 +176,7 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
ptr::null_mut(), ptr::null_mut(),
); );
let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize];
let db = data.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; let db = data.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
let buf = &mut (*db).ReparseTarget as *mut u16; let buf = &mut (*db).ReparseTarget as *mut u16;
let mut i = 0; let mut i = 0;

View file

@ -12,7 +12,7 @@ export PATH=`pwd`/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-14.04/bin:$PATH
git clone https://github.com/CraneStation/wasi-libc git clone https://github.com/CraneStation/wasi-libc
cd wasi-libc cd wasi-libc
git reset --hard f645f498dfbbbc00a7a97874d33082d3605c3f21 git reset --hard 1fad33890a5e299027ce0eab7b6ad5260585e347
make -j$(nproc) INSTALL_DIR=/wasm32-wasi install make -j$(nproc) INSTALL_DIR=/wasm32-wasi install
cd .. cd ..

View file

@ -1244,12 +1244,15 @@ impl<'a> Formatter<'a> {
// The sign and prefix goes before the padding if the fill character // The sign and prefix goes before the padding if the fill character
// is zero // is zero
Some(min) if self.sign_aware_zero_pad() => { Some(min) if self.sign_aware_zero_pad() => {
self.fill = '0'; let old_fill = crate::mem::replace(&mut self.fill, '0');
self.align = rt::v1::Alignment::Right; let old_align = crate::mem::replace(&mut self.align, rt::v1::Alignment::Right);
write_prefix(self, sign, prefix)?; write_prefix(self, sign, prefix)?;
let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
self.buf.write_str(buf)?; self.buf.write_str(buf)?;
post_padding.write(self.buf) post_padding.write(self.buf)?;
self.fill = old_fill;
self.align = old_align;
Ok(())
} }
// Otherwise, the sign and prefix goes after the padding // Otherwise, the sign and prefix goes after the padding
Some(min) => { Some(min) => {

View file

@ -28,3 +28,18 @@ fn test_estimated_capacity() {
assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 0); assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 0);
assert_eq!(format_args!("{}. 16-bytes piece", "World").estimated_capacity(), 32); assert_eq!(format_args!("{}. 16-bytes piece", "World").estimated_capacity(), 32);
} }
#[test]
fn pad_integral_resets() {
struct Bar;
impl core::fmt::Display for Bar {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
"1".fmt(f)?;
f.pad_integral(true, "", "5")?;
"1".fmt(f)
}
}
assert_eq!(format!("{:<03}", Bar), "1 0051 ");
}

View file

@ -1219,7 +1219,7 @@ pub fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: DefId, opaque_hir_id: hir
let res = hir_id == scope; let res = hir_id == scope;
trace!( trace!(
"may_define_opaque_type(def={:?}, opaque_node={:?}) = {}", "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
tcx.hir().get(hir_id), tcx.hir().find(hir_id),
tcx.hir().get(opaque_hir_id), tcx.hir().get(opaque_hir_id),
res res
); );

View file

@ -34,7 +34,6 @@
#![feature(const_transmute)] #![feature(const_transmute)]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(drain_filter)] #![feature(drain_filter)]
#![cfg_attr(windows, feature(libc))]
#![feature(never_type)] #![feature(never_type)]
#![feature(exhaustive_patterns)] #![feature(exhaustive_patterns)]
#![feature(overlapping_marker_traits)] #![feature(overlapping_marker_traits)]

View file

@ -1,6 +1,7 @@
use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId}; use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId};
use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext}; use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext};
use crate::session::config::OptLevel; use crate::session::config::OptLevel;
use crate::traits::TraitQueryMode;
use crate::ty::print::obsolete::DefPathBasedNames; use crate::ty::print::obsolete::DefPathBasedNames;
use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt};
use rustc_data_structures::base_n; use rustc_data_structures::base_n;
@ -167,7 +168,9 @@ impl<'tcx> MonoItem<'tcx> {
MonoItem::GlobalAsm(..) => return true, MonoItem::GlobalAsm(..) => return true,
}; };
tcx.substitute_normalize_and_test_predicates((def_id, &substs)) // We shouldn't encounter any overflow here, so we use TraitQueryMode::Standard\
// to report an error if overflow somehow occurs.
tcx.substitute_normalize_and_test_predicates((def_id, &substs, TraitQueryMode::Standard))
} }
pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String { pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String {

View file

@ -1148,11 +1148,11 @@ rustc_queries! {
desc { "normalizing `{:?}`", goal } desc { "normalizing `{:?}`", goal }
} }
query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>, traits::TraitQueryMode)) -> bool {
no_force no_force
desc { |tcx| desc { |tcx|
"testing substituted normalized predicates:`{}`", "testing substituted normalized predicates in mode {:?}:`{}`",
tcx.def_path_str(key.0) key.2, tcx.def_path_str(key.0)
} }
} }

View file

@ -16,6 +16,7 @@ use super::CodeSelectionError;
use super::{ConstEvalFailure, Unimplemented}; use super::{ConstEvalFailure, Unimplemented};
use super::{FulfillmentError, FulfillmentErrorCode}; use super::{FulfillmentError, FulfillmentErrorCode};
use super::{ObligationCause, PredicateObligation}; use super::{ObligationCause, PredicateObligation};
use crate::traits::TraitQueryMode;
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
type Predicate = ty::Predicate<'tcx>; type Predicate = ty::Predicate<'tcx>;
@ -62,6 +63,9 @@ pub struct FulfillmentContext<'tcx> {
// a snapshot (they don't *straddle* a snapshot, so there // a snapshot (they don't *straddle* a snapshot, so there
// is no trouble there). // is no trouble there).
usable_in_snapshot: bool, usable_in_snapshot: bool,
// The `TraitQueryMode` used when constructing a `SelectionContext`
query_mode: TraitQueryMode,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -75,12 +79,26 @@ pub struct PendingPredicateObligation<'tcx> {
static_assert_size!(PendingPredicateObligation<'_>, 136); static_assert_size!(PendingPredicateObligation<'_>, 136);
impl<'a, 'tcx> FulfillmentContext<'tcx> { impl<'a, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context. /// Creates a new fulfillment context with `TraitQueryMode::Standard`
/// You almost always want to use this instead of `with_query_mode`
pub fn new() -> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext { FulfillmentContext {
predicates: ObligationForest::new(), predicates: ObligationForest::new(),
register_region_obligations: true, register_region_obligations: true,
usable_in_snapshot: false, usable_in_snapshot: false,
query_mode: TraitQueryMode::Standard,
}
}
/// Creates a new fulfillment context with the specified query mode.
/// This should only be used when you want to ignore overflow,
/// rather than reporting it as an error.
pub fn with_query_mode(query_mode: TraitQueryMode) -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
register_region_obligations: true,
usable_in_snapshot: false,
query_mode,
} }
} }
@ -89,6 +107,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
predicates: ObligationForest::new(), predicates: ObligationForest::new(),
register_region_obligations: true, register_region_obligations: true,
usable_in_snapshot: true, usable_in_snapshot: true,
query_mode: TraitQueryMode::Standard,
} }
} }
@ -97,6 +116,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
predicates: ObligationForest::new(), predicates: ObligationForest::new(),
register_region_obligations: false, register_region_obligations: false,
usable_in_snapshot: false, usable_in_snapshot: false,
query_mode: TraitQueryMode::Standard,
} }
} }
@ -217,7 +237,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
&mut self, &mut self,
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> { ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
let mut selcx = SelectionContext::new(infcx); let mut selcx = SelectionContext::with_query_mode(infcx, self.query_mode);
self.select(&mut selcx) self.select(&mut selcx)
} }

View file

@ -95,7 +95,7 @@ pub enum IntercrateMode {
} }
/// The mode that trait queries run in. /// The mode that trait queries run in.
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, HashStable)]
pub enum TraitQueryMode { pub enum TraitQueryMode {
// Standard/un-canonicalized queries get accurate // Standard/un-canonicalized queries get accurate
// spans etc. passed in and hence can do reasonable // spans etc. passed in and hence can do reasonable
@ -1017,13 +1017,14 @@ where
fn normalize_and_test_predicates<'tcx>( fn normalize_and_test_predicates<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
predicates: Vec<ty::Predicate<'tcx>>, predicates: Vec<ty::Predicate<'tcx>>,
mode: TraitQueryMode,
) -> bool { ) -> bool {
debug!("normalize_and_test_predicates(predicates={:?})", predicates); debug!("normalize_and_test_predicates(predicates={:?}, mode={:?})", predicates, mode);
let result = tcx.infer_ctxt().enter(|infcx| { let result = tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::reveal_all(); let param_env = ty::ParamEnv::reveal_all();
let mut selcx = SelectionContext::new(&infcx); let mut selcx = SelectionContext::with_query_mode(&infcx, mode);
let mut fulfill_cx = FulfillmentContext::new(); let mut fulfill_cx = FulfillmentContext::with_query_mode(mode);
let cause = ObligationCause::dummy(); let cause = ObligationCause::dummy();
let Normalized { value: predicates, obligations } = let Normalized { value: predicates, obligations } =
normalize(&mut selcx, param_env, cause.clone(), &predicates); normalize(&mut selcx, param_env, cause.clone(), &predicates);
@ -1043,12 +1044,12 @@ fn normalize_and_test_predicates<'tcx>(
fn substitute_normalize_and_test_predicates<'tcx>( fn substitute_normalize_and_test_predicates<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
key: (DefId, SubstsRef<'tcx>), key: (DefId, SubstsRef<'tcx>, TraitQueryMode),
) -> bool { ) -> bool {
debug!("substitute_normalize_and_test_predicates(key={:?})", key); debug!("substitute_normalize_and_test_predicates(key={:?})", key);
let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
let result = normalize_and_test_predicates(tcx, predicates); let result = normalize_and_test_predicates(tcx, predicates, key.2);
debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result); debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result);
result result
@ -1101,7 +1102,10 @@ fn vtable_methods<'tcx>(
// Note that this method could then never be called, so we // Note that this method could then never be called, so we
// do not want to try and codegen it, in that case (see #23435). // do not want to try and codegen it, in that case (see #23435).
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
if !normalize_and_test_predicates(tcx, predicates.predicates) { // We don't expect overflow here, so report an error if it somehow ends
// up happening.
if !normalize_and_test_predicates(tcx, predicates.predicates, TraitQueryMode::Standard)
{
debug!("vtable_methods: predicates do not hold"); debug!("vtable_methods: predicates do not hold");
return None; return None;
} }

View file

@ -125,6 +125,15 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
} }
} }
impl<'tcx> Key for (DefId, SubstsRef<'tcx>, traits::TraitQueryMode) {
fn query_crate(&self) -> CrateNum {
self.0.krate
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.0.default_span(tcx)
}
}
impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
fn query_crate(&self) -> CrateNum { fn query_crate(&self) -> CrateNum {
self.1.def_id().krate self.1.def_id().krate

View file

@ -31,3 +31,6 @@ measureme = "0.7.1"
[dependencies.parking_lot] [dependencies.parking_lot]
version = "0.9" version = "0.9"
features = ["nightly"] features = ["nightly"]
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["fileapi", "psapi"] }

View file

@ -87,39 +87,11 @@ cfg_if! {
} else if #[cfg(windows)] { } else if #[cfg(windows)] {
use std::mem; use std::mem;
use std::os::windows::prelude::*; use std::os::windows::prelude::*;
use std::os::windows::raw::HANDLE;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::os::raw::{c_ulong, c_int};
type DWORD = c_ulong; use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK};
type BOOL = c_int; use winapi::um::fileapi::LockFileEx;
type ULONG_PTR = usize; use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
type LPOVERLAPPED = *mut OVERLAPPED;
const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x0000_0002;
const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x0000_0001;
const FILE_SHARE_DELETE: DWORD = 0x4;
const FILE_SHARE_READ: DWORD = 0x1;
const FILE_SHARE_WRITE: DWORD = 0x2;
#[repr(C)]
struct OVERLAPPED {
Internal: ULONG_PTR,
InternalHigh: ULONG_PTR,
Offset: DWORD,
OffsetHigh: DWORD,
hEvent: HANDLE,
}
extern "system" {
fn LockFileEx(hFile: HANDLE,
dwFlags: DWORD,
dwReserved: DWORD,
nNumberOfBytesToLockLow: DWORD,
nNumberOfBytesToLockHigh: DWORD,
lpOverlapped: LPOVERLAPPED) -> BOOL;
}
#[derive(Debug)] #[derive(Debug)]
pub struct Lock { pub struct Lock {

View file

@ -33,9 +33,6 @@ extern crate libc;
#[macro_use] #[macro_use]
extern crate cfg_if; extern crate cfg_if;
#[cfg(windows)]
extern crate libc;
pub use rustc_serialize::hex::ToHex; pub use rustc_serialize::hex::ToHex;
#[inline(never)] #[inline(never)]

View file

@ -569,39 +569,19 @@ fn get_resident() -> Option<usize> {
#[cfg(windows)] #[cfg(windows)]
fn get_resident() -> Option<usize> { fn get_resident() -> Option<usize> {
type BOOL = i32; use std::mem::{self, MaybeUninit};
type DWORD = u32; use winapi::shared::minwindef::DWORD;
type HANDLE = *mut u8; use winapi::um::processthreadsapi::GetCurrentProcess;
use libc::size_t; use winapi::um::psapi::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS};
#[repr(C)]
#[allow(non_snake_case)] let mut pmc = MaybeUninit::<PROCESS_MEMORY_COUNTERS>::uninit();
struct PROCESS_MEMORY_COUNTERS { match unsafe {
cb: DWORD, GetProcessMemoryInfo(GetCurrentProcess(), pmc.as_mut_ptr(), mem::size_of_val(&pmc) as DWORD)
PageFaultCount: DWORD, } {
PeakWorkingSetSize: size_t,
WorkingSetSize: size_t,
QuotaPeakPagedPoolUsage: size_t,
QuotaPagedPoolUsage: size_t,
QuotaPeakNonPagedPoolUsage: size_t,
QuotaNonPagedPoolUsage: size_t,
PagefileUsage: size_t,
PeakPagefileUsage: size_t,
}
#[allow(non_camel_case_types)]
type PPROCESS_MEMORY_COUNTERS = *mut PROCESS_MEMORY_COUNTERS;
#[link(name = "psapi")]
extern "system" {
fn GetCurrentProcess() -> HANDLE;
fn GetProcessMemoryInfo(
Process: HANDLE,
ppsmemCounters: PPROCESS_MEMORY_COUNTERS,
cb: DWORD,
) -> BOOL;
}
let mut pmc: PROCESS_MEMORY_COUNTERS = unsafe { std::mem::zeroed() };
pmc.cb = std::mem::size_of_val(&pmc) as DWORD;
match unsafe { GetProcessMemoryInfo(GetCurrentProcess(), &mut pmc, pmc.cb) } {
0 => None, 0 => None,
_ => Some(pmc.WorkingSetSize as usize), _ => {
let pmc = unsafe { pmc.assume_init() };
Some(pmc.WorkingSetSize as usize)
}
} }
} }

View file

@ -32,5 +32,8 @@ rustc_serialize = { path = "../libserialize", package = "serialize" }
syntax = { path = "../libsyntax" } syntax = { path = "../libsyntax" }
rustc_span = { path = "../librustc_span" } rustc_span = { path = "../librustc_span" }
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] }
[features] [features]
llvm = ['rustc_interface/llvm'] llvm = ['rustc_interface/llvm']

View file

@ -514,15 +514,10 @@ fn stdout_isatty() -> bool {
#[cfg(windows)] #[cfg(windows)]
fn stdout_isatty() -> bool { fn stdout_isatty() -> bool {
type DWORD = u32; use winapi::um::consoleapi::GetConsoleMode;
type BOOL = i32; use winapi::um::processenv::GetStdHandle;
type HANDLE = *mut u8; use winapi::um::winbase::STD_OUTPUT_HANDLE;
type LPDWORD = *mut u32;
const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
extern "system" {
fn GetStdHandle(which: DWORD) -> HANDLE;
fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
}
unsafe { unsafe {
let handle = GetStdHandle(STD_OUTPUT_HANDLE); let handle = GetStdHandle(STD_OUTPUT_HANDLE);
let mut out = 0; let mut out = 0;
@ -1214,11 +1209,8 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
#[cfg(windows)] #[cfg(windows)]
unsafe { unsafe {
if env::var("RUSTC_BREAK_ON_ICE").is_ok() { if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
extern "system" {
fn DebugBreak();
}
// Trigger a debugger if we crashed during bootstrap // Trigger a debugger if we crashed during bootstrap
DebugBreak(); winapi::um::debugapi::DebugBreak();
} }
} }
} }

View file

@ -1,3 +1,24 @@
A pattern binding is using the same name as one of the variants of a type.
Erroneous code example:
```compile_fail,E0170
# #![deny(warnings)]
enum Method {
GET,
POST,
}
fn is_empty(s: Method) -> bool {
match s {
GET => true,
_ => false
}
}
fn main() {}
```
Enum variants are qualified by default. For example, given this type: Enum variants are qualified by default. For example, given this type:
``` ```

View file

@ -19,3 +19,6 @@ atty = "0.2"
termcolor = "1.0" termcolor = "1.0"
annotate-snippets = "0.6.1" annotate-snippets = "0.6.1"
term_size = "0.3.1" term_size = "0.3.1"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["handleapi", "synchapi", "winbase"] }

View file

@ -12,31 +12,14 @@
use std::any::Any; use std::any::Any;
#[cfg(windows)] #[cfg(windows)]
#[allow(nonstandard_style)]
pub fn acquire_global_lock(name: &str) -> Box<dyn Any> { pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
use std::ffi::CString; use std::ffi::CString;
use std::io; use std::io;
type LPSECURITY_ATTRIBUTES = *mut u8; use winapi::shared::ntdef::HANDLE;
type BOOL = i32; use winapi::um::handleapi::CloseHandle;
type LPCSTR = *const u8; use winapi::um::synchapi::{CreateMutexA, ReleaseMutex, WaitForSingleObject};
type HANDLE = *mut u8; use winapi::um::winbase::{INFINITE, WAIT_ABANDONED, WAIT_OBJECT_0};
type DWORD = u32;
const INFINITE: DWORD = !0;
const WAIT_OBJECT_0: DWORD = 0;
const WAIT_ABANDONED: DWORD = 0x00000080;
extern "system" {
fn CreateMutexA(
lpMutexAttributes: LPSECURITY_ATTRIBUTES,
bInitialOwner: BOOL,
lpName: LPCSTR,
) -> HANDLE;
fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
fn ReleaseMutex(hMutex: HANDLE) -> BOOL;
fn CloseHandle(hObject: HANDLE) -> BOOL;
}
struct Handle(HANDLE); struct Handle(HANDLE);
@ -65,7 +48,7 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
// //
// This will silently create one if it doesn't already exist, or it'll // This will silently create one if it doesn't already exist, or it'll
// open up a handle to one if it already exists. // open up a handle to one if it already exists.
let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr() as *const u8); let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr());
if mutex.is_null() { if mutex.is_null() {
panic!( panic!(
"failed to create global mutex named `{}`: {}", "failed to create global mutex named `{}`: {}",

View file

@ -43,6 +43,9 @@ rustc_resolve = { path = "../librustc_resolve" }
tempfile = "3.0.5" tempfile = "3.0.5"
once_cell = "1" once_cell = "1"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["libloaderapi"] }
[dev-dependencies] [dev-dependencies]
rustc_target = { path = "../librustc_target" } rustc_target = { path = "../librustc_target" }

View file

@ -340,19 +340,17 @@ fn sysroot_candidates() -> Vec<PathBuf> {
fn current_dll_path() -> Option<PathBuf> { fn current_dll_path() -> Option<PathBuf> {
use std::ffi::OsString; use std::ffi::OsString;
use std::os::windows::prelude::*; use std::os::windows::prelude::*;
use std::ptr;
extern "system" { use winapi::um::libloaderapi::{
fn GetModuleHandleExW(dwFlags: u32, lpModuleName: usize, phModule: *mut usize) -> i32; GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
fn GetModuleFileNameW(hModule: usize, lpFilename: *mut u16, nSize: u32) -> u32; };
}
const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x00000004;
unsafe { unsafe {
let mut module = 0; let mut module = ptr::null_mut();
let r = GetModuleHandleExW( let r = GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
current_dll_path as usize, current_dll_path as usize as *mut _,
&mut module, &mut module,
); );
if r == 0 { if r == 0 {

View file

@ -215,12 +215,14 @@ fn main() {
let mut cmd = Command::new(&llvm_config); let mut cmd = Command::new(&llvm_config);
cmd.arg(llvm_link_arg).arg("--ldflags"); cmd.arg(llvm_link_arg).arg("--ldflags");
for lib in output(&mut cmd).split_whitespace() { for lib in output(&mut cmd).split_whitespace() {
if lib.starts_with("-LIBPATH:") { if is_crossed {
println!("cargo:rustc-link-search=native={}", &lib[9..]); if lib.starts_with("-LIBPATH:") {
} else if is_crossed { println!("cargo:rustc-link-search=native={}", lib[9..].replace(&host, &target));
if lib.starts_with("-L") { } else if lib.starts_with("-L") {
println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target)); println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target));
} }
} else if lib.starts_with("-LIBPATH:") {
println!("cargo:rustc-link-search=native={}", &lib[9..]);
} else if lib.starts_with("-l") { } else if lib.starts_with("-l") {
println!("cargo:rustc-link-lib={}", &lib[2..]); println!("cargo:rustc-link-lib={}", &lib[2..]);
} else if lib.starts_with("-L") { } else if lib.starts_with("-L") {

View file

@ -27,3 +27,6 @@ rustc_expand = { path = "../librustc_expand" }
rustc_parse = { path = "../librustc_parse" } rustc_parse = { path = "../librustc_parse" }
rustc_span = { path = "../librustc_span" } rustc_span = { path = "../librustc_span" }
rustc_error_codes = { path = "../librustc_error_codes" } rustc_error_codes = { path = "../librustc_error_codes" }
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["errhandlingapi", "libloaderapi"] }

View file

@ -111,9 +111,9 @@ mod dl {
) -> Result<*mut u8, String> { ) -> Result<*mut u8, String> {
check_for_errors_in(|| libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8) check_for_errors_in(|| libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8)
} }
pub(super) unsafe fn close(handle: *mut u8) { pub(super) unsafe fn close(handle: *mut u8) {
libc::dlclose(handle as *mut libc::c_void); libc::dlclose(handle as *mut libc::c_void);
()
} }
} }
@ -124,27 +124,15 @@ mod dl {
use std::os::windows::prelude::*; use std::os::windows::prelude::*;
use std::ptr; use std::ptr;
use libc::{c_char, c_uint, c_void}; use winapi::shared::minwindef::HMODULE;
use winapi::um::errhandlingapi::SetThreadErrorMode;
type DWORD = u32; use winapi::um::libloaderapi::{FreeLibrary, GetModuleHandleExW, GetProcAddress, LoadLibraryW};
type HMODULE = *mut u8; use winapi::um::winbase::SEM_FAILCRITICALERRORS;
type BOOL = i32;
type LPCWSTR = *const u16;
type LPCSTR = *const i8;
extern "system" {
fn SetThreadErrorMode(dwNewMode: DWORD, lpOldMode: *mut DWORD) -> c_uint;
fn LoadLibraryW(name: LPCWSTR) -> HMODULE;
fn GetModuleHandleExW(dwFlags: DWORD, name: LPCWSTR, handle: *mut HMODULE) -> BOOL;
fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void;
fn FreeLibrary(handle: HMODULE) -> BOOL;
}
pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> { pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
// disable "dll load failed" error dialog. // disable "dll load failed" error dialog.
let prev_error_mode = unsafe { let prev_error_mode = unsafe {
// SEM_FAILCRITICALERRORS 0x01 let new_error_mode = SEM_FAILCRITICALERRORS;
let new_error_mode = 1;
let mut prev_error_mode = 0; let mut prev_error_mode = 0;
let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode); let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode);
if result == 0 { if result == 0 {
@ -156,12 +144,12 @@ mod dl {
let result = match filename { let result = match filename {
Some(filename) => { Some(filename) => {
let filename_str: Vec<_> = filename.encode_wide().chain(Some(0)).collect(); let filename_str: Vec<_> = filename.encode_wide().chain(Some(0)).collect();
let result = unsafe { LoadLibraryW(filename_str.as_ptr()) }; let result = unsafe { LoadLibraryW(filename_str.as_ptr()) } as *mut u8;
ptr_result(result) ptr_result(result)
} }
None => { None => {
let mut handle = ptr::null_mut(); let mut handle = ptr::null_mut();
let succeeded = unsafe { GetModuleHandleExW(0 as DWORD, ptr::null(), &mut handle) }; let succeeded = unsafe { GetModuleHandleExW(0, ptr::null(), &mut handle) };
if succeeded == 0 { if succeeded == 0 {
Err(io::Error::last_os_error().to_string()) Err(io::Error::last_os_error().to_string())
} else { } else {
@ -177,7 +165,10 @@ mod dl {
result result
} }
pub(super) unsafe fn symbol(handle: *mut u8, symbol: *const c_char) -> Result<*mut u8, String> { pub(super) unsafe fn symbol(
handle: *mut u8,
symbol: *const libc::c_char,
) -> Result<*mut u8, String> {
let ptr = GetProcAddress(handle as HMODULE, symbol) as *mut u8; let ptr = GetProcAddress(handle as HMODULE, symbol) as *mut u8;
ptr_result(ptr) ptr_result(ptr)
} }

View file

@ -587,12 +587,6 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
// padding. // padding.
match tys.kind { match tys.kind {
ty::Int(..) | ty::Uint(..) | ty::Float(..) => true, ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
ty::Tuple(tys) if tys.len() == 0 => true,
ty::Adt(adt_def, _)
if adt_def.is_struct() && adt_def.all_fields().next().is_none() =>
{
true
}
_ => false, _ => false,
} }
} => } =>
@ -609,11 +603,6 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
} }
// This is the element type size. // This is the element type size.
let layout = self.ecx.layout_of(tys)?; let layout = self.ecx.layout_of(tys)?;
// Empty tuples and fieldless structs (the only ZSTs that allow reaching this code)
// have no data to be checked.
if layout.is_zst() {
return Ok(());
}
// This is the size in bytes of the whole array. // This is the size in bytes of the whole array.
let size = layout.size * len; let size = layout.size * len;
// Size is not 0, get a pointer. // Size is not 0, get a pointer.
@ -656,6 +645,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
} }
} }
} }
// Fast path for arrays and slices of ZSTs. We only need to check a single ZST element
// of an array and not all of them, because there's only a single value of a specific
// ZST type, so either validation fails for all elements or none.
ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(tys)?.is_zst() => {
// Validate just the first element
self.walk_aggregate(op, fields.take(1))?
}
_ => { _ => {
self.walk_aggregate(op, fields)? // default handler self.walk_aggregate(op, fields)? // default handler
} }

View file

@ -14,6 +14,7 @@ use rustc::mir::{
SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
UnOp, RETURN_PLACE, UnOp, RETURN_PLACE,
}; };
use rustc::traits::TraitQueryMode;
use rustc::ty::layout::{ use rustc::ty::layout::{
HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout, HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
}; };
@ -74,6 +75,46 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
return; return;
} }
// Check if it's even possible to satisfy the 'where' clauses
// for this item.
// This branch will never be taken for any normal function.
// However, it's possible to `#!feature(trivial_bounds)]` to write
// a function with impossible to satisfy clauses, e.g.:
// `fn foo() where String: Copy {}`
//
// We don't usually need to worry about this kind of case,
// since we would get a compilation error if the user tried
// to call it. However, since we can do const propagation
// even without any calls to the function, we need to make
// sure that it even makes sense to try to evaluate the body.
// If there are unsatisfiable where clauses, then all bets are
// off, and we just give up.
//
// Note that we use TraitQueryMode::Canonical here, which causes
// us to treat overflow like any other error. This is because we
// are "speculatively" evaluating this item with the default substs.
// While this usually succeeds, it may fail with tricky impls
// (e.g. the typenum crate). Const-propagation is fundamentally
// "best-effort", and does not affect correctness in any way.
// Therefore, it's perfectly fine to just "give up" if we're
// unable to check the bounds with the default substs.
//
// False negatives (failing to run const-prop on something when we actually
// could) are fine. However, false positives (running const-prop on
// an item with unsatisfiable bounds) can lead to us generating invalid
// MIR.
if !tcx.substitute_normalize_and_test_predicates((
source.def_id(),
InternalSubsts::identity_for_item(tcx, source.def_id()),
TraitQueryMode::Canonical,
)) {
trace!(
"ConstProp skipped for item with unsatisfiable predicates: {:?}",
source.def_id()
);
return;
}
trace!("ConstProp starting for {:?}", source.def_id()); trace!("ConstProp starting for {:?}", source.def_id());
let dummy_body = &Body::new( let dummy_body = &Body::new(

View file

@ -1,6 +1,10 @@
// build-pass // build-pass
// ignore-32bit // ignore-32bit
// This test is a canary test that will essentially not compile in a reasonable time frame
// (so it'll take hours) if any of the optimizations regress. With the optimizations, these compile
// in milliseconds just as if the length were set to `1`.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct Foo; struct Foo;
@ -8,4 +12,6 @@ fn main() {
let _ = [(); 4_000_000_000]; let _ = [(); 4_000_000_000];
let _ = [0u8; 4_000_000_000]; let _ = [0u8; 4_000_000_000];
let _ = [Foo; 4_000_000_000]; let _ = [Foo; 4_000_000_000];
let _ = [(Foo, (), Foo, ((), Foo, [0; 0])); 4_000_000_000];
let _ = [[0; 0]; 4_000_000_000];
} }

View file

@ -0,0 +1,20 @@
// check-pass
// compile-flags: --emit=mir,link
// Checks that we don't ICE due to attempting to run const prop
// on a function with unsatisifable 'where' clauses
#![allow(unused)]
trait A {
fn foo(&self) -> Self where Self: Copy;
}
impl A for [fn(&())] {
fn foo(&self) -> Self where Self: Copy { *(&[] as &[_]) }
}
impl A for i32 {
fn foo(&self) -> Self { 3 }
}
fn main() {}

View file

@ -1,5 +1,9 @@
#![feature(const_raw_ptr_deref, never_type)] #![feature(const_raw_ptr_deref, never_type)]
const FOO: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
const _: &[!; 0] = unsafe { &*(1_usize as *const [!; 0]) }; // ok
const _: &[!] = unsafe { &*(1_usize as *const [!; 0]) }; // ok
const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; //~ ERROR undefined behavior
fn main() {} fn main() {}

View file

@ -1,11 +1,27 @@
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/validate_never_arrays.rs:3:1 --> $DIR/validate_never_arrays.rs:3:1
| |
LL | const FOO: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error: aborting due to previous error error[E0080]: it is undefined behavior to use this value
--> $DIR/validate_never_arrays.rs:6:1
|
LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>[0]
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error[E0080]: it is undefined behavior to use this value
--> $DIR/validate_never_arrays.rs:7:1
|
LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>[0]
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0080`. For more information about this error, try `rustc --explain E0080`.

View file

@ -1,4 +1,8 @@
// run-pass // check-pass
// compile-flags: --emit=mir,link
// Force mir to be emitted, to ensure that const
// propagation doesn't ICE on a function
// with an 'impossible' body. See issue #67696
// Inconsistent bounds with trait implementations // Inconsistent bounds with trait implementations
#![feature(trivial_bounds)] #![feature(trivial_bounds)]

View file

@ -42,10 +42,8 @@ mod tests;
#[cfg(windows)] #[cfg(windows)]
fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R { fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
use std::sync::Mutex; use std::sync::Mutex;
const SEM_NOGPFAULTERRORBOX: u32 = 0x0002; use winapi::um::errhandlingapi::SetErrorMode;
extern "system" { use winapi::um::winbase::SEM_NOGPFAULTERRORBOX;
fn SetErrorMode(mode: u32) -> u32;
}
lazy_static! { lazy_static! {
static ref LOCK: Mutex<()> = { Mutex::new(()) }; static ref LOCK: Mutex<()> = { Mutex::new(()) };