From 73996df6291001f0742b6409249329301aa77a23 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 1 Jan 2020 14:43:24 -0500 Subject: [PATCH 01/19] Reset Formatter flags on exit from pad_integral This fixes a bug where after calling pad_integral with appropriate flags, the fill and alignment flags would be set to '0' and 'Right' and left as such even after exiting pad_integral, which meant that future calls on the same Formatter would get incorrect flags reported. This is quite difficult to observe in practice, as almost all formatting implementations in practice don't call `Display::fmt` directly, but rather use `write!` or a similar macro, which means that they cannot observe the effects of the wrong flags (as `write!` creates a fresh Formatter instance). However, we include a test case. --- src/libcore/fmt/mod.rs | 9 ++++++--- src/libcore/tests/fmt/mod.rs | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 6c8d1626b09b6..e68f3c58a3e07 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1244,12 +1244,15 @@ impl<'a> Formatter<'a> { // The sign and prefix goes before the padding if the fill character // is zero Some(min) if self.sign_aware_zero_pad() => { - self.fill = '0'; - self.align = rt::v1::Alignment::Right; + let old_fill = crate::mem::replace(&mut self.fill, '0'); + let old_align = crate::mem::replace(&mut self.align, rt::v1::Alignment::Right); write_prefix(self, sign, prefix)?; let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; 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 Some(min) => { diff --git a/src/libcore/tests/fmt/mod.rs b/src/libcore/tests/fmt/mod.rs index d86e21cf40b6e..7b281ce48e6aa 100644 --- a/src/libcore/tests/fmt/mod.rs +++ b/src/libcore/tests/fmt/mod.rs @@ -28,3 +28,18 @@ fn test_estimated_capacity() { assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 0); 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 "); +} From 7b564c67deb6f5e9d7102871d63a9ad3d7161278 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 4 Jan 2020 16:46:47 -0500 Subject: [PATCH 02/19] use winapi for non-stdlib Windows bindings --- Cargo.lock | 6 ++ src/bootstrap/Cargo.toml | 4 ++ src/bootstrap/job.rs | 88 +++-------------------- src/bootstrap/util.rs | 62 ++++------------ src/librustc/lib.rs | 1 - src/librustc_data_structures/Cargo.toml | 3 + src/librustc_data_structures/flock.rs | 34 +-------- src/librustc_data_structures/lib.rs | 3 - src/librustc_data_structures/profiling.rs | 46 ++++-------- src/librustc_driver/Cargo.toml | 3 + src/librustc_driver/lib.rs | 18 ++--- src/librustc_errors/Cargo.toml | 3 + src/librustc_errors/lock.rs | 27 ++----- src/librustc_interface/Cargo.toml | 3 + src/librustc_interface/util.rs | 14 ++-- src/librustc_metadata/Cargo.toml | 3 + src/librustc_metadata/dynamic_lib.rs | 33 ++++----- src/tools/compiletest/src/runtest.rs | 6 +- 18 files changed, 94 insertions(+), 263 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54ad60e71506b..0e7f91283cfaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -201,6 +201,7 @@ dependencies = [ "serde_json", "time", "toml", + "winapi 0.3.8", ] [[package]] @@ -3491,6 +3492,7 @@ dependencies = [ "serialize", "smallvec 1.0.0", "stable_deref_trait", + "winapi 0.3.8", ] [[package]] @@ -3518,6 +3520,7 @@ dependencies = [ "rustc_target", "serialize", "syntax", + "winapi 0.3.8", ] [[package]] @@ -3537,6 +3540,7 @@ dependencies = [ "term_size", "termcolor", "unicode-width", + "winapi 0.3.8", ] [[package]] @@ -3647,6 +3651,7 @@ dependencies = [ "smallvec 1.0.0", "syntax", "tempfile", + "winapi 0.3.8", ] [[package]] @@ -3715,6 +3720,7 @@ dependencies = [ "smallvec 1.0.0", "stable_deref_trait", "syntax", + "winapi 0.3.8", ] [[package]] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 3ab00a6e147fc..c09f58cc591a6 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -49,5 +49,9 @@ lazy_static = "1.3.0" time = "0.1" ignore = "0.4.10" +[target.'cfg(windows)'.dependencies.winapi] +version = "0.3" +features = ["fileapi", "ioapiset", "jobapi2", "handleapi", "winioctl"] + [dev-dependencies] pretty_assertions = "0.5" diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs index 57153e2ad39f4..efeb86540b7b7 100644 --- a/src/bootstrap/job.rs +++ b/src/bootstrap/job.rs @@ -35,84 +35,16 @@ use std::io; use std::mem; use std::ptr; -type HANDLE = *mut u8; -type BOOL = i32; -type DWORD = u32; -type LPHANDLE = *mut HANDLE; -type LPVOID = *mut u8; -type JOBOBJECTINFOCLASS = i32; -type SIZE_T = usize; -type LARGE_INTEGER = i64; -type UINT = u32; -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, -} +use winapi::shared::minwindef::{DWORD, FALSE, LPVOID}; +use winapi::um::errhandlingapi::SetErrorMode; +use winapi::um::handleapi::{CloseHandle, DuplicateHandle}; +use winapi::um::jobapi2::{AssignProcessToJobObject, CreateJobObjectW, SetInformationJobObject}; +use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcess}; +use winapi::um::winbase::{BELOW_NORMAL_PRIORITY_CLASS, SEM_NOGPFAULTERRORBOX}; +use winapi::um::winnt::{ + JobObjectExtendedLimitInformation, DUPLICATE_SAME_ACCESS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, PROCESS_DUP_HANDLE, +}; pub unsafe fn setup(build: &mut Build) { // Enable the Windows Error Reporting dialog which msys disables, diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 5fd25981851d4..7d1efe4610f9c 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -123,37 +123,24 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { // what can be found here: // // http://www.flexhex.com/docs/articles/hard-links.phtml - // - // Copied from std #[cfg(windows)] - #[allow(nonstandard_style)] fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> { use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; use std::ptr; - const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; - const GENERIC_WRITE: DWORD = 0x40000000; - const OPEN_EXISTING: DWORD = 3; - const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000; - const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000; - const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4; - const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003; - const FILE_SHARE_DELETE: DWORD = 0x4; - const FILE_SHARE_READ: DWORD = 0x1; - 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; - + use winapi::shared::minwindef::{DWORD, WORD}; + use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING}; + use winapi::um::handleapi::CloseHandle; + use winapi::um::ioapiset::DeviceIoControl; + use winapi::um::winbase::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT}; + use winapi::um::winioctl::FSCTL_SET_REPARSE_POINT; + use winapi::um::winnt::{ + FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_WRITE, + IO_REPARSE_TAG_MOUNT_POINT, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, WCHAR, + }; + + #[allow(non_snake_case)] #[repr(C)] struct REPARSE_MOUNTPOINT_DATA_BUFFER { ReparseTag: DWORD, @@ -165,29 +152,6 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { 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: S) -> io::Result> { 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(), ); - 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 buf = &mut (*db).ReparseTarget as *mut u16; let mut i = 0; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 3c0160a04527e..30372e4af5033 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -34,7 +34,6 @@ #![feature(const_transmute)] #![feature(core_intrinsics)] #![feature(drain_filter)] -#![cfg_attr(windows, feature(libc))] #![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(overlapping_marker_traits)] diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 19db9834fd48e..fb4f818c4b249 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -31,3 +31,6 @@ measureme = "0.7.1" [dependencies.parking_lot] version = "0.9" features = ["nightly"] + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["fileapi", "psapi"] } diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index e3282c5d276b0..2a0139fa90d5a 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -87,39 +87,11 @@ cfg_if! { } else if #[cfg(windows)] { use std::mem; use std::os::windows::prelude::*; - use std::os::windows::raw::HANDLE; use std::fs::{File, OpenOptions}; - use std::os::raw::{c_ulong, c_int}; - - type DWORD = c_ulong; - type BOOL = c_int; - type ULONG_PTR = usize; - - 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; - } + use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK}; + use winapi::um::fileapi::LockFileEx; + use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE}; #[derive(Debug)] pub struct Lock { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 51a38a7d2ab9c..6db2910bca496 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -33,9 +33,6 @@ extern crate libc; #[macro_use] extern crate cfg_if; -#[cfg(windows)] -extern crate libc; - pub use rustc_serialize::hex::ToHex; #[inline(never)] diff --git a/src/librustc_data_structures/profiling.rs b/src/librustc_data_structures/profiling.rs index 8deb43d50f938..004db0a79a880 100644 --- a/src/librustc_data_structures/profiling.rs +++ b/src/librustc_data_structures/profiling.rs @@ -569,39 +569,19 @@ fn get_resident() -> Option { #[cfg(windows)] fn get_resident() -> Option { - type BOOL = i32; - type DWORD = u32; - type HANDLE = *mut u8; - use libc::size_t; - #[repr(C)] - #[allow(non_snake_case)] - struct PROCESS_MEMORY_COUNTERS { - cb: 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) } { + use std::mem::{self, MaybeUninit}; + use winapi::shared::minwindef::DWORD; + use winapi::um::processthreadsapi::GetCurrentProcess; + use winapi::um::psapi::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}; + + let mut pmc = MaybeUninit::::uninit(); + match unsafe { + GetProcessMemoryInfo(GetCurrentProcess(), pmc.as_mut_ptr(), mem::size_of_val(&pmc) as DWORD) + } { 0 => None, - _ => Some(pmc.WorkingSetSize as usize), + _ => { + let pmc = unsafe { pmc.assume_init() }; + Some(pmc.WorkingSetSize as usize) + } } } diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 37449f9402eff..b856e5da5a093 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -32,5 +32,8 @@ rustc_serialize = { path = "../libserialize", package = "serialize" } syntax = { path = "../libsyntax" } rustc_span = { path = "../librustc_span" } +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] } + [features] llvm = ['rustc_interface/llvm'] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 3d31f240a34e0..5aba824e32c7a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -515,15 +515,10 @@ fn stdout_isatty() -> bool { #[cfg(windows)] fn stdout_isatty() -> bool { - type DWORD = u32; - type BOOL = i32; - type HANDLE = *mut u8; - 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; - } + use winapi::um::consoleapi::GetConsoleMode; + use winapi::um::processenv::GetStdHandle; + use winapi::um::winbase::STD_OUTPUT_HANDLE; + unsafe { let handle = GetStdHandle(STD_OUTPUT_HANDLE); let mut out = 0; @@ -1215,11 +1210,8 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { #[cfg(windows)] unsafe { if env::var("RUSTC_BREAK_ON_ICE").is_ok() { - extern "system" { - fn DebugBreak(); - } // Trigger a debugger if we crashed during bootstrap - DebugBreak(); + winapi::um::debugapi::DebugBreak(); } } } diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index 0d0989677c585..01ea80659d6b9 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -19,3 +19,6 @@ atty = "0.2" termcolor = "1.0" annotate-snippets = "0.6.1" term_size = "0.3.1" + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["handleapi", "synchapi", "winbase"] } diff --git a/src/librustc_errors/lock.rs b/src/librustc_errors/lock.rs index 198a9c12406e5..a73472021d412 100644 --- a/src/librustc_errors/lock.rs +++ b/src/librustc_errors/lock.rs @@ -12,31 +12,14 @@ use std::any::Any; #[cfg(windows)] -#[allow(nonstandard_style)] pub fn acquire_global_lock(name: &str) -> Box { use std::ffi::CString; use std::io; - type LPSECURITY_ATTRIBUTES = *mut u8; - type BOOL = i32; - type LPCSTR = *const u8; - type HANDLE = *mut u8; - 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; - } + use winapi::shared::ntdef::HANDLE; + use winapi::um::handleapi::CloseHandle; + use winapi::um::synchapi::{CreateMutexA, ReleaseMutex, WaitForSingleObject}; + use winapi::um::winbase::{INFINITE, WAIT_ABANDONED, WAIT_OBJECT_0}; struct Handle(HANDLE); @@ -65,7 +48,7 @@ pub fn acquire_global_lock(name: &str) -> Box { // // This will silently create one if it doesn't already exist, or it'll // 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() { panic!( "failed to create global mutex named `{}`: {}", diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index eb0551c606548..548985c451408 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -42,6 +42,9 @@ rustc_resolve = { path = "../librustc_resolve" } tempfile = "3.0.5" once_cell = "1" +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["libloaderapi"] } + [dev-dependencies] rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 2fafd3af7a5ff..21f9fa4816591 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -340,19 +340,17 @@ fn sysroot_candidates() -> Vec { fn current_dll_path() -> Option { use std::ffi::OsString; use std::os::windows::prelude::*; + use std::ptr; - extern "system" { - fn GetModuleHandleExW(dwFlags: u32, lpModuleName: usize, phModule: *mut usize) -> i32; - fn GetModuleFileNameW(hModule: usize, lpFilename: *mut u16, nSize: u32) -> u32; - } - - const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x00000004; + use winapi::um::libloaderapi::{ + GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + }; unsafe { - let mut module = 0; + let mut module = ptr::null_mut(); let r = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - current_dll_path as usize, + current_dll_path as usize as *mut _, &mut module, ); if r == 0 { diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 48767c377a94c..0a0bcb190bea7 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -27,3 +27,6 @@ rustc_expand = { path = "../librustc_expand" } rustc_parse = { path = "../librustc_parse" } rustc_span = { path = "../librustc_span" } rustc_error_codes = { path = "../librustc_error_codes" } + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["errhandlingapi", "libloaderapi"] } diff --git a/src/librustc_metadata/dynamic_lib.rs b/src/librustc_metadata/dynamic_lib.rs index fa4983d8a815e..f04d0239d4923 100644 --- a/src/librustc_metadata/dynamic_lib.rs +++ b/src/librustc_metadata/dynamic_lib.rs @@ -111,9 +111,9 @@ mod dl { ) -> Result<*mut u8, String> { check_for_errors_in(|| libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8) } + pub(super) unsafe fn close(handle: *mut u8) { libc::dlclose(handle as *mut libc::c_void); - () } } @@ -124,27 +124,15 @@ mod dl { use std::os::windows::prelude::*; use std::ptr; - use libc::{c_char, c_uint, c_void}; - - type DWORD = u32; - type HMODULE = *mut u8; - 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; - } + use winapi::shared::minwindef::HMODULE; + use winapi::um::errhandlingapi::SetThreadErrorMode; + use winapi::um::libloaderapi::{FreeLibrary, GetModuleHandleExW, GetProcAddress, LoadLibraryW}; + use winapi::um::winbase::SEM_FAILCRITICALERRORS; pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> { // disable "dll load failed" error dialog. let prev_error_mode = unsafe { - // SEM_FAILCRITICALERRORS 0x01 - let new_error_mode = 1; + let new_error_mode = SEM_FAILCRITICALERRORS; let mut prev_error_mode = 0; let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode); if result == 0 { @@ -156,12 +144,12 @@ mod dl { let result = match filename { Some(filename) => { 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) } None => { 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 { Err(io::Error::last_os_error().to_string()) } else { @@ -177,7 +165,10 @@ mod dl { 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; ptr_result(ptr) } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1912c9ef5baeb..3a114a0b71517 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -42,10 +42,8 @@ mod tests; #[cfg(windows)] fn disable_error_reporting R, R>(f: F) -> R { use std::sync::Mutex; - const SEM_NOGPFAULTERRORBOX: u32 = 0x0002; - extern "system" { - fn SetErrorMode(mode: u32) -> u32; - } + use winapi::um::errhandlingapi::SetErrorMode; + use winapi::um::winbase::SEM_NOGPFAULTERRORBOX; lazy_static! { static ref LOCK: Mutex<()> = { Mutex::new(()) }; From 5896998e7659bf22ffb804956a3680c028ede45f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 5 Jan 2020 22:32:53 -0500 Subject: [PATCH 03/19] Don't run const propagation on items with inconsistent bounds Using `#![feature(trivial_bounds)]`, it's possible to write functions with unsatisfiable 'where' clauses, making them uncallable. However, the user can act as if these 'where' clauses are true inside the body of the function, leading to code that would normally be impossible to write. Since const propgation can run even without any user-written calls to a function, we need to explcitly check for these uncallable functions. --- src/librustc_mir/transform/const_prop.rs | 25 +++++++++++++++++++ ...ounds-inconsistent-associated-functions.rs | 4 +++ ...s-inconsistent-associated-functions.stderr | 2 ++ 3 files changed, 31 insertions(+) create mode 100644 src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.stderr diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 1d5a643484a73..48ab24a14c7c6 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -74,6 +74,31 @@ impl<'tcx> MirPass<'tcx> for ConstProp { return; } + // Check if it's even possible to satisy 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. + if !tcx.substitute_normalize_and_test_predicates(( + source.def_id(), + InternalSubsts::identity_for_item(tcx, source.def_id()), + )) { + trace!( + "ConstProp skipped for item with unsatisfiable predicates: {:?}", + source.def_id() + ); + return; + } + trace!("ConstProp starting for {:?}", source.def_id()); let dummy_body = &Body::new( diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs index 6450ddd1b67fc..818be10554720 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs @@ -1,4 +1,8 @@ // run-pass +// Force mir to be emitted, to ensure that const +// propagation doesn't ICE on a function +// with an 'impossible' body. See issue #67696 +// compile-flags: --emit=mir,link // Inconsistent bounds with trait implementations #![feature(trivial_bounds)] diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.stderr new file mode 100644 index 0000000000000..0ee1e2e0ba56a --- /dev/null +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.stderr @@ -0,0 +1,2 @@ +warning: due to multiple output types requested, the explicitly specified output file name will be adapted for each output type + From e1fc22c4eba6e07a5549c74b197fbaa53f7b29e1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 7 Jan 2020 10:01:52 -0500 Subject: [PATCH 04/19] Add additional regression test --- .../ui/consts/issue-67696-const-prop-ice.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/ui/consts/issue-67696-const-prop-ice.rs diff --git a/src/test/ui/consts/issue-67696-const-prop-ice.rs b/src/test/ui/consts/issue-67696-const-prop-ice.rs new file mode 100644 index 0000000000000..ad52608b3f46d --- /dev/null +++ b/src/test/ui/consts/issue-67696-const-prop-ice.rs @@ -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() {} From 92d86cc9b8bbd744c5eebf3718a9dc87576b786c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 7 Jan 2020 10:53:04 -0500 Subject: [PATCH 05/19] Fix typo --- src/librustc_mir/transform/const_prop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 48ab24a14c7c6..35dbf2f7eaa42 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -74,7 +74,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { return; } - // Check if it's even possible to satisy the 'where' clauses + // 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 From 7df8ca29545301c1d3020bf8fc9aa8f9fd8759ea Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 11 Jan 2020 13:20:09 -0500 Subject: [PATCH 06/19] Convert test to check-pass --- .../trivial-bounds-inconsistent-associated-functions.rs | 4 ++-- .../trivial-bounds-inconsistent-associated-functions.stderr | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) delete mode 100644 src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.stderr diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs index 818be10554720..e0d4d538b40e7 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs @@ -1,8 +1,8 @@ -// run-pass +// check-pass +// compile-flags: --emit=mir // Force mir to be emitted, to ensure that const // propagation doesn't ICE on a function // with an 'impossible' body. See issue #67696 -// compile-flags: --emit=mir,link // Inconsistent bounds with trait implementations #![feature(trivial_bounds)] diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.stderr deleted file mode 100644 index 0ee1e2e0ba56a..0000000000000 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: due to multiple output types requested, the explicitly specified output file name will be adapted for each output type - From 6a0bb1867b2026e05982f865bb48857d7e492cd7 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 11 Jan 2020 14:17:42 -0500 Subject: [PATCH 07/19] Add "--emit=link" This avoids a strange linker error that we get with only "--emit=mir" and "check-pass" --- .../trivial-bounds-inconsistent-associated-functions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs index e0d4d538b40e7..69eee66e64d89 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs @@ -1,5 +1,5 @@ // check-pass -// compile-flags: --emit=mir +// 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 From e390b91e5717a338db20360a1ddffa23ba66701d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 13 Jan 2020 06:06:42 -0500 Subject: [PATCH 08/19] Use TraitQueryMode::Canonical when testing predicates in const prop --- src/librustc/mir/mono.rs | 5 ++++- src/librustc/query/mod.rs | 6 +++--- src/librustc/traits/fulfill.rs | 24 ++++++++++++++++++++++-- src/librustc/traits/mod.rs | 18 +++++++++++------- src/librustc/ty/query/keys.rs | 9 +++++++++ src/librustc_mir/transform/const_prop.rs | 16 ++++++++++++++++ 6 files changed, 65 insertions(+), 13 deletions(-) diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 51ce575e51f3b..e7a4c5b592105 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -1,6 +1,7 @@ use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId}; use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext}; use crate::session::config::OptLevel; +use crate::traits::TraitQueryMode; use crate::ty::print::obsolete::DefPathBasedNames; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; use rustc_data_structures::base_n; @@ -167,7 +168,9 @@ impl<'tcx> MonoItem<'tcx> { 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 { diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 50ef115da2c42..669ba4abfadd8 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -1141,11 +1141,11 @@ rustc_queries! { 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 desc { |tcx| - "testing substituted normalized predicates:`{}`", - tcx.def_path_str(key.0) + "testing substituted normalized predicates in mode {:?}:`{}`", + key.2, tcx.def_path_str(key.0) } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 46ece6fc40593..9e5abc80822c7 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -16,6 +16,7 @@ use super::CodeSelectionError; use super::{ConstEvalFailure, Unimplemented}; use super::{FulfillmentError, FulfillmentErrorCode}; use super::{ObligationCause, PredicateObligation}; +use crate::traits::TraitQueryMode; impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { type Predicate = ty::Predicate<'tcx>; @@ -62,6 +63,9 @@ pub struct FulfillmentContext<'tcx> { // a snapshot (they don't *straddle* a snapshot, so there // is no trouble there). usable_in_snapshot: bool, + + // The `TraitQueryMode` used when constructing a `SelectionContext` + query_mode: TraitQueryMode, } #[derive(Clone, Debug)] @@ -75,12 +79,26 @@ pub struct PendingPredicateObligation<'tcx> { static_assert_size!(PendingPredicateObligation<'_>, 136); 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> { FulfillmentContext { predicates: ObligationForest::new(), register_region_obligations: true, 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(), register_region_obligations: true, usable_in_snapshot: true, + query_mode: TraitQueryMode::Standard, } } @@ -97,6 +116,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { predicates: ObligationForest::new(), register_region_obligations: false, usable_in_snapshot: false, + query_mode: TraitQueryMode::Standard, } } @@ -217,7 +237,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { &mut self, infcx: &InferCtxt<'_, 'tcx>, ) -> Result<(), Vec>> { - let mut selcx = SelectionContext::new(infcx); + let mut selcx = SelectionContext::with_query_mode(infcx, self.query_mode); self.select(&mut selcx) } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 2d3160dc3e51a..31de5409fc8be 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -95,7 +95,7 @@ pub enum IntercrateMode { } /// The mode that trait queries run in. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, HashStable)] pub enum TraitQueryMode { // Standard/un-canonicalized queries get accurate // spans etc. passed in and hence can do reasonable @@ -1017,13 +1017,14 @@ where fn normalize_and_test_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: Vec>, + mode: TraitQueryMode, ) -> 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 param_env = ty::ParamEnv::reveal_all(); - let mut selcx = SelectionContext::new(&infcx); - let mut fulfill_cx = FulfillmentContext::new(); + let mut selcx = SelectionContext::with_query_mode(&infcx, mode); + let mut fulfill_cx = FulfillmentContext::with_query_mode(mode); let cause = ObligationCause::dummy(); let Normalized { value: predicates, obligations } = 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>( tcx: TyCtxt<'tcx>, - key: (DefId, SubstsRef<'tcx>), + key: (DefId, SubstsRef<'tcx>, TraitQueryMode), ) -> bool { debug!("substitute_normalize_and_test_predicates(key={:?})", key); 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); result @@ -1101,7 +1102,10 @@ fn vtable_methods<'tcx>( // Note that this method could then never be called, so we // do not want to try and codegen it, in that case (see #23435). 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"); return None; } diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index d64f27d9cc26c..20f8e7f564abd 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -115,6 +115,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>) { fn query_crate(&self) -> CrateNum { self.1.def_id().krate diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 35dbf2f7eaa42..90c97480c7562 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -14,6 +14,7 @@ use rustc::mir::{ SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, }; +use rustc::traits::TraitQueryMode; use rustc::ty::layout::{ HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout, }; @@ -88,9 +89,24 @@ impl<'tcx> MirPass<'tcx> for ConstProp { // 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: {:?}", From 5076a3efc707436c20c62f90e5df47e78052ed2d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 14 Jan 2020 14:04:03 +0100 Subject: [PATCH 09/19] Add failing example for E0170 explanation --- src/librustc_error_codes/error_codes/E0170.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/librustc_error_codes/error_codes/E0170.md b/src/librustc_error_codes/error_codes/E0170.md index 4b870dbf22155..56e1b5aa241d2 100644 --- a/src/librustc_error_codes/error_codes/E0170.md +++ b/src/librustc_error_codes/error_codes/E0170.md @@ -1,3 +1,24 @@ +A pattern binding is using the same name as one of the variants 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: ``` From 6faad6dc7a0ad1524e3c490f4ea99c998ce9ae04 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 13 Jan 2020 17:58:37 +0100 Subject: [PATCH 10/19] Untangle ZST validation from integer validation and generalize it to all zsts --- src/librustc_mir/interpret/validity.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 2f0fb81fffd13..6934ec0bdb6aa 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -587,12 +587,6 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // padding. match tys.kind { 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, } } => @@ -609,11 +603,6 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } // This is the element type size. 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. let size = layout.size * len; // 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 } From 87504173b3bb948ca0292055fbeb833fc5a41400 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 Jan 2020 09:59:46 -0800 Subject: [PATCH 11/19] Update the wasi-libc bundled with libstd --- src/ci/docker/dist-various-2/build-wasi-toolchain.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh index 925d5ca0223b1..b868677564298 100755 --- a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh @@ -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 cd wasi-libc -git reset --hard f645f498dfbbbc00a7a97874d33082d3605c3f21 +git reset --hard 1fad33890a5e299027ce0eab7b6ad5260585e347 make -j$(nproc) INSTALL_DIR=/wasm32-wasi install cd .. From 9f1452f6996935f796daadab05a956fd0ae69196 Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 14 Jan 2020 11:26:03 -0800 Subject: [PATCH 12/19] Update libssh2-sys to a version that can build for aarch64-pc-windows-msvc --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4836e15cd799a..202c297b82de2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1806,9 +1806,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d" +checksum = "36aa6e813339d3a063292b77091dfbbb6152ff9006a459895fa5bebed7d34f10" dependencies = [ "cc", "libc", From 535fc9ce4c97598f7cc1a093c9cd506a81e22689 Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 14 Jan 2020 11:52:46 -0800 Subject: [PATCH 13/19] Update iovec to a version with no winapi dependency --- Cargo.lock | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4836e15cd799a..9eedab0a1d093 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1581,12 +1581,11 @@ dependencies = [ [[package]] name = "iovec" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" dependencies = [ "libc", - "winapi 0.2.8", ] [[package]] From 9febc2bc7a3a6397ca7e30155924d2d180a5e940 Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 14 Jan 2020 11:56:51 -0800 Subject: [PATCH 14/19] Update to a version of cmake with windows arm64 support --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4836e15cd799a..602e0ae150a73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -514,9 +514,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.38" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96210eec534fc3fbfc0452a63769424eaa80205fda6cea98e5b61cb3d97bcec8" +checksum = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" dependencies = [ "cc", ] From 7d6271b76b7ee7a192e03933ed6b37e6e6385c08 Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Fri, 10 Jan 2020 09:11:32 -0800 Subject: [PATCH 15/19] Better support for cross compilation on Windows. --- src/bootstrap/native.rs | 2 ++ src/librustc_llvm/build.rs | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index ce977f1bbc44e..89e1a7319cf59 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -230,6 +230,8 @@ impl Step for Llvm { cfg.define("CMAKE_SYSTEM_NAME", "NetBSD"); } else if target.contains("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")); diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index dff20f8741065..405ce0307cd82 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -215,12 +215,14 @@ fn main() { let mut cmd = Command::new(&llvm_config); cmd.arg(llvm_link_arg).arg("--ldflags"); for lib in output(&mut cmd).split_whitespace() { - if lib.starts_with("-LIBPATH:") { - println!("cargo:rustc-link-search=native={}", &lib[9..]); - } else if is_crossed { - if lib.starts_with("-L") { + if is_crossed { + if lib.starts_with("-LIBPATH:") { + println!("cargo:rustc-link-search=native={}", lib[9..].replace(&host, &target)); + } else if lib.starts_with("-L") { 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") { println!("cargo:rustc-link-lib={}", &lib[2..]); } else if lib.starts_with("-L") { From 106fe0b13a60c678c7a3372b8ef3f6160549ad5c Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 14 Jan 2020 13:32:26 -0800 Subject: [PATCH 16/19] Update to a version of compiler_builtins with changes for fixes remainder for aarch64 windows --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4836e15cd799a..08b22e629d221 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -570,9 +570,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f083abf9bb9005a27d2da62706f661245278cb7096da37ab27410eaf60f2c1" +checksum = "b9975aefa63997ef75ca9cf013ff1bb81487aaa0b622c21053afd3b92979a7af" dependencies = [ "cc", "rustc-std-workspace-core", From 01dc44bfe00e374cf769cee5757d0ac97faa15a2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 14 Jan 2020 14:26:35 -0500 Subject: [PATCH 17/19] Avoid calling tcx.hir().get() on CRATE_HIR_ID This was causing an ICE when enabling trace logging for an unrelated module, since the arguments to `trace!` ended up getting evaluated --- src/librustc/infer/opaque_types/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index a1afb1a86be44..ee214bea7b8fc 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -1219,7 +1219,7 @@ pub fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: DefId, opaque_hir_id: hir let res = hir_id == scope; trace!( "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}", - tcx.hir().get(hir_id), + tcx.hir().find(hir_id), tcx.hir().get(opaque_hir_id), res ); From 6801cf436bf3549db72c364a912da43ac38d0e79 Mon Sep 17 00:00:00 2001 From: Dylan DPC Date: Wed, 15 Jan 2020 11:52:21 +0530 Subject: [PATCH 18/19] Update E0170.md --- src/librustc_error_codes/error_codes/E0170.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0170.md b/src/librustc_error_codes/error_codes/E0170.md index 56e1b5aa241d2..9678cd173b7ca 100644 --- a/src/librustc_error_codes/error_codes/E0170.md +++ b/src/librustc_error_codes/error_codes/E0170.md @@ -1,4 +1,4 @@ -A pattern binding is using the same name as one of the variants a type. +A pattern binding is using the same name as one of the variants of a type. Erroneous code example: From 0e14b9ff268b6987f935847d7857969a69b7ee7d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 15 Jan 2020 10:30:26 +0100 Subject: [PATCH 19/19] Add tests --- src/test/ui/consts/huge-values.rs | 6 +++++ src/test/ui/consts/validate_never_arrays.rs | 6 ++++- .../ui/consts/validate_never_arrays.stderr | 22 ++++++++++++++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/test/ui/consts/huge-values.rs b/src/test/ui/consts/huge-values.rs index ab09922d7614a..70a5b10e9be99 100644 --- a/src/test/ui/consts/huge-values.rs +++ b/src/test/ui/consts/huge-values.rs @@ -1,6 +1,10 @@ // build-pass // 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)] struct Foo; @@ -8,4 +12,6 @@ fn main() { let _ = [(); 4_000_000_000]; let _ = [0u8; 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]; } diff --git a/src/test/ui/consts/validate_never_arrays.rs b/src/test/ui/consts/validate_never_arrays.rs index 9610b7b22f161..c7144f05ec7a4 100644 --- a/src/test/ui/consts/validate_never_arrays.rs +++ b/src/test/ui/consts/validate_never_arrays.rs @@ -1,5 +1,9 @@ #![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() {} diff --git a/src/test/ui/consts/validate_never_arrays.stderr b/src/test/ui/consts/validate_never_arrays.stderr index c4c7a33718279..cb995b8216f4e 100644 --- a/src/test/ui/consts/validate_never_arrays.stderr +++ b/src/test/ui/consts/validate_never_arrays.stderr @@ -1,11 +1,27 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:3:1 | -LL | const FOO: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at . +LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at . | = 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 .[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 .[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`.