diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0bcb3219858c9..16113a32d2448 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,6 +83,21 @@ feature. We use the 'fork and pull' model described there. Please make pull requests against the `master` branch. +Compiling all of `make check` can take a while. When testing your pull request, +consider using one of the more specialized `make` targets to cut down on the +amount of time you have to wait. You need to have built the compiler at least +once before running these will work, but that’s only one full build rather than +one each time. + + $ make -j8 rustc-stage1 && make check-stage1 + +is one such example, which builds just `rustc`, and then runs the tests. If +you’re adding something to the standard library, try + + $ make -j8 check-stage1-std NO_REBUILD=1 + +This will not rebuild the compiler, but will run the tests. + All pull requests are reviewed by another person. We have a bot, @rust-highfive, that will automatically assign a random person to review your request. @@ -108,6 +123,10 @@ will run all the tests on every platform we support. If it all works out, [merge-queue]: http://buildbot.rust-lang.org/homu/queue/rust +Speaking of tests, Rust has a comprehensive test suite. More information about +it can be found +[here](https://github.com/rust-lang/rust-wiki-backup/blob/master/Note-testsuite.md). + ## Writing Documentation Documentation improvements are very welcome. The source of `doc.rust-lang.org` diff --git a/mk/main.mk b/mk/main.mk index 39261191fb74f..964ae626d0c8d 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -295,7 +295,6 @@ LLVM_BINDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --bindir) LLVM_INCDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --includedir) LLVM_LIBDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libdir) LLVM_LIBDIR_RUSTFLAGS_$(1)=-L "$$(LLVM_LIBDIR_$(1))" -LLVM_LIBS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libs $$(LLVM_COMPONENTS)) LLVM_LDFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --ldflags) ifeq ($$(findstring freebsd,$(1)),freebsd) # On FreeBSD, it may search wrong headers (that are for pre-installed LLVM), diff --git a/mk/target.mk b/mk/target.mk index c398950965f54..c2de9af39c764 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -249,11 +249,9 @@ endef $(foreach host,$(CFG_HOST), \ $(foreach target,$(CFG_TARGET), \ - $(foreach stage,$(STAGES), \ - $(foreach crate,$(CRATES), \ - $(eval $(call SETUP_LIB_MSVC_ENV_VARS,$(stage),$(target),$(host),$(crate))))))) + $(foreach crate,$(CRATES), \ + $(eval $(call SETUP_LIB_MSVC_ENV_VARS,0,$(target),$(host),$(crate)))))) $(foreach host,$(CFG_HOST), \ $(foreach target,$(CFG_TARGET), \ - $(foreach stage,$(STAGES), \ - $(foreach tool,$(TOOLS), \ - $(eval $(call SETUP_TOOL_MSVC_ENV_VARS,$(stage),$(target),$(host),$(tool))))))) + $(foreach tool,$(TOOLS), \ + $(eval $(call SETUP_TOOL_MSVC_ENV_VARS,0,$(target),$(host),$(tool)))))) diff --git a/src/doc/reference.md b/src/doc/reference.md index bdd4ba026d6f0..060f954274a9d 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2515,9 +2515,8 @@ Here are some examples: #### Moved and copied types When a [local variable](#variables) is used as an -[rvalue](#lvalues,-rvalues-and-temporaries) the variable will either be moved -or copied, depending on its type. All values whose type implements `Copy` are -copied, all others are moved. +[rvalue](#lvalues,-rvalues-and-temporaries), the variable will be copied +if its type implements `Copy`. All others are moved. ### Literal expressions @@ -2882,7 +2881,6 @@ operand. ``` # let mut x = 0; # let y = 0; - x = y; ``` diff --git a/src/doc/trpl/comments.md b/src/doc/trpl/comments.md index 7687d2a57da92..e7eb48dc42c52 100644 --- a/src/doc/trpl/comments.md +++ b/src/doc/trpl/comments.md @@ -38,6 +38,17 @@ fn add_one(x: i32) -> i32 { } ``` +There is another style of doc comment, `//!`, to comment containing items (e.g. +crates, modules or functions), instead of the items following it. Commonly used +inside crates root (lib.rs) or modules root (mod.rs): + +``` +//! # The Rust Standard Library +//! +//! The Rust Standard Library provides the essential runtime +//! functionality for building portable Rust software. +``` + When writing doc comments, providing some examples of usage is very, very helpful. You’ll notice we’ve used a new macro here: `assert_eq!`. This compares two values, and `panic!`s if they’re not equal to each other. It’s very helpful diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 442a1f062ef47..cbedf86371414 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -533,19 +533,10 @@ attribute turns off Rust's name mangling, so that it is easier to link to. # FFI and panics -It’s important to be mindful of `panic!`s when working with FFI. This code, -when called from C, will `abort`: - -```rust -#[no_mangle] -pub extern fn oh_no() -> ! { - panic!("Oops!"); -} -# fn main() {} -``` - -If you’re writing code that may panic, you should run it in another thread, -so that the panic doesn’t bubble up to C: +It’s important to be mindful of `panic!`s when working with FFI. A `panic!` +across an FFI boundary is undefined behavior. If you’re writing code that may +panic, you should run it in another thread, so that the panic doesn’t bubble up +to C: ```rust use std::thread; diff --git a/src/doc/trpl/patterns.md b/src/doc/trpl/patterns.md index 7a1f8bf21bf34..9603eec7aca71 100644 --- a/src/doc/trpl/patterns.md +++ b/src/doc/trpl/patterns.md @@ -282,6 +282,38 @@ This ‘destructuring’ behavior works on any compound data type, like [tuples]: primitive-types.html#tuples [enums]: enums.html +# Ignoring bindings + +You can use `_` in a pattern to disregard the value. For example, here’s a +`match` against a `Result`: + +```rust +# let some_value: Result = Err("There was an error"); +match some_value { + Ok(value) => println!("got a value: {}", value), + Err(_) => println!("an error occurred"), +} +``` + +In the first arm, we bind the value inside the `Ok` variant to `value`. But +in the `Err` arm, we use `_` to disregard the specific error, and just print +a general error message. + +`_` is valid in any pattern that creates a binding. This can be useful to +ignore parts of a larger structure: + +```rust +fn coordinate() -> (i32, i32, i32) { + // generate and return some sort of triple tuple +# (1, 2, 3) +} + +let (x, _, z) = coordinate(); +``` + +Here, we bind the first and last element of the tuple to `x` and `z`, but +ignore the middle element. + # Mix and Match Whew! That’s a lot of different ways to match things, and they can all be diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py index 7a925fa3f3367..1cc65406b2c00 100644 --- a/src/etc/mklldeps.py +++ b/src/etc/mklldeps.py @@ -14,10 +14,9 @@ f = open(sys.argv[1], 'wb') -components = sys.argv[2].split(' ') -components = [i for i in components if i] # ignore extra whitespaces +components = sys.argv[2].split() # splits on whitespace enable_static = sys.argv[3] -llconfig = sys.argv[4] +llvm_config = sys.argv[4] f.write("""// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at @@ -39,7 +38,7 @@ def run(args): out, err = proc.communicate() if err: - print("failed to run llconfig: args = `{}`".format(args)) + print("failed to run llvm_config: args = `{}`".format(args)) print(err) sys.exit(1) return out @@ -47,7 +46,7 @@ def run(args): f.write("\n") # LLVM libs -args = [llconfig, '--libs', '--system-libs'] +args = [llvm_config, '--libs', '--system-libs'] args.extend(components) out = run(args) @@ -69,13 +68,13 @@ def run(args): f.write(")]\n") # LLVM ldflags -out = run([llconfig, '--ldflags']) +out = run([llvm_config, '--ldflags']) for lib in out.strip().split(' '): if lib[:2] == "-l": f.write("#[link(name = \"" + lib[2:] + "\")]\n") # C++ runtime library -out = run([llconfig, '--cxxflags']) +out = run([llvm_config, '--cxxflags']) if enable_static == '1': assert('stdlib=libc++' not in out) f.write("#[link(name = \"stdc++\", kind = \"static\")]\n") diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index f66811e561adf..2c5ebc25f6bde 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -6128,7 +6128,7 @@ pub mod funcs { use types::os::arch::c95::{c_char, c_uchar, c_int, c_uint, c_ulong, size_t}; extern { - pub fn ioctl(d: c_int, request: c_ulong, ...) -> c_int; + pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; pub fn sysctl(name: *mut c_int, namelen: c_uint, oldp: *mut c_void, @@ -6160,12 +6160,12 @@ pub mod funcs { #[cfg(any(target_os = "linux", target_os = "android"))] pub mod bsd44 { use types::common::c95::{c_void}; - use types::os::arch::c95::{c_uchar, c_int, size_t}; + use types::os::arch::c95::{c_uchar, c_int, c_ulong, size_t}; extern { #[cfg(not(all(target_os = "android", target_arch = "aarch64")))] pub fn getdtablesize() -> c_int; - pub fn ioctl(d: c_int, request: c_int, ...) -> c_int; + pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index a9787987611f7..36438ccc784f8 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -481,6 +481,17 @@ pub fn commit_date_str() -> Option<&'static str> { option_env!("CFG_VER_DATE") } +/// Returns a stage string, such as "stage0". +pub fn stage_str() -> Option<&'static str> { + if cfg!(stage0) { + Some("stage0") + } else if cfg!(stage1) { + Some("stage1") + } else { + None + } +} + /// Prints version information pub fn version(binary: &str, matches: &getopts::Matches) { let verbose = matches.opt_present("verbose"); @@ -493,6 +504,9 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(release_str())); + if let Some(stage) = stage_str() { + println!("stage: {}", stage); + } } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index cf5feabcc57e2..e0495226d9061 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -12,6 +12,7 @@ use super::archive::{Archive, ArchiveBuilder, ArchiveConfig, METADATA_FILENAME}; use super::linker::{Linker, GnuLinker, MsvcLinker}; use super::rpath::RPathConfig; use super::rpath; +use super::msvc; use super::svh::Svh; use session::config; use session::config::NoDebugInfo; @@ -358,10 +359,14 @@ pub fn mangle_internal_name_by_path_and_seq(path: PathElems, flav: &str) -> Stri mangle(path.chain(Some(gensym_name(flav))), None) } -pub fn get_cc_prog(sess: &Session) -> String { - match sess.opts.cg.linker { - Some(ref linker) => return linker.to_string(), - None => sess.target.target.options.linker.clone(), +pub fn get_linker(sess: &Session) -> (String, Command) { + if let Some(ref linker) = sess.opts.cg.linker { + (linker.clone(), Command::new(linker)) + } else if sess.target.target.options.is_like_msvc { + ("link.exe".to_string(), msvc::link_exe_cmd(sess)) + } else { + (sess.target.target.options.linker.clone(), + Command::new(&sess.target.target.options.linker)) } } @@ -807,8 +812,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool, let tmpdir = TempDir::new("rustc").ok().expect("needs a temp dir"); // The invocations of cc share some flags across platforms - let pname = get_cc_prog(sess); - let mut cmd = Command::new(&pname); + let (pname, mut cmd) = get_linker(sess); cmd.env("PATH", command_path(sess)); let root = sess.target_filesearch(PathKind::Native).get_lib_path(); diff --git a/src/librustc_trans/back/msvc/mod.rs b/src/librustc_trans/back/msvc/mod.rs new file mode 100644 index 0000000000000..0077e7eed52d0 --- /dev/null +++ b/src/librustc_trans/back/msvc/mod.rs @@ -0,0 +1,239 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! MSVC-specific logic for linkers and such. +//! +//! This module contains a cross-platform interface but has a blank unix +//! implementation. The Windows implementation builds on top of Windows native +//! libraries (reading registry keys), so it otherwise wouldn't link on unix. +//! +//! Note that we don't have much special logic for finding the system linker on +//! any other platforms, so it may seem a little odd to single out MSVC to have +//! a good deal of code just to find the linker. Unlike Unix systems, however, +//! the MSVC linker is not in the system PATH by default. It also additionally +//! needs a few environment variables or command line flags to be able to link +//! against system libraries. +//! +//! In order to have a nice smooth experience on Windows, the logic in this file +//! is here to find the MSVC linker and set it up in the default configuration +//! one would need to set up anyway. This means that the Rust compiler can be +//! run not only in the developer shells of MSVC but also the standard cmd.exe +//! shell or MSYS shells. +//! +//! As a high-level note, all logic in this module for looking up various +//! paths/files is copied over from Clang in its MSVCToolChain.cpp file, but +//! comments can also be found below leading through the various code paths. + +use std::process::Command; +use session::Session; + +#[cfg(windows)] +mod registry; + +#[cfg(windows)] +pub fn link_exe_cmd(sess: &Session) -> Command { + use std::env; + use std::ffi::OsString; + use std::fs; + use std::path::PathBuf; + use self::registry::{RegistryKey, LOCAL_MACHINE}; + + // When finding the link.exe binary the 32-bit version is at the top level + // but the versions to cross to other architectures are stored in + // sub-folders. Unknown architectures also just bail out early to return the + // standard `link.exe` command. + let extra = match &sess.target.target.arch[..] { + "x86" => "", + "x86_64" => "amd64", + "arm" => "arm", + _ => return Command::new("link.exe"), + }; + + let vs_install_dir = get_vs_install_dir(); + + // First up, we need to find the `link.exe` binary itself, and there's a few + // locations that we can look. First up is the standard VCINSTALLDIR + // environment variable which is normally set by the vcvarsall.bat file. If + // an environment is set up manually by whomever's driving the compiler then + // we shouldn't muck with that decision and should instead respect that. + // + // Next up is looking in PATH itself. Here we look for `cl.exe` and then + // assume that `link.exe` is next to it if we find it. Note that we look for + // `cl.exe` because MinGW ships /usr/bin/link.exe which is normally found in + // PATH but we're not interested in finding that. + // + // Finally we read the Windows registry to discover the VS install root. + // From here we probe for `link.exe` just to make sure that it exists. + let mut cmd = env::var_os("VCINSTALLDIR").and_then(|dir| { + let mut p = PathBuf::from(dir); + p.push("bin"); + p.push(extra); + p.push("link.exe"); + if fs::metadata(&p).is_ok() {Some(p)} else {None} + }).or_else(|| { + env::var_os("PATH").and_then(|path| { + env::split_paths(&path).find(|path| { + fs::metadata(&path.join("cl.exe")).is_ok() + }).map(|p| { + p.join("link.exe") + }) + }) + }).or_else(|| { + vs_install_dir.as_ref().and_then(|p| { + let mut p = p.join("VC/bin"); + p.push(extra); + p.push("link.exe"); + if fs::metadata(&p).is_ok() {Some(p)} else {None} + }) + }).map(|linker| { + Command::new(linker) + }).unwrap_or_else(|| { + Command::new("link.exe") + }); + + // The MSVC linker uses the LIB environment variable as the default lookup + // path for libraries. This environment variable is normally set up by the + // VS shells, so we only want to start adding our own pieces if it's not + // set. + // + // If we're adding our own pieces, then we need to add two primary + // directories to the default search path for the linker. The first is in + // the VS install direcotry and the next is the Windows SDK directory. + if env::var_os("LIB").is_none() { + if let Some(mut vs_install_dir) = vs_install_dir { + vs_install_dir.push("VC/lib"); + vs_install_dir.push(extra); + let mut arg = OsString::from("/LIBPATH:"); + arg.push(&vs_install_dir); + cmd.arg(arg); + } + if let Some(path) = get_windows_sdk_lib_path(sess) { + let mut arg = OsString::from("/LIBPATH:"); + arg.push(&path); + cmd.arg(arg); + } + } + + return cmd; + + // When looking for the Visual Studio installation directory we look in a + // number of locations in varying degrees of precedence: + // + // 1. The Visual Studio registry keys + // 2. The Visual Studio Express registry keys + // 3. A number of somewhat standard environment variables + // + // If we find a hit from any of these keys then we strip off the IDE/Tools + // folders which are typically found at the end. + // + // As a final note, when we take a look at the registry keys they're + // typically found underneath the version of what's installed, but we don't + // quite know what's installed. As a result we probe all sub-keys of the two + // keys we're looking at to find out the maximum version of what's installed + // and we use that root directory. + fn get_vs_install_dir() -> Option { + LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VisualStudio".as_ref()).or_else(|_| { + LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VCExpress".as_ref()) + }).ok().and_then(|key| { + max_version(&key).and_then(|(_vers, key)| { + key.query_str("InstallDir").ok() + }) + }).or_else(|| { + env::var_os("VS120COMNTOOLS") + }).or_else(|| { + env::var_os("VS100COMNTOOLS") + }).or_else(|| { + env::var_os("VS90COMNTOOLS") + }).or_else(|| { + env::var_os("VS80COMNTOOLS") + }).map(PathBuf::from).and_then(|mut dir| { + if dir.ends_with("Common7/IDE") || dir.ends_with("Common7/Tools") { + dir.pop(); + dir.pop(); + Some(dir) + } else { + None + } + }) + } + + // Given a registry key, look at all the sub keys and find the one which has + // the maximal numeric value. + // + // Returns the name of the maximal key as well as the opened maximal key. + fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> { + let mut max_vers = 0; + let mut max_key = None; + for subkey in key.iter().filter_map(|k| k.ok()) { + let val = subkey.to_str().and_then(|s| { + s.trim_left_matches("v").replace(".", "").parse().ok() + }); + let val = match val { + Some(s) => s, + None => continue, + }; + if val > max_vers { + if let Ok(k) = key.open(&subkey) { + max_vers = val; + max_key = Some((subkey, k)); + } + } + } + return max_key + } + + fn get_windows_sdk_lib_path(sess: &Session) -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows"; + let key = LOCAL_MACHINE.open(key.as_ref()); + let (n, k) = match key.ok().as_ref().and_then(max_version) { + Some(p) => p, + None => return None, + }; + let mut parts = n.to_str().unwrap().trim_left_matches("v").splitn(2, "."); + let major = parts.next().unwrap().parse::().unwrap(); + let _minor = parts.next().unwrap().parse::().unwrap(); + let path = match k.query_str("InstallationFolder") { + Ok(p) => PathBuf::from(p).join("Lib"), + Err(..) => return None, + }; + if major <= 7 { + // In Windows SDK 7.x, x86 libraries are directly in the Lib folder, + // x64 libraries are inside, and it's not necessary to link agains + // the SDK 7.x when targeting ARM or other architectures. + let x86 = match &sess.target.target.arch[..] { + "x86" => true, + "x86_64" => false, + _ => return None, + }; + Some(if x86 {path} else {path.join("x64")}) + } else { + // Windows SDK 8.x installes libraries in a folder whose names + // depend on the version of the OS you're targeting. By default + // choose the newest, which usually corresponds to the version of + // the OS you've installed the SDK on. + let extra = match &sess.target.target.arch[..] { + "x86" => "x86", + "x86_64" => "x64", + "arm" => "arm", + _ => return None, + }; + ["winv6.3", "win8", "win7"].iter().map(|p| path.join(p)).find(|part| { + fs::metadata(part).is_ok() + }).map(|path| { + path.join("um").join(extra) + }) + } + } +} + +#[cfg(not(windows))] +pub fn link_exe_cmd(_sess: &Session) -> Command { + Command::new("link.exe") +} diff --git a/src/librustc_trans/back/msvc/registry.rs b/src/librustc_trans/back/msvc/registry.rs new file mode 100644 index 0000000000000..97fd7f99d197e --- /dev/null +++ b/src/librustc_trans/back/msvc/registry.rs @@ -0,0 +1,170 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::io; +use std::ffi::{OsString, OsStr}; +use std::os::windows::prelude::*; +use std::ops::RangeFrom; +use libc::{DWORD, LPCWSTR, LONG, LPDWORD, LPBYTE, ERROR_SUCCESS}; + +const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY; +const KEY_WOW64_32KEY: REGSAM = 0x0200; +const KEY_READ: REGSAM = (STANDARD_RIGTS_READ | KEY_QUERY_VALUE | + KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & !SYNCHRONIZE; +const STANDARD_RIGTS_READ: REGSAM = READ_CONTROL; +const READ_CONTROL: REGSAM = 0x00020000; +const KEY_QUERY_VALUE: REGSAM = 0x0001; +const KEY_ENUMERATE_SUB_KEYS: REGSAM = 0x0008; +const KEY_NOTIFY: REGSAM = 0x0010; +const SYNCHRONIZE: REGSAM = 0x00100000; +const REG_SZ: DWORD = 1; +const ERROR_NO_MORE_ITEMS: DWORD = 259; + +enum __HKEY__ {} +pub type HKEY = *mut __HKEY__; +pub type PHKEY = *mut HKEY; +pub type REGSAM = DWORD; +pub type LPWSTR = *mut u16; +pub type PFILETIME = *mut (); + +#[link(name = "advapi32")] +extern "system" { + fn RegOpenKeyExW(hKey: HKEY, + lpSubKey: LPCWSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY) -> LONG; + fn RegQueryValueExW(hKey: HKEY, + lpValueName: LPCWSTR, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD) -> LONG; + fn RegEnumKeyExW(hKey: HKEY, + dwIndex: DWORD, + lpName: LPWSTR, + lpcName: LPDWORD, + lpReserved: LPDWORD, + lpClass: LPWSTR, + lpcClass: LPDWORD, + lpftLastWriteTime: PFILETIME) -> LONG; + fn RegCloseKey(hKey: HKEY) -> LONG; +} + +pub struct RegistryKey(Repr); + +struct OwnedKey(HKEY); + +enum Repr { + Const(HKEY), + Owned(OwnedKey), +} + +pub struct Iter<'a> { + idx: RangeFrom, + key: &'a RegistryKey, +} + +unsafe impl Sync for RegistryKey {} +unsafe impl Send for RegistryKey {} + +pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE)); + +impl RegistryKey { + fn raw(&self) -> HKEY { + match self.0 { + Repr::Const(val) => val, + Repr::Owned(ref val) => val.0, + } + } + + pub fn open(&self, key: &OsStr) -> io::Result { + let key = key.encode_wide().chain(Some(0)).collect::>(); + let mut ret = 0 as *mut _; + let err = unsafe { + RegOpenKeyExW(self.raw(), key.as_ptr(), 0, + KEY_READ | KEY_WOW64_32KEY, &mut ret) + }; + if err == ERROR_SUCCESS { + Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) + } else { + Err(io::Error::from_raw_os_error(err as i32)) + } + } + + pub fn iter(&self) -> Iter { + Iter { idx: 0.., key: self } + } + + pub fn query_str(&self, name: &str) -> io::Result { + let name: &OsStr = name.as_ref(); + let name = name.encode_wide().chain(Some(0)).collect::>(); + let mut len = 0; + let mut kind = 0; + unsafe { + let err = RegQueryValueExW(self.raw(), name.as_ptr(), 0 as *mut _, + &mut kind, 0 as *mut _, &mut len); + if err != ERROR_SUCCESS { + return Err(io::Error::from_raw_os_error(err as i32)) + } + if kind != REG_SZ { + return Err(io::Error::new(io::ErrorKind::Other, + "registry key wasn't a string")) + } + + // The length here is the length in bytes, but we're using wide + // characters so we need to be sure to halve it for the capacity + // passed in. + let mut v = Vec::with_capacity(len as usize / 2); + let err = RegQueryValueExW(self.raw(), name.as_ptr(), 0 as *mut _, + 0 as *mut _, v.as_mut_ptr() as *mut _, + &mut len); + if err != ERROR_SUCCESS { + return Err(io::Error::from_raw_os_error(err as i32)) + } + v.set_len(len as usize / 2); + + // Some registry keys may have a terminating nul character, but + // we're not interested in that, so chop it off if it's there. + if v[v.len() - 1] == 0 { + v.pop(); + } + Ok(OsString::from_wide(&v)) + } + } +} + +impl Drop for OwnedKey { + fn drop(&mut self) { + unsafe { RegCloseKey(self.0); } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.idx.next().and_then(|i| unsafe { + let mut v = Vec::with_capacity(256); + let mut len = v.capacity() as DWORD; + let ret = RegEnumKeyExW(self.key.raw(), i, v.as_mut_ptr(), &mut len, + 0 as *mut _, 0 as *mut _, 0 as *mut _, + 0 as *mut _); + if ret == ERROR_NO_MORE_ITEMS as LONG { + None + } else if ret != ERROR_SUCCESS { + Some(Err(io::Error::from_raw_os_error(ret as i32))) + } else { + v.set_len(len as usize); + Some(Ok(OsString::from_wide(&v))) + } + }) + } +} diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 267f0b6d95329..90ddba4e09c58 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -9,7 +9,7 @@ // except according to those terms. use back::lto; -use back::link::{get_cc_prog, remove}; +use back::link::{get_linker, remove}; use session::config::{OutputFilenames, Passes, SomePasses, AllPasses}; use session::Session; use session::config; @@ -27,7 +27,7 @@ use std::ffi::{CStr, CString}; use std::fs; use std::mem; use std::path::Path; -use std::process::{Command, Stdio}; +use std::process::Stdio; use std::ptr; use std::str; use std::sync::{Arc, Mutex}; @@ -737,8 +737,7 @@ pub fn run_passes(sess: &Session, None }; - let pname = get_cc_prog(sess); - let mut cmd = Command::new(&pname[..]); + let (pname, mut cmd) = get_linker(sess); cmd.args(&sess.target.target.options.pre_link_args); cmd.arg("-nostdlib"); @@ -767,8 +766,7 @@ pub fn run_passes(sess: &Session, }, Err(e) => { sess.err(&format!("could not exec the linker `{}`: {}", - pname, - e)); + pname, e)); sess.abort_if_errors(); }, } @@ -986,8 +984,7 @@ fn run_work_multithreaded(sess: &Session, } pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) { - let pname = get_cc_prog(sess); - let mut cmd = Command::new(&pname[..]); + let (pname, mut cmd) = get_linker(sess); cmd.arg("-c").arg("-o").arg(&outputs.path(config::OutputTypeObject)) .arg(&outputs.temp_path(config::OutputTypeAssembly)); @@ -1007,9 +1004,7 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) { } }, Err(e) => { - sess.err(&format!("could not exec the linker `{}`: {}", - pname, - e)); + sess.err(&format!("could not exec the linker `{}`: {}", pname, e)); sess.abort_if_errors(); } } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index bb7e95cd4ae44..cd2e597db1333 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -82,7 +82,7 @@ pub mod back { pub mod link; pub mod lto; pub mod write; - + pub mod msvc; } pub mod trans; diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index c2397ec31cffa..936b0070dfccf 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -1351,7 +1351,7 @@ fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool reassigned: false }; { - let infcx = infer::new_infer_ctxt(bcx.tcx(), &bcx.tcx().tables, None, false); + let infcx = infer::normalizing_infer_ctxt(bcx.tcx(), &bcx.tcx().tables); let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx); visitor.walk_expr(body); } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index edb61b0d3cf38..08b8fab1fd707 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -753,13 +753,15 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } pub fn need_invoke(bcx: Block) -> bool { - // FIXME(#25869) currently unwinding is not implemented for MSVC and our - // normal unwinding infrastructure ends up just causing linker - // errors with the current LLVM implementation, so landing - // pads are disabled entirely for MSVC targets - if bcx.sess().no_landing_pads() || - bcx.sess().target.target.options.is_like_msvc { - return false; + if bcx.sess().no_landing_pads() { + return false + } + + // Currently 32-bit MSVC unwinding is not super well implemented in LLVM, so + // we avoid it entirely. + if bcx.sess().target.target.options.is_like_msvc && + bcx.sess().target.target.arch == "x86" { + return false } // Avoid using invoke if we are already inside a landing pad. diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 588e4cea5048b..1891320313a85 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -851,8 +851,8 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx // an "exception", but for MSVC we want to force SEH. This means that we // can't actually have the personality function be our standard // `rust_eh_personality` function, but rather we wired it up to the - // CRT's custom `__C_specific_handler` personality funciton, which - // forces LLVM to consider landing pads as "landing pads for SEH". + // CRT's custom personality function, which forces LLVM to consider + // landing pads as "landing pads for SEH". let target = &self.ccx.sess().target.target; let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() { Some(def_id) if !target.options.is_like_msvc => { @@ -864,10 +864,12 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx match *personality { Some(llpersonality) => llpersonality, None => { - let name = if target.options.is_like_msvc { - "__C_specific_handler" - } else { + let name = if !target.options.is_like_msvc { "rust_eh_personality" + } else if target.arch == "x86" { + "_except_handler3" + } else { + "__C_specific_handler" }; let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); let f = declare::declare_cfn(self.ccx, name, fty, diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index e1c1ac9a772eb..a4559708bf4e8 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -936,7 +936,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, predicates); let tcx = ccx.tcx(); - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, true); + let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables); let mut selcx = traits::SelectionContext::new(&infcx); let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut(); let cause = traits::ObligationCause::dummy(); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index e7e2793fc7e9d..ece52b3ad4d6d 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -486,13 +486,12 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, .map(|e| const_expr(cx, &**e, param_substs, fn_args).0) .collect() }; - unsafe { - let _icx = push_ctxt("const_expr"); - match e.node { - ast::ExprLit(ref lit) => { - const_lit(cx, e, &**lit) - } - ast::ExprBinary(b, ref e1, ref e2) => { + let _icx = push_ctxt("const_expr"); + match e.node { + ast::ExprLit(ref lit) => { + const_lit(cx, e, &**lit) + }, + ast::ExprBinary(b, ref e1, ref e2) => { /* Neither type is bottom, and we expect them to be unified * already, so the following is safe. */ let (te1, ty) = const_expr(cx, &**e1, param_substs, fn_args); @@ -512,145 +511,136 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, check_binary_expr_validity(cx, e, ty, te1, te2); - match b.node { - ast::BiAdd => { - if is_float { llvm::LLVMConstFAdd(te1, te2) } - else { llvm::LLVMConstAdd(te1, te2) } - } - ast::BiSub => { - if is_float { llvm::LLVMConstFSub(te1, te2) } - else { llvm::LLVMConstSub(te1, te2) } - } - ast::BiMul => { - if is_float { llvm::LLVMConstFMul(te1, te2) } - else { llvm::LLVMConstMul(te1, te2) } - } - ast::BiDiv => { - if is_float { llvm::LLVMConstFDiv(te1, te2) } - else if signed { llvm::LLVMConstSDiv(te1, te2) } - else { llvm::LLVMConstUDiv(te1, te2) } - } - ast::BiRem => { - if is_float { llvm::LLVMConstFRem(te1, te2) } - else if signed { llvm::LLVMConstSRem(te1, te2) } - else { llvm::LLVMConstURem(te1, te2) } - } - ast::BiAnd => llvm::LLVMConstAnd(te1, te2), - ast::BiOr => llvm::LLVMConstOr(te1, te2), - ast::BiBitXor => llvm::LLVMConstXor(te1, te2), - ast::BiBitAnd => llvm::LLVMConstAnd(te1, te2), - ast::BiBitOr => llvm::LLVMConstOr(te1, te2), - ast::BiShl => { - let te2 = base::cast_shift_const_rhs(b.node, te1, te2); - llvm::LLVMConstShl(te1, te2) - } - ast::BiShr => { - let te2 = base::cast_shift_const_rhs(b.node, te1, te2); - if signed { llvm::LLVMConstAShr(te1, te2) } - else { llvm::LLVMConstLShr(te1, te2) } - } - ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGt | ast::BiGe => { - if is_float { - let cmp = base::bin_op_to_fcmp_predicate(cx, b.node); - ConstFCmp(cmp, te1, te2) - } else { - let cmp = base::bin_op_to_icmp_predicate(cx, b.node, signed); - let bool_val = ConstICmp(cmp, te1, te2); - if is_simd { - // LLVM outputs an `< size x i1 >`, so we need to perform - // a sign extension to get the correctly sized type. - llvm::LLVMConstIntCast(bool_val, val_ty(te1).to_ref(), True) - } else { - bool_val - } - } - } - } - }, - ast::ExprUnary(u, ref inner_e) => { + unsafe { match b.node { + ast::BiAdd if is_float => llvm::LLVMConstFAdd(te1, te2), + ast::BiAdd => llvm::LLVMConstAdd(te1, te2), + + ast::BiSub if is_float => llvm::LLVMConstFSub(te1, te2), + ast::BiSub => llvm::LLVMConstSub(te1, te2), + + ast::BiMul if is_float => llvm::LLVMConstFMul(te1, te2), + ast::BiMul => llvm::LLVMConstMul(te1, te2), + + ast::BiDiv if is_float => llvm::LLVMConstFDiv(te1, te2), + ast::BiDiv if signed => llvm::LLVMConstSDiv(te1, te2), + ast::BiDiv => llvm::LLVMConstUDiv(te1, te2), + + ast::BiRem if is_float => llvm::LLVMConstFRem(te1, te2), + ast::BiRem if signed => llvm::LLVMConstSRem(te1, te2), + ast::BiRem => llvm::LLVMConstURem(te1, te2), + + ast::BiAnd => llvm::LLVMConstAnd(te1, te2), + ast::BiOr => llvm::LLVMConstOr(te1, te2), + ast::BiBitXor => llvm::LLVMConstXor(te1, te2), + ast::BiBitAnd => llvm::LLVMConstAnd(te1, te2), + ast::BiBitOr => llvm::LLVMConstOr(te1, te2), + ast::BiShl => { + let te2 = base::cast_shift_const_rhs(b.node, te1, te2); + llvm::LLVMConstShl(te1, te2) + }, + ast::BiShr => { + let te2 = base::cast_shift_const_rhs(b.node, te1, te2); + if signed { llvm::LLVMConstAShr(te1, te2) } + else { llvm::LLVMConstLShr(te1, te2) } + }, + ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGt | ast::BiGe => { + if is_float { + let cmp = base::bin_op_to_fcmp_predicate(cx, b.node); + ConstFCmp(cmp, te1, te2) + } else { + let cmp = base::bin_op_to_icmp_predicate(cx, b.node, signed); + let bool_val = ConstICmp(cmp, te1, te2); + if is_simd { + // LLVM outputs an `< size x i1 >`, so we need to perform + // a sign extension to get the correctly sized type. + llvm::LLVMConstIntCast(bool_val, val_ty(te1).to_ref(), True) + } else { + bool_val + } + } + }, + } } // unsafe { match b.node { + }, + ast::ExprUnary(u, ref inner_e) => { let (te, ty) = const_expr(cx, &**inner_e, param_substs, fn_args); check_unary_expr_validity(cx, e, ty, te); let is_float = ty.is_fp(); - match u { - ast::UnUniq | ast::UnDeref => { - const_deref(cx, te, ty).0 - } - ast::UnNot => llvm::LLVMConstNot(te), - ast::UnNeg => { - if is_float { llvm::LLVMConstFNeg(te) } - else { llvm::LLVMConstNeg(te) } - } + unsafe { match u { + ast::UnUniq | ast::UnDeref => const_deref(cx, te, ty).0, + ast::UnNot => llvm::LLVMConstNot(te), + ast::UnNeg if is_float => llvm::LLVMConstFNeg(te), + ast::UnNeg => llvm::LLVMConstNeg(te), + } } + }, + ast::ExprField(ref base, field) => { + let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); + let brepr = adt::represent_type(cx, bt); + expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| { + let ix = cx.tcx().field_idx_strict(field.node.name, field_tys); + adt::const_get_field(cx, &*brepr, bv, discr, ix) + }) + }, + ast::ExprTupField(ref base, idx) => { + let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); + let brepr = adt::represent_type(cx, bt); + expr::with_field_tys(cx.tcx(), bt, None, |discr, _| { + adt::const_get_field(cx, &*brepr, bv, discr, idx.node) + }) + }, + + ast::ExprIndex(ref base, ref index) => { + let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); + let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) { + Ok(ConstVal::Int(i)) => i as u64, + Ok(ConstVal::Uint(u)) => u, + _ => cx.sess().span_bug(index.span, + "index is not an integer-constant expression") + }; + let (arr, len) = match bt.sty { + ty::TyArray(_, u) => (bv, C_uint(cx, u)), + ty::TySlice(_) | ty::TyStr => { + let e1 = const_get_elt(cx, bv, &[0]); + (const_deref_ptr(cx, e1), const_get_elt(cx, bv, &[1])) + }, + ty::TyRef(_, mt) => match mt.ty.sty { + ty::TyArray(_, u) => { + (const_deref_ptr(cx, bv), C_uint(cx, u)) + }, + _ => cx.sess().span_bug(base.span, + &format!("index-expr base must be a vector \ + or string type, found {:?}", + bt)), + }, + _ => cx.sess().span_bug(base.span, + &format!("index-expr base must be a vector \ + or string type, found {:?}", + bt)), + }; + + let len = unsafe { llvm::LLVMConstIntGetZExtValue(len) as u64 }; + let len = match bt.sty { + ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) => match ty.sty { + ty::TyStr => { + assert!(len > 0); + len - 1 + }, + _ => len, + }, + _ => len, + }; + if iv >= len { + // FIXME #3170: report this earlier on in the const-eval + // pass. Reporting here is a bit late. + cx.sess().span_err(e.span, + "const index-expr is out of bounds"); + C_undef(type_of::type_of(cx, bt).element_type()) + } else { + const_get_elt(cx, arr, &[iv as c_uint]) } - } - ast::ExprField(ref base, field) => { - let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); - let brepr = adt::represent_type(cx, bt); - expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| { - let ix = cx.tcx().field_idx_strict(field.node.name, field_tys); - adt::const_get_field(cx, &*brepr, bv, discr, ix) - }) - } - ast::ExprTupField(ref base, idx) => { - let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); - let brepr = adt::represent_type(cx, bt); - expr::with_field_tys(cx.tcx(), bt, None, |discr, _| { - adt::const_get_field(cx, &*brepr, bv, discr, idx.node) - }) - } - - ast::ExprIndex(ref base, ref index) => { - let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); - let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) { - Ok(ConstVal::Int(i)) => i as u64, - Ok(ConstVal::Uint(u)) => u, - _ => cx.sess().span_bug(index.span, - "index is not an integer-constant expression") - }; - let (arr, len) = match bt.sty { - ty::TyArray(_, u) => (bv, C_uint(cx, u)), - ty::TySlice(_) | ty::TyStr => { - let e1 = const_get_elt(cx, bv, &[0]); - (const_deref_ptr(cx, e1), const_get_elt(cx, bv, &[1])) - } - ty::TyRef(_, mt) => match mt.ty.sty { - ty::TyArray(_, u) => { - (const_deref_ptr(cx, bv), C_uint(cx, u)) - }, - _ => cx.sess().span_bug(base.span, - &format!("index-expr base must be a vector \ - or string type, found {:?}", - bt)) - }, - _ => cx.sess().span_bug(base.span, - &format!("index-expr base must be a vector \ - or string type, found {:?}", - bt)) - }; - - let len = llvm::LLVMConstIntGetZExtValue(len) as u64; - let len = match bt.sty { - ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) => match ty.sty { - ty::TyStr => { - assert!(len > 0); - len - 1 - } - _ => len - }, - _ => len - }; - if iv >= len { - // FIXME #3170: report this earlier on in the const-eval - // pass. Reporting here is a bit late. - cx.sess().span_err(e.span, - "const index-expr is out of bounds"); - C_undef(type_of::type_of(cx, bt).element_type()) - } else { - const_get_elt(cx, arr, &[iv as c_uint]) - } - } - ast::ExprCast(ref base, _) => { + }, + ast::ExprCast(ref base, _) => { let t_cast = ety; let llty = type_of::type_of(cx, t_cast); let (v, t_expr) = const_expr(cx, &**base, param_substs, fn_args); @@ -671,136 +661,121 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return addr; } } - match (CastTy::from_ty(cx.tcx(), t_expr).expect("bad input type for cast"), - CastTy::from_ty(cx.tcx(), t_cast).expect("bad output type for cast")) { - (CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => { - let repr = adt::represent_type(cx, t_expr); - let discr = adt::const_get_discrim(cx, &*repr, v); - let iv = C_integral(cx.int_type(), discr, false); - let s = adt::is_discr_signed(&*repr) as Bool; - llvm::LLVMConstIntCast(iv, llty.to_ref(), s) - } - (CastTy::Int(_), CastTy::Int(_)) => { - let s = t_expr.is_signed() as Bool; - llvm::LLVMConstIntCast(v, llty.to_ref(), s) - } - (CastTy::Int(_), CastTy::Float) => { - if t_expr.is_signed() { - llvm::LLVMConstSIToFP(v, llty.to_ref()) - } else { - llvm::LLVMConstUIToFP(v, llty.to_ref()) - } - } - (CastTy::Float, CastTy::Float) => { - llvm::LLVMConstFPCast(v, llty.to_ref()) - } - (CastTy::Float, CastTy::Int(IntTy::I)) => { - llvm::LLVMConstFPToSI(v, llty.to_ref()) - } - (CastTy::Float, CastTy::Int(_)) => { - llvm::LLVMConstFPToUI(v, llty.to_ref()) - } - (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_)) - | (CastTy::RPtr(_), CastTy::Ptr(_)) => { - ptrcast(v, llty) - } - (CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion? - (CastTy::Int(_), CastTy::Ptr(_)) => { - llvm::LLVMConstIntToPtr(v, llty.to_ref()) - } - (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => { - llvm::LLVMConstPtrToInt(v, llty.to_ref()) - } - _ => { - cx.sess().impossible_case(e.span, - "bad combination of types for cast") - } - } - } - ast::ExprAddrOf(ast::MutImmutable, ref sub) => { - // If this is the address of some static, then we need to return - // the actual address of the static itself (short circuit the rest - // of const eval). - let mut cur = sub; - loop { - match cur.node { - ast::ExprParen(ref sub) => cur = sub, - ast::ExprBlock(ref blk) => { + unsafe { match ( + CastTy::from_ty(cx.tcx(), t_expr).expect("bad input type for cast"), + CastTy::from_ty(cx.tcx(), t_cast).expect("bad output type for cast"), + ) { + (CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => { + let repr = adt::represent_type(cx, t_expr); + let discr = adt::const_get_discrim(cx, &*repr, v); + let iv = C_integral(cx.int_type(), discr, false); + let s = adt::is_discr_signed(&*repr) as Bool; + llvm::LLVMConstIntCast(iv, llty.to_ref(), s) + }, + (CastTy::Int(_), CastTy::Int(_)) => { + let s = t_expr.is_signed() as Bool; + llvm::LLVMConstIntCast(v, llty.to_ref(), s) + }, + (CastTy::Int(_), CastTy::Float) => { + if t_expr.is_signed() { + llvm::LLVMConstSIToFP(v, llty.to_ref()) + } else { + llvm::LLVMConstUIToFP(v, llty.to_ref()) + } + }, + (CastTy::Float, CastTy::Float) => llvm::LLVMConstFPCast(v, llty.to_ref()), + (CastTy::Float, CastTy::Int(IntTy::I)) => llvm::LLVMConstFPToSI(v, llty.to_ref()), + (CastTy::Float, CastTy::Int(_)) => llvm::LLVMConstFPToUI(v, llty.to_ref()), + (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_)) + | (CastTy::RPtr(_), CastTy::Ptr(_)) => { + ptrcast(v, llty) + }, + (CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion? + (CastTy::Int(_), CastTy::Ptr(_)) => llvm::LLVMConstIntToPtr(v, llty.to_ref()), + (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => { + llvm::LLVMConstPtrToInt(v, llty.to_ref()) + }, + _ => { + cx.sess().impossible_case(e.span, + "bad combination of types for cast") + }, + } } // unsafe { match ( ... ) { + }, + ast::ExprAddrOf(ast::MutImmutable, ref sub) => { + // If this is the address of some static, then we need to return + // the actual address of the static itself (short circuit the rest + // of const eval). + let mut cur = sub; + loop { + match cur.node { + ast::ExprParen(ref sub) => cur = sub, + ast::ExprBlock(ref blk) => { if let Some(ref sub) = blk.expr { cur = sub; } else { break; } - } - _ => break, - } - } - let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def()); - if let Some(def::DefStatic(def_id, _)) = opt_def { - get_static_val(cx, def_id, ety) - } else { - // If this isn't the address of a static, then keep going through - // normal constant evaluation. - let (v, _) = const_expr(cx, &**sub, param_substs, fn_args); - addr_of(cx, v, "ref") - } - } - ast::ExprAddrOf(ast::MutMutable, ref sub) => { - let (v, _) = const_expr(cx, &**sub, param_substs, fn_args); - addr_of_mut(cx, v, "ref_mut_slice") - } - ast::ExprTup(ref es) => { - let repr = adt::represent_type(cx, ety); - let vals = map_list(&es[..]); - adt::trans_const(cx, &*repr, 0, &vals[..]) - } - ast::ExprStruct(_, ref fs, ref base_opt) => { - let repr = adt::represent_type(cx, ety); - - let base_val = match *base_opt { + }, + _ => break, + } + } + let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def()); + if let Some(def::DefStatic(def_id, _)) = opt_def { + get_static_val(cx, def_id, ety) + } else { + // If this isn't the address of a static, then keep going through + // normal constant evaluation. + let (v, _) = const_expr(cx, &**sub, param_substs, fn_args); + addr_of(cx, v, "ref") + } + }, + ast::ExprAddrOf(ast::MutMutable, ref sub) => { + let (v, _) = const_expr(cx, &**sub, param_substs, fn_args); + addr_of_mut(cx, v, "ref_mut_slice") + }, + ast::ExprTup(ref es) => { + let repr = adt::represent_type(cx, ety); + let vals = map_list(&es[..]); + adt::trans_const(cx, &*repr, 0, &vals[..]) + }, + ast::ExprStruct(_, ref fs, ref base_opt) => { + let repr = adt::represent_type(cx, ety); + + let base_val = match *base_opt { Some(ref base) => Some(const_expr(cx, &**base, param_substs, fn_args)), None => None - }; - - expr::with_field_tys(cx.tcx(), ety, Some(e.id), |discr, field_tys| { - let cs = field_tys.iter().enumerate() - .map(|(ix, &field_ty)| { - match fs.iter().find(|f| field_ty.name == f.ident.node.name) { - Some(ref f) => const_expr(cx, &*f.expr, param_substs, fn_args).0, - None => { - match base_val { - Some((bv, _)) => { - adt::const_get_field(cx, &*repr, bv, - discr, ix) - } - None => { - cx.sess().span_bug(e.span, - "missing struct field") - } - } - } - } - }).collect::>(); - if ety.is_simd(cx.tcx()) { - C_vector(&cs[..]) - } else { - adt::trans_const(cx, &*repr, discr, &cs[..]) - } - }) - } - ast::ExprVec(ref es) => { + }; + + expr::with_field_tys(cx.tcx(), ety, Some(e.id), |discr, field_tys| { + let cs = field_tys.iter().enumerate() + .map(|(ix, &field_ty)| { + match (fs.iter().find(|f| field_ty.name == f.ident.node.name), base_val) { + (Some(ref f), _) => const_expr(cx, &*f.expr, param_substs, fn_args).0, + (_, Some((bv, _))) => adt::const_get_field(cx, &*repr, bv, discr, ix), + (_, None) => cx.sess().span_bug(e.span, "missing struct field"), + } + }).collect::>(); + if ety.is_simd(cx.tcx()) { + C_vector(&cs[..]) + } else { + adt::trans_const(cx, &*repr, discr, &cs[..]) + } + }) + }, + ast::ExprVec(ref es) => { let unit_ty = ety.sequence_element_type(cx.tcx()); let llunitty = type_of::type_of(cx, unit_ty); - let vs = es.iter().map(|e| const_expr(cx, &**e, param_substs, fn_args).0) - .collect::>(); + let vs = es.iter() + .map(|e| const_expr(cx, &**e, param_substs, fn_args).0) + .collect::>(); // If the vector contains enums, an LLVM array won't work. if vs.iter().any(|vi| val_ty(*vi) != llunitty) { C_struct(cx, &vs[..], false) } else { C_array(llunitty, &vs[..]) } - } - ast::ExprRepeat(ref elem, ref count) => { + }, + ast::ExprRepeat(ref elem, ref count) => { let unit_ty = ety.sequence_element_type(cx.tcx()); let llunitty = type_of::type_of(cx, unit_ty); let n = cx.tcx().eval_repeat_count(count); @@ -811,8 +786,8 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } else { C_array(llunitty, &vs[..]) } - } - ast::ExprPath(..) => { + }, + ast::ExprPath(..) => { let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def(); match def { def::DefLocal(id) => { @@ -853,69 +828,68 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, or variant def") } } - } - ast::ExprCall(ref callee, ref args) => { - let mut callee = &**callee; - loop { - callee = match callee.node { - ast::ExprParen(ref inner) => &**inner, - ast::ExprBlock(ref block) => match block.expr { - Some(ref tail) => &**tail, - None => break - }, - _ => break - }; - } - let def = cx.tcx().def_map.borrow()[&callee.id].full_def(); - let arg_vals = map_list(args); - match def { - def::DefFn(did, _) | def::DefMethod(did, _) => { - const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs) - } - def::DefStruct(_) => { - if ety.is_simd(cx.tcx()) { - C_vector(&arg_vals[..]) - } else { - let repr = adt::represent_type(cx, ety); - adt::trans_const(cx, &*repr, 0, &arg_vals[..]) - } - } - def::DefVariant(enum_did, variant_did, _) => { - let repr = adt::represent_type(cx, ety); - let vinfo = cx.tcx().enum_variant_with_id(enum_did, variant_did); - adt::trans_const(cx, - &*repr, - vinfo.disr_val, - &arg_vals[..]) - } - _ => cx.sess().span_bug(e.span, "expected a struct, variant, or const fn def") - } - } - ast::ExprMethodCall(_, _, ref args) => { - let arg_vals = map_list(args); - let method_call = ty::MethodCall::expr(e.id); + }, + ast::ExprCall(ref callee, ref args) => { + let mut callee = &**callee; + loop { + callee = match callee.node { + ast::ExprParen(ref inner) => &**inner, + ast::ExprBlock(ref block) => match block.expr { + Some(ref tail) => &**tail, + None => break, + }, + _ => break, + }; + } + let def = cx.tcx().def_map.borrow()[&callee.id].full_def(); + let arg_vals = map_list(args); + match def { + def::DefFn(did, _) | def::DefMethod(did, _) => { + const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs) + }, + def::DefStruct(_) => { + if ety.is_simd(cx.tcx()) { + C_vector(&arg_vals[..]) + } else { + let repr = adt::represent_type(cx, ety); + adt::trans_const(cx, &*repr, 0, &arg_vals[..]) + } + }, + def::DefVariant(enum_did, variant_did, _) => { + let repr = adt::represent_type(cx, ety); + let vinfo = cx.tcx().enum_variant_with_id(enum_did, variant_did); + adt::trans_const(cx, + &*repr, + vinfo.disr_val, + &arg_vals[..]) + }, + _ => cx.sess().span_bug(e.span, "expected a struct, variant, or const fn def"), + } + }, + ast::ExprMethodCall(_, _, ref args) => { + let arg_vals = map_list(args); + let method_call = ty::MethodCall::expr(e.id); let method_did = cx.tcx().tables.borrow().method_map[&method_call].def_id; - const_fn_call(cx, MethodCallKey(method_call), - method_did, &arg_vals, param_substs) - } - ast::ExprParen(ref e) => const_expr(cx, &**e, param_substs, fn_args).0, - ast::ExprBlock(ref block) => { + const_fn_call(cx, MethodCallKey(method_call), + method_did, &arg_vals, param_substs) + }, + ast::ExprParen(ref e) => const_expr(cx, &**e, param_substs, fn_args).0, + ast::ExprBlock(ref block) => { match block.expr { Some(ref expr) => const_expr(cx, &**expr, param_substs, fn_args).0, - None => C_nil(cx) + None => C_nil(cx), } - } - ast::ExprClosure(_, ref decl, ref body) => { + }, + ast::ExprClosure(_, ref decl, ref body) => { closure::trans_closure_expr(closure::Dest::Ignore(cx), decl, body, e.id, param_substs); C_null(type_of::type_of(cx, ety)) - } - _ => cx.sess().span_bug(e.span, - "bad constant expression type in consts::const_expr") - } + }, + _ => cx.sess().span_bug(e.span, + "bad constant expression type in consts::const_expr"), } } diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index e530eb0de59b8..541a9ab466e56 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -22,8 +22,9 @@ use middle::lang_items::ExchangeFreeFnLangItem; use middle::subst; use middle::subst::{Subst, Substs}; use middle::ty::{self, Ty}; -use trans::adt; use trans::adt::GetDtorType; // for tcx.dtor_type() +use trans::adt; +use trans::attributes; use trans::base::*; use trans::build::*; use trans::callee; @@ -43,6 +44,7 @@ use trans::type_::Type; use arena::TypedArena; use libc::c_uint; use syntax::ast; +use syntax::attr::InlineAttr; pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, @@ -250,6 +252,25 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, update_linkage(ccx, llfn, None, OriginalTranslation); + // FIXME: Currently LLVM has a bug where if an SSA value is created in one + // landing pad and then used in another it will abort during + // compilation. The compiler never actually generates nested landing + // pads, but this often arises when destructors are inlined into + // other functions. To prevent this inlining from happening (and thus + // preventing the LLVM abort) we mark all drop glue as inline(never) + // on MSVC. + // + // For more information about the bug, see: + // + // https://llvm.org/bugs/show_bug.cgi?id=23884 + // + // This is clearly not the ideal solution to the problem (due to the + // perf hits), so this should be removed once the upstream bug is + // fixed. + if ccx.sess().target.target.options.is_like_msvc { + attributes::inline(llfn, InlineAttr::Never); + } + ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1); // All glue functions take values passed *by alias*; this is a // requirement since in many contexts glue is invoked indirectly and diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 7f29af0d84b2d..046e83bf3fcbc 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1113,6 +1113,7 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, // any ambiguity. fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, ty_param_node_id: ast::NodeId, + ty_param_name: Option, assoc_name: ast::Name, span: Span) -> Result, ErrorReported> @@ -1138,12 +1139,21 @@ fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) .collect(); - let ty_param_name = tcx.type_parameter_def(ty_param_node_id).name; - one_bound_for_assoc_type(tcx, - suitable_bounds, - &token::get_name(ty_param_name), - &token::get_name(assoc_name), - span) + if let Some(s) = ty_param_name { + // borrowck doesn't like this any other way + one_bound_for_assoc_type(tcx, + suitable_bounds, + &token::get_name(s), + &token::get_name(assoc_name), + span) + } else { + one_bound_for_assoc_type(tcx, + suitable_bounds, + "Self", + &token::get_name(assoc_name), + span) + + } } @@ -1240,12 +1250,20 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, _ => unreachable!() } } - (&ty::TyParam(_), def::DefTyParam(..)) | - (&ty::TyParam(_), def::DefSelfTy(Some(_), None)) => { - // A type parameter or Self, we need to find the associated item from - // a bound. - let ty_param_node_id = ty_path_def.local_node_id(); - match find_bound_for_assoc_item(this, ty_param_node_id, assoc_name, span) { + (&ty::TyParam(_), def::DefSelfTy(Some(trait_did), None)) => { + assert_eq!(trait_did.krate, ast::LOCAL_CRATE); + match find_bound_for_assoc_item(this, trait_did.node, None, assoc_name, span) { + Ok(bound) => bound, + Err(ErrorReported) => return (tcx.types.err, ty_path_def), + } + } + (&ty::TyParam(_), def::DefTyParam(_, _, param_did, param_name)) => { + assert_eq!(param_did.krate, ast::LOCAL_CRATE); + match find_bound_for_assoc_item(this, + param_did.node, + Some(param_name), + assoc_name, + span) { Ok(bound) => bound, Err(ErrorReported) => return (tcx.types.err, ty_path_def), } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 2117291817754..73e45619774d7 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -151,6 +151,7 @@ #![cfg_attr(windows, feature(str_utf16))] #![cfg_attr(test, feature(float_from_str_radix, range_inclusive, float_extras))] #![cfg_attr(test, feature(test, rustc_private, float_consts))] +#![cfg_attr(target_env = "msvc", feature(link_args))] // Don't link to std. We are std. #![no_std] diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 04f36d99c8eb5..031fda089c84c 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -13,7 +13,6 @@ use io::prelude::*; use env; use fmt; use intrinsics; -use libc::uintptr_t; use sync::atomic::{self, Ordering}; use sys::stdio::Stderr; @@ -22,10 +21,18 @@ use sys::stdio::Stderr; /// can't run correctly un-altered. Valgrind is there to help /// you notice weirdness in normal, un-doctored code paths! pub fn running_on_valgrind() -> bool { - extern { - fn rust_running_on_valgrind() -> uintptr_t; + return on_valgrind(); + #[cfg(windows)] + fn on_valgrind() -> bool { false } + + #[cfg(unix)] + fn on_valgrind() -> bool { + use libc::uintptr_t; + extern { + fn rust_running_on_valgrind() -> uintptr_t; + } + unsafe { rust_running_on_valgrind() != 0 } } - unsafe { rust_running_on_valgrind() != 0 } } /// Valgrind has a fixed-sized array (size around 2000) of segment descriptors diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index a395dbf8995c6..a3b2ab7705eaf 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -12,8 +12,8 @@ //! the standard library This varies per-platform, but these libraries are //! necessary for running libstd. -// All platforms need to link to rustrt -#[cfg(not(test))] +// A few small shims in C that haven't been translated to Rust yet +#[cfg(all(not(test), not(windows)))] #[link(name = "rust_builtin", kind = "static")] extern {} diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 5002de559884d..a2dbb0f834243 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -221,8 +221,8 @@ unsafe fn unregister_dtor(key: Key) -> bool { // // # The article mentions crazy stuff about "/INCLUDE"? // -// It sure does! This seems to work for now, so maybe we'll just run into -// that if we start linking with msvc? +// It sure does! We include it below for MSVC targets, but it look like for GNU +// targets we don't require it. #[link_section = ".CRT$XLB"] #[linkage = "external"] @@ -231,6 +231,10 @@ pub static p_thread_callback: unsafe extern "system" fn(LPVOID, DWORD, LPVOID) = on_tls_callback; +#[cfg(target_env = "msvc")] +#[link_args = "/INCLUDE:_tls_used"] +extern {} + #[allow(warnings)] unsafe extern "system" fn on_tls_callback(h: LPVOID, dwReason: DWORD, diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 0a3c350086cdd..724c0b2a8927f 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -872,7 +872,7 @@ fn run_tests(opts: &TestOpts, #[allow(deprecated)] fn get_concurrency() -> usize { - match env::var("RUST_TEST_THREADS") { + return match env::var("RUST_TEST_THREADS") { Ok(s) => { let opt_n: Option = s.parse().ok(); match opt_n { @@ -884,10 +884,24 @@ fn get_concurrency() -> usize { if std::rt::util::limit_thread_creation_due_to_osx_and_valgrind() { 1 } else { - extern { fn rust_get_num_cpus() -> libc::uintptr_t; } - unsafe { rust_get_num_cpus() as usize } + num_cpus() } } + }; + + #[cfg(windows)] + fn num_cpus() -> usize { + unsafe { + let mut sysinfo = std::mem::zeroed(); + libc::GetSystemInfo(&mut sysinfo); + sysinfo.dwNumberOfProcessors as usize + } + } + + #[cfg(unix)] + fn num_cpus() -> usize { + extern { fn rust_get_num_cpus() -> libc::uintptr_t; } + unsafe { rust_get_num_cpus() as usize } } } diff --git a/src/rt/rust_builtin.c b/src/rt/rust_builtin.c index 1a2917a1dd67f..76a3debef59a4 100644 --- a/src/rt/rust_builtin.c +++ b/src/rt/rust_builtin.c @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#if !defined(_WIN32) + #include #include #include @@ -15,7 +17,6 @@ #include -#if !defined(_WIN32) #include #include #include @@ -23,12 +24,6 @@ #include #include #include -#else -#include -#include -#include -#include -#endif #ifdef __APPLE__ #include @@ -41,17 +36,8 @@ /* Foreign builtins. */ //include valgrind.h after stdint.h so that uintptr_t is defined for msys2 w64 -#ifndef _WIN32 #include "valgrind/valgrind.h" -#endif - -#if defined(_MSC_VER) -# define RUST_BUILTIN_API __declspec(dllexport) -#else -# define RUST_BUILTIN_API -#endif -#ifndef _WIN32 char* rust_list_dir_val(struct dirent* entry_ptr) { return entry_ptr->d_name; @@ -92,17 +78,8 @@ int rust_dirent_t_size() { return sizeof(struct dirent); } -#endif - -#if defined(_WIN32) -int -get_num_cpus() { - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - return (int) sysinfo.dwNumberOfProcessors; -} -#elif defined(__BSD__) +#if defined(__BSD__) int get_num_cpus() { /* swiped from http://stackoverflow.com/questions/150355/ @@ -136,7 +113,6 @@ get_num_cpus() { } #endif -RUST_BUILTIN_API uintptr_t rust_get_num_cpus() { return get_num_cpus(); @@ -144,11 +120,7 @@ rust_get_num_cpus() { uintptr_t rust_running_on_valgrind() { -#ifdef _WIN32 - return 0; -#else return RUNNING_ON_VALGRIND; -#endif } #if defined(__DragonFly__) @@ -484,6 +456,8 @@ const char * rust_current_exe() { #endif +#endif // !defined(_WIN32) + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_try_msvc_32.ll b/src/rt/rust_try_msvc_32.ll new file mode 100644 index 0000000000000..bdee53b136e10 --- /dev/null +++ b/src/rt/rust_try_msvc_32.ll @@ -0,0 +1,42 @@ +; Copyright 2015 The Rust Project Developers. See the COPYRIGHT +; file at the top-level directory of this distribution and at +; http://rust-lang.org/COPYRIGHT. +; +; Licensed under the Apache License, Version 2.0 or the MIT license +; , at your +; option. This file may not be copied, modified, or distributed +; except according to those terms. + +; For more comments about what's going on here see rust_try_msvc_64.ll. The only +; difference between that and this file is the personality function used as it's +; different for 32-bit MSVC than it is for 64-bit. + +define i8* @rust_try(void (i8*)* %f, i8* %env) + personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) +{ + invoke void %f(i8* %env) + to label %normal + unwind label %catch + +normal: + ret i8* null +catch: + %vals = landingpad { i8*, i32 } + catch i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*) + %ehptr = extractvalue { i8*, i32 } %vals, 0 + %sel = extractvalue { i8*, i32 } %vals, 1 + %filter_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*)) + %is_filter = icmp eq i32 %sel, %filter_sel + br i1 %is_filter, label %catch-return, label %catch-resume + +catch-return: + ret i8* %ehptr + +catch-resume: + resume { i8*, i32 } %vals +} + +declare i32 @_except_handler3(...) +declare i32 @__rust_try_filter(i8*, i8*) +declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind diff --git a/src/test/compile-fail/issue-26812.rs b/src/test/compile-fail/issue-26812.rs new file mode 100644 index 0000000000000..c1ccfe269cdd3 --- /dev/null +++ b/src/test/compile-fail/issue-26812.rs @@ -0,0 +1,12 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn avg(_: T) {} //~ ERROR associated type `Item` not found for `T` +fn main() {} diff --git a/src/test/run-pass/extern-pass-empty.rs b/src/test/run-pass/extern-pass-empty.rs index 17b0bb580fce2..21948d2e5ad23 100644 --- a/src/test/run-pass/extern-pass-empty.rs +++ b/src/test/run-pass/extern-pass-empty.rs @@ -11,6 +11,7 @@ // Test a foreign function that accepts empty struct. // pretty-expanded FIXME #23616 +// ignore-msvc struct TwoU8s { one: u8, diff --git a/src/test/run-pass/issue-2214.rs b/src/test/run-pass/issue-2214.rs index 775cfb0ee4219..316e379e664ae 100644 --- a/src/test/run-pass/issue-2214.rs +++ b/src/test/run-pass/issue-2214.rs @@ -37,7 +37,7 @@ mod m { #[link_name="lgamma_r"] pub fn lgamma(n: c_double, sign: &mut c_int) -> c_double; #[cfg(windows)] - #[link_name="__lgamma_r"] + #[link_name="lgamma"] pub fn lgamma(n: c_double, sign: &mut c_int) -> c_double; } } diff --git a/src/test/run-pass/issue-26805.rs b/src/test/run-pass/issue-26805.rs new file mode 100644 index 0000000000000..c996c8f65ac8b --- /dev/null +++ b/src/test/run-pass/issue-26805.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct NonOrd; + +fn main() { + let _: Box> = Box::new(vec![NonOrd].into_iter()); +}