diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 6557b8410b196..f2e5d0b6b1a01 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -96,6 +96,139 @@ pub fn docs(build: &Build, stage: u32, host: &str) { } } +fn find_files(files: &[&str], path: &[PathBuf]) -> Vec { + let mut found = Vec::new(); + + for file in files { + let file_path = + path.iter() + .map(|dir| dir.join(file)) + .find(|p| p.exists()); + + if let Some(file_path) = file_path { + found.push(file_path); + } else { + panic!("Could not find '{}' in {:?}", file, path); + } + } + + found +} + +fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build: &Build) { + //Ask gcc where it keeps its stuff + let mut cmd = Command::new(build.cc(target_triple)); + cmd.arg("-print-search-dirs"); + build.run_quiet(&mut cmd); + let gcc_out = + String::from_utf8( + cmd + .output() + .expect("failed to execute gcc") + .stdout).expect("gcc.exe output was not utf8"); + + let mut bin_path: Vec<_> = + env::split_paths(&env::var_os("PATH").unwrap_or_default()) + .collect(); + let mut lib_path = Vec::new(); + + for line in gcc_out.lines() { + let idx = line.find(':').unwrap(); + let key = &line[..idx]; + let trim_chars: &[_] = &[' ', '=']; + let value = + line[(idx + 1)..] + .trim_left_matches(trim_chars) + .split(';') + .map(|s| PathBuf::from(s)); + + if key == "programs" { + bin_path.extend(value); + } else if key == "libraries" { + lib_path.extend(value); + } + } + + let target_tools = vec!["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "libwinpthread-1.dll"]; + let mut rustc_dlls = vec!["libstdc++-6.dll", "libwinpthread-1.dll"]; + if target_triple.starts_with("i686-") { + rustc_dlls.push("libgcc_s_dw2-1.dll"); + } else { + rustc_dlls.push("libgcc_s_seh-1.dll"); + } + + let target_libs = vec![ //MinGW libs + "libgcc.a", + "libgcc_eh.a", + "libgcc_s.a", + "libm.a", + "libmingw32.a", + "libmingwex.a", + "libstdc++.a", + "libiconv.a", + "libmoldname.a", + "libpthread.a", + //Windows import libs + "libadvapi32.a", + "libbcrypt.a", + "libcomctl32.a", + "libcomdlg32.a", + "libcrypt32.a", + "libgdi32.a", + "libimagehlp.a", + "libiphlpapi.a", + "libkernel32.a", + "libmsvcrt.a", + "libodbc32.a", + "libole32.a", + "liboleaut32.a", + "libopengl32.a", + "libpsapi.a", + "librpcrt4.a", + "libsetupapi.a", + "libshell32.a", + "libuser32.a", + "libuserenv.a", + "libuuid.a", + "libwinhttp.a", + "libwinmm.a", + "libwinspool.a", + "libws2_32.a", + "libwsock32.a", + ]; + + //Find mingw artifacts we want to bundle + let target_tools = find_files(&target_tools, &bin_path); + let rustc_dlls = find_files(&rustc_dlls, &bin_path); + let target_libs = find_files(&target_libs, &lib_path); + + fn copy_to_folder(src: &Path, dest_folder: &Path) { + let file_name = src.file_name().unwrap().to_os_string(); + let dest = dest_folder.join(file_name); + copy(src, &dest); + } + + //Copy runtime dlls next to rustc.exe + let dist_bin_dir = rust_root.join("bin/"); + for src in rustc_dlls { + copy_to_folder(&src, &dist_bin_dir); + } + + //Copy platform tools to platform-specific bin directory + let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin"); + fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed"); + for src in target_tools { + copy_to_folder(&src, &target_bin_dir); + } + + //Copy platform libs to platform-specific lib directory + let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib"); + fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed"); + for src in target_libs { + copy_to_folder(&src, &target_lib_dir); + } +} + /// Build the `rust-mingw` installer component. /// /// This contains all the bits and pieces to run the MinGW Windows targets @@ -109,18 +242,11 @@ pub fn mingw(build: &Build, host: &str) { let _ = fs::remove_dir_all(&image); t!(fs::create_dir_all(&image)); - // The first argument to the script is a "temporary directory" which is just + // The first argument is a "temporary directory" which is just // thrown away (this contains the runtime DLLs included in the rustc package // above) and the second argument is where to place all the MinGW components // (which is what we want). - // - // FIXME: this script should be rewritten into Rust - let mut cmd = Command::new(build.python()); - cmd.arg(build.src.join("src/etc/make-win-dist.py")) - .arg(tmpdir(build)) - .arg(&image) - .arg(host); - build.run(&mut cmd); + make_win_dist(&tmpdir(build), &image, host, &build); let mut cmd = rust_installer(build); cmd.arg("generate") @@ -172,15 +298,8 @@ pub fn rustc(build: &Build, stage: u32, host: &str) { // anything requiring us to distribute a license, but it's likely the // install will *also* include the rust-mingw package, which also needs // licenses, so to be safe we just include it here in all MinGW packages. - // - // FIXME: this script should be rewritten into Rust if host.contains("pc-windows-gnu") { - let mut cmd = Command::new(build.python()); - cmd.arg(build.src.join("src/etc/make-win-dist.py")) - .arg(&image) - .arg(tmpdir(build)) - .arg(host); - build.run(&mut cmd); + make_win_dist(&image, &tmpdir(build), host, build); let dst = image.join("share/doc"); t!(fs::create_dir_all(&dst)); diff --git a/src/etc/make-win-dist.py b/src/etc/make-win-dist.py deleted file mode 100644 index 4699fefbb20e3..0000000000000 --- a/src/etc/make-win-dist.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2013-2014 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. - -# Script parameters: -# argv[1] = rust component root, -# argv[2] = gcc component root, -# argv[3] = target triple -# The first two correspond to the two installable components defined in the setup script. - -import sys -import os -import shutil -import subprocess - - -def find_files(files, path): - found = [] - for fname in files: - for dir in path: - filepath = os.path.normpath(os.path.join(dir, fname)) - if os.path.isfile(filepath): - found.append(filepath) - break - else: - raise Exception("Could not find '%s' in %s" % (fname, path)) - return found - - -# rust_root - root directory of the host binaries image -# plat_root - root directory of the target platform tools and libs image -# (the two get overlayed on top of each other during installation) -# target_triple - triple of the target image being layed out -def make_win_dist(rust_root, plat_root, target_triple): - # Ask gcc where it keeps its stuff - gcc_out = subprocess.check_output(["gcc.exe", "-print-search-dirs"]) - bin_path = os.environ["PATH"].split(os.pathsep) - lib_path = [] - for line in gcc_out.splitlines(): - key, val = line.split(':', 1) - if key == "programs": - bin_path.extend(val.lstrip(' =').split(';')) - elif key == "libraries": - lib_path.extend(val.lstrip(' =').split(';')) - - target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", - "libwinpthread-1.dll"] - - rustc_dlls = ["libstdc++-6.dll", "libwinpthread-1.dll"] - if target_triple.startswith("i686-"): - rustc_dlls.append("libgcc_s_dw2-1.dll") - else: - rustc_dlls.append("libgcc_s_seh-1.dll") - - target_libs = [ # MinGW libs - "libgcc.a", - "libgcc_eh.a", - "libgcc_s.a", - "libm.a", - "libmingw32.a", - "libmingwex.a", - "libstdc++.a", - "libiconv.a", - "libmoldname.a", - "libpthread.a", - # Windows import libs - "libadvapi32.a", - "libbcrypt.a", - "libcomctl32.a", - "libcomdlg32.a", - "libcrypt32.a", - "libgdi32.a", - "libimagehlp.a", - "libiphlpapi.a", - "libkernel32.a", - "libmsvcrt.a", - "libodbc32.a", - "libole32.a", - "liboleaut32.a", - "libopengl32.a", - "libpsapi.a", - "librpcrt4.a", - "libsetupapi.a", - "libshell32.a", - "libuser32.a", - "libuserenv.a", - "libuuid.a", - "libwinhttp.a", - "libwinmm.a", - "libwinspool.a", - "libws2_32.a", - "libwsock32.a", - ] - - # Find mingw artifacts we want to bundle - target_tools = find_files(target_tools, bin_path) - rustc_dlls = find_files(rustc_dlls, bin_path) - target_libs = find_files(target_libs, lib_path) - - # Copy runtime dlls next to rustc.exe - dist_bin_dir = os.path.join(rust_root, "bin") - for src in rustc_dlls: - shutil.copy(src, dist_bin_dir) - - # Copy platform tools to platform-specific bin directory - target_bin_dir = os.path.join(plat_root, "lib", "rustlib", target_triple, "bin") - if not os.path.exists(target_bin_dir): - os.makedirs(target_bin_dir) - for src in target_tools: - shutil.copy(src, target_bin_dir) - - # Copy platform libs to platform-specific lib directory - target_lib_dir = os.path.join(plat_root, "lib", "rustlib", target_triple, "lib") - if not os.path.exists(target_lib_dir): - os.makedirs(target_lib_dir) - for src in target_libs: - shutil.copy(src, target_lib_dir) - -if __name__ == "__main__": - make_win_dist(sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 013f02685bad1..6cc374b13b7b3 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -12,6 +12,7 @@ use super::Wrapping; use ops::*; +#[allow(unused_macros)] macro_rules! sh_impl_signed { ($t:ident, $f:ident) => ( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 6942f5fb67b60..fc3af096b1838 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -799,6 +799,7 @@ macro_rules! neg_impl_numeric { ($($t:ty)*) => { neg_impl_core!{ x => -x, $($t)*} } } +#[allow(unused_macros)] macro_rules! neg_impl_unsigned { ($($t:ty)*) => { neg_impl_core!{ x => { diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index e681d55cf94b8..07140f71aebaa 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -76,6 +76,12 @@ declare_lint! { "detects unreachable patterns" } +declare_lint! { + pub UNUSED_MACROS, + Warn, + "detects macros that were not used" +} + declare_lint! { pub WARNINGS, Warn, @@ -259,6 +265,7 @@ impl LintPass for HardwiredLints { DEAD_CODE, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, + UNUSED_MACROS, WARNINGS, UNUSED_FEATURES, STABLE_FEATURES, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 60e671f1772e3..9d5ba2c8f9501 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -49,6 +49,7 @@ use hir; use hir::def_id::LOCAL_CRATE; use hir::intravisit as hir_visit; use syntax::visit as ast_visit; +use syntax::tokenstream::ThinTokenStream; /// Information about the registered lints. /// @@ -1125,6 +1126,13 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_attribute(&mut self, attr: &'a ast::Attribute) { run_lints!(self, check_attribute, early_passes, attr); } + + fn visit_mac_def(&mut self, _mac: &'a ThinTokenStream, id: ast::NodeId) { + let lints = self.sess.lints.borrow_mut().take(id); + for early_lint in lints { + self.early_lint(&early_lint); + } + } } enum CheckLintNameResult { diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 7b5e2253109aa..17564671a1e36 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -116,6 +116,7 @@ pub fn record_time(accu: &Cell, f: F) -> T where } // Like std::macros::try!, but for Option<>. +#[cfg(unix)] macro_rules! option_try( ($e:expr) => (match $e { Some(e) => e, None => return None }) ); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 8fddbe110b0e6..eff5d2b2f37f1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -699,6 +699,8 @@ pub fn phase_2_configure_and_expand(sess: &Session, let krate = ecx.monotonic_expander().expand_crate(krate); + ecx.check_unused_macros(); + let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect(); missing_fragment_specifiers.sort(); diff --git a/src/librustc_incremental/persist/preds/compress/test_macro.rs b/src/librustc_incremental/persist/preds/compress/test_macro.rs index 31b30d2b2857c..044b143e30625 100644 --- a/src/librustc_incremental/persist/preds/compress/test_macro.rs +++ b/src/librustc_incremental/persist/preds/compress/test_macro.rs @@ -37,14 +37,3 @@ macro_rules! graph { } } } - -macro_rules! set { - ($( $value:expr ),*) => { - { - use $crate::rustc_data_structures::fx::FxHashSet; - let mut set = FxHashSet(); - $(set.insert($value);)* - set - } - } -} diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 2d0b5a6a51c6b..479c7206cb4cb 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -171,7 +171,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UNUSED_MUST_USE, UNUSED_UNSAFE, PATH_STATEMENTS, - UNUSED_ATTRIBUTES); + UNUSED_ATTRIBUTES, + UNUSED_MACROS); // Guidelines for creating a future incompatibility lint: // diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index cdde56f5f634b..3027489d65be2 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -103,7 +103,8 @@ impl<'a> Registry<'a> { } self.syntax_exts.push((name, match extension { NormalTT(ext, _, allow_internal_unstable) => { - NormalTT(ext, Some(self.krate_span), allow_internal_unstable) + let nid = ast::CRATE_NODE_ID; + NormalTT(ext, Some((nid, self.krate_span)), allow_internal_unstable) } IdentTT(ext, _, allow_internal_unstable) => { IdentTT(ext, Some(self.krate_span), allow_internal_unstable) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 774e84de36638..6ea666e21dcdd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1187,6 +1187,10 @@ pub struct Resolver<'a> { pub whitelisted_legacy_custom_derives: Vec, pub found_unresolved_macro: bool, + // List of crate local macros that we need to warn about as being unused. + // Right now this only includes macro_rules! macros. + unused_macros: FxHashSet, + // Maps the `Mark` of an expansion to its containing module or block. invocations: FxHashMap>, @@ -1392,6 +1396,7 @@ impl<'a> Resolver<'a> { potentially_unused_imports: Vec::new(), struct_constructors: DefIdMap(), found_unresolved_macro: false, + unused_macros: FxHashSet(), } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index c08421cb9374e..231d30cd2a22d 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -16,7 +16,7 @@ use resolve_imports::ImportResolver; use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}; use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; -use rustc::ty; +use rustc::{ty, lint}; use syntax::ast::{self, Name, Ident}; use syntax::attr::{self, HasAttrs}; use syntax::errors::DiagnosticBuilder; @@ -291,12 +291,32 @@ impl<'a> base::Resolver for Resolver<'a> { }, }; self.macro_defs.insert(invoc.expansion_data.mark, def.def_id()); + self.unused_macros.remove(&def.def_id()); Ok(Some(self.get_macro(def))) } fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) -> Result, Determinacy> { - self.resolve_macro_to_def(scope, path, kind, force).map(|def| self.get_macro(def)) + self.resolve_macro_to_def(scope, path, kind, force).map(|def| { + self.unused_macros.remove(&def.def_id()); + self.get_macro(def) + }) + } + + fn check_unused_macros(&self) { + for did in self.unused_macros.iter() { + let id_span = match *self.macro_map[did] { + SyntaxExtension::NormalTT(_, isp, _) => isp, + _ => None, + }; + if let Some((id, span)) = id_span { + let lint = lint::builtin::UNUSED_MACROS; + let msg = "unused macro definition".to_string(); + self.session.add_lint(lint, id, span, msg); + } else { + bug!("attempted to create unused macro error, but span not available"); + } + } } } @@ -687,6 +707,8 @@ impl<'a> Resolver<'a> { if attr::contains_name(&item.attrs, "macro_export") { let def = Def::Macro(def_id, MacroKind::Bang); self.macro_exports.push(Export { name: ident.name, def: def, span: item.span }); + } else { + self.unused_macros.insert(def_id); } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index c7ec379b0de25..7e70bb92cd6e0 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -251,9 +251,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let bound_list = unsatisfied_predicates.iter() .map(|p| format!("`{} : {}`", p.self_ty(), p)) .collect::>() - .join(", "); + .join("\n"); err.note(&format!("the method `{}` exists but the following trait bounds \ - were not satisfied: {}", + were not satisfied:\n{}", item_name, bound_list)); } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 5db82e23bbf1e..612793e2567f1 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1177,7 +1177,6 @@ impl fmt::Display for AbiSpace { let quot = if f.alternate() { "\"" } else { """ }; match self.0 { Abi::Rust => Ok(()), - Abi::C => write!(f, "extern "), abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()), } } diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index e2b22b1d89f04..c2c6e6cf87dff 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -19,16 +19,16 @@ use mem; /// A thread local storage key which owns its contents. /// /// This key uses the fastest possible implementation available to it for the -/// target platform. It is instantiated with the `thread_local!` macro and the -/// primary method is the `with` method. +/// target platform. It is instantiated with the [`thread_local!`] macro and the +/// primary method is the [`with`] method. /// -/// The `with` method yields a reference to the contained value which cannot be +/// The [`with`] method yields a reference to the contained value which cannot be /// sent across threads or escape the given closure. /// /// # Initialization and Destruction /// -/// Initialization is dynamically performed on the first call to `with()` -/// within a thread, and values that implement `Drop` get destructed when a +/// Initialization is dynamically performed on the first call to [`with`] +/// within a thread, and values that implement [`Drop`] get destructed when a /// thread exits. Some caveats apply, which are explained below. /// /// # Examples @@ -77,6 +77,10 @@ use mem; /// 3. On macOS, initializing TLS during destruction of other TLS slots can /// sometimes cancel *all* destructors for the current thread, whether or not /// the slots have already had their destructors run or not. +/// +/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with +/// [`thread_local!`]: ../../std/macro.thread_local.html +/// [`Drop`]: ../../std/ops/trait.Drop.html #[stable(feature = "rust1", since = "1.0.0")] pub struct LocalKey { // This outer `LocalKey` type is what's going to be stored in statics, @@ -106,7 +110,7 @@ impl fmt::Debug for LocalKey { } } -/// Declare a new thread local storage key of type `std::thread::LocalKey`. +/// Declare a new thread local storage key of type [`std::thread::LocalKey`]. /// /// # Syntax /// @@ -124,8 +128,10 @@ impl fmt::Debug for LocalKey { /// # fn main() {} /// ``` /// -/// See [LocalKey documentation](thread/struct.LocalKey.html) for more +/// See [LocalKey documentation][`std::thread::LocalKey`] for more /// information. +/// +/// [`std::thread::LocalKey`]: ../std/thread/struct.LocalKey.html #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable] @@ -195,11 +201,13 @@ macro_rules! __thread_local_inner { #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum LocalKeyState { /// All keys are in this state whenever a thread starts. Keys will - /// transition to the `Valid` state once the first call to `with` happens + /// transition to the `Valid` state once the first call to [`with`] happens /// and the initialization expression succeeds. /// /// Keys in the `Uninitialized` state will yield a reference to the closure - /// passed to `with` so long as the initialization routine does not panic. + /// passed to [`with`] so long as the initialization routine does not panic. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with Uninitialized, /// Once a key has been accessed successfully, it will enter the `Valid` @@ -208,7 +216,9 @@ pub enum LocalKeyState { /// `Destroyed` state. /// /// Keys in the `Valid` state will be guaranteed to yield a reference to the - /// closure passed to `with`. + /// closure passed to [`with`]. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with Valid, /// When a thread exits, the destructors for keys will be run (if @@ -216,7 +226,9 @@ pub enum LocalKeyState { /// destructor has run, a key is in the `Destroyed` state. /// /// Keys in the `Destroyed` states will trigger a panic when accessed via - /// `with`. + /// [`with`]. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with Destroyed, } @@ -283,23 +295,26 @@ impl LocalKey { /// Query the current state of this key. /// /// A key is initially in the `Uninitialized` state whenever a thread - /// starts. It will remain in this state up until the first call to `with` + /// starts. It will remain in this state up until the first call to [`with`] /// within a thread has run the initialization expression successfully. /// /// Once the initialization expression succeeds, the key transitions to the - /// `Valid` state which will guarantee that future calls to `with` will + /// `Valid` state which will guarantee that future calls to [`with`] will /// succeed within the thread. /// /// When a thread exits, each key will be destroyed in turn, and as keys are /// destroyed they will enter the `Destroyed` state just before the /// destructor starts to run. Keys may remain in the `Destroyed` state after /// destruction has completed. Keys without destructors (e.g. with types - /// that are `Copy`), may never enter the `Destroyed` state. + /// that are [`Copy`]), may never enter the `Destroyed` state. /// /// Keys in the `Uninitialized` state can be accessed so long as the /// initialization does not panic. Keys in the `Valid` state are guaranteed /// to be able to be accessed. Keys in the `Destroyed` state will panic on - /// any call to `with`. + /// any call to [`with`]. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with + /// [`Copy`]: ../../std/marker/trait.Copy.html #[unstable(feature = "thread_local_state", reason = "state querying was recently added", issue = "27716")] diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 200368be275c3..154406a1d8bd7 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -180,8 +180,33 @@ pub use self::local::{LocalKey, LocalKeyState}; // Builder //////////////////////////////////////////////////////////////////////////////// -/// Thread configuration. Provides detailed control over the properties -/// and behavior of new threads. +/// Thread factory, which can be used in order to configure the properties of +/// a new thread. +/// +/// Methods can be chained on it in order to configure it. +/// +/// The two configurations available are: +/// +/// - [`name`]: allows to give a name to the thread which is currently +/// only used in `panic` messages. +/// - [`stack_size`]: specifies the desired stack size. Note that this can +/// be overriden by the OS. +/// +/// If the [`stack_size`] field is not specified, the stack size +/// will be the `RUST_MIN_STACK` environment variable. If it is +/// not specified either, a sensible default will be set. +/// +/// If the [`name`] field is not specified, the thread will not be named. +/// +/// The [`spawn`] method will take ownership of the builder and create an +/// [`io::Result`] to the thread handle with the given configuration. +/// +/// The [`thread::spawn`] free function uses a `Builder` with default +/// configuration and [`unwrap`]s its return value. +/// +/// You may want to use [`spawn`] instead of [`thread::spawn`], when you want +/// to recover from a failure to launch a thread, indeed the free function will +/// panick where the `Builder` method will return a [`io::Result`]. /// /// # Examples /// @@ -196,6 +221,13 @@ pub use self::local::{LocalKey, LocalKeyState}; /// /// handler.join().unwrap(); /// ``` +/// +/// [`thread::spawn`]: ../../std/thread/fn.spawn.html +/// [`stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size +/// [`name`]: ../../std/thread/struct.Builder.html#method.name +/// [`spawn`]: ../../std/thread/struct.Builder.html#method.spawn +/// [`io::Result`]: ../../std/io/type.Result.html +/// [`unwrap`]: ../../std/result/enum.Result.html#method.unwrap #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Builder { @@ -209,11 +241,6 @@ impl Builder { /// Generates the base configuration for spawning a thread, from which /// configuration methods can be chained. /// - /// If the [`stack_size`] field is not specified, the stack size - /// will be the `RUST_MIN_STACK` environment variable. If it is - /// not specified either, a sensible default will be set (2MB as - /// of the writting of this doc). - /// /// # Examples /// /// ``` @@ -229,8 +256,6 @@ impl Builder { /// /// handler.join().unwrap(); /// ``` - /// - /// [`stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Builder { Builder { @@ -280,9 +305,10 @@ impl Builder { self } - /// Spawns a new thread, and returns a join handle for it. + /// Spawns a new thread by taking ownership of the `Builder`, and returns an + /// [`io::Result`] to its [`JoinHandle`]. /// - /// The child thread may outlive the parent (unless the parent thread + /// The spawned thread may outlive the caller (unless the caller thread /// is the main thread; the whole process is terminated when the main /// thread finishes). The join handle can be used to block on /// termination of the child thread, including recovering its panics. @@ -297,6 +323,7 @@ impl Builder { /// /// [`spawn`]: ../../std/thread/fn.spawn.html /// [`io::Result`]: ../../std/io/type.Result.html + /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html /// /// # Examples /// @@ -468,6 +495,23 @@ pub fn current() -> Thread { /// Cooperatively gives up a timeslice to the OS scheduler. /// +/// This is used when the programmer knows that the thread will have nothing +/// to do for some time, and thus avoid wasting computing time. +/// +/// For example when polling on a resource, it is common to check that it is +/// available, and if not to yield in order to avoid busy waiting. +/// +/// Thus the pattern of `yield`ing after a failed poll is rather common when +/// implementing low-level shared resources or synchronization primitives. +/// +/// However programmers will usualy prefer to use, [`channel`]s, [`Condvar`]s, +/// [`Mutex`]es or [`join`] for their synchronisation routines, as they avoid +/// thinking about thread schedulling. +/// +/// Note that [`channel`]s for example are implemented using this primitive. +/// Indeed when you call `send` or `recv`, which are blocking, they will yield +/// if the channel is not available. +/// /// # Examples /// /// ``` @@ -475,6 +519,12 @@ pub fn current() -> Thread { /// /// thread::yield_now(); /// ``` +/// +/// [`channel`]: ../../std/sync/mpsc/index.html +/// [`spawn`]: ../../std/thread/fn.spawn.html +/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join +/// [`Mutex`]: ../../std/sync/struct.Mutex.html +/// [`Condvar`]: ../../std/sync/struct.Condvar.html #[stable(feature = "rust1", since = "1.0.0")] pub fn yield_now() { imp::Thread::yield_now() diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index f731c5abdd6a1..86202f77dbf8a 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -535,7 +535,7 @@ pub enum SyntaxExtension { /// /// The `bool` dictates whether the contents of the macro can /// directly use `#[unstable]` things (true == yes). - NormalTT(Box, Option, bool), + NormalTT(Box, Option<(ast::NodeId, Span)>, bool), /// A function-like syntax extension that has an extra ident before /// the block. @@ -589,6 +589,7 @@ pub trait Resolver { -> Result>, Determinacy>; fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) -> Result, Determinacy>; + fn check_unused_macros(&self); } #[derive(Copy, Clone, Debug)] @@ -618,6 +619,7 @@ impl Resolver for DummyResolver { _force: bool) -> Result, Determinacy> { Err(Determinacy::Determined) } + fn check_unused_macros(&self) {} } #[derive(Clone)] @@ -800,6 +802,10 @@ impl<'a> ExtCtxt<'a> { pub fn name_of(&self, st: &str) -> ast::Name { Symbol::intern(st) } + + pub fn check_unused_macros(&self) { + self.resolver.check_unused_macros(); + } } /// Extract a string literal from the macro expanded version of `expr`, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a8aa103f80a8e..75dd09f23115e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -469,7 +469,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), - span: exp_span, + span: exp_span.map(|(_, s)| s), allow_internal_unstable: allow_internal_unstable, }, }); diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index eb0b7c29f8d9a..780b7ec8c2a16 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -267,11 +267,12 @@ pub fn parse_failure_msg(tok: Token) -> String { /// Perform a token equality check, ignoring syntax context (that is, an unhygienic comparison) fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { - match (t1,t2) { - (&token::Ident(id1),&token::Ident(id2)) - | (&token::Lifetime(id1),&token::Lifetime(id2)) => - id1.name == id2.name, - _ => *t1 == *t2 + if let (Some(id1), Some(id2)) = (t1.ident(), t2.ident()) { + id1.name == id2.name + } else if let (&token::Lifetime(id1), &token::Lifetime(id2)) = (t1, t2) { + id1.name == id2.name + } else { + *t1 == *t2 } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index f959ccc989e2e..39a60e5c08010 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -252,7 +252,9 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) valid: valid, }); - NormalTT(exp, Some(def.span), attr::contains_name(&def.attrs, "allow_internal_unstable")) + NormalTT(exp, + Some((def.id, def.span)), + attr::contains_name(&def.attrs, "allow_internal_unstable")) } fn check_lhs_nt_follows(sess: &ParseSess, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9288d95009c1d..ee9d1980fab66 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -27,6 +27,7 @@ use abi::Abi; use ast::*; use syntax_pos::Span; use codemap::Spanned; +use tokenstream::ThinTokenStream; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { @@ -112,6 +113,9 @@ pub trait Visitor<'ast>: Sized { // definition in your trait impl: // visit::walk_mac(self, _mac) } + fn visit_mac_def(&mut self, _mac: &'ast ThinTokenStream, _id: NodeId) { + // Nothing to do + } fn visit_path(&mut self, path: &'ast Path, _id: NodeId) { walk_path(self, path) } @@ -290,7 +294,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_trait_item, methods); } ItemKind::Mac(ref mac) => visitor.visit_mac(mac), - ItemKind::MacroDef(..) => {}, + ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id), } walk_list!(visitor, visit_attribute, &item.attrs); } diff --git a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs index e0066dd43be89..ddd8631f02e62 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs @@ -14,6 +14,7 @@ // aux-build:bang_proc_macro.rs #![feature(proc_macro)] +#![allow(unused_macros)] #[macro_use] extern crate derive_foo; diff --git a/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs b/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs index 1aabe6b87dff5..9af501b141955 100644 --- a/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs +++ b/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs @@ -10,6 +10,8 @@ // gate-test-allow_internal_unstable +#![allow(unused_macros)] + macro_rules! bar { () => { // more layers don't help: diff --git a/src/test/compile-fail/feature-gate-allow-internal-unstable.rs b/src/test/compile-fail/feature-gate-allow-internal-unstable.rs index 8a2d8dddac074..61a362cb37fb2 100644 --- a/src/test/compile-fail/feature-gate-allow-internal-unstable.rs +++ b/src/test/compile-fail/feature-gate-allow-internal-unstable.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + #[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps macro_rules! foo { () => {} diff --git a/src/test/compile-fail/invalid-macro-matcher.rs b/src/test/compile-fail/invalid-macro-matcher.rs index a0ac5d4c72041..d710f5647dd9f 100644 --- a/src/test/compile-fail/invalid-macro-matcher.rs +++ b/src/test/compile-fail/invalid-macro-matcher.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! invalid { _ => (); //~ ERROR invalid macro matcher } diff --git a/src/test/compile-fail/issue-21356.rs b/src/test/compile-fail/issue-21356.rs index fefd432e22982..f66c09291cc9e 100644 --- a/src/test/compile-fail/issue-21356.rs +++ b/src/test/compile-fail/issue-21356.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! test { ($wrong:t_ty ..) => () } //~^ ERROR: invalid fragment specifier `t_ty` diff --git a/src/test/compile-fail/issue-39388.rs b/src/test/compile-fail/issue-39388.rs index 6994d2199d276..15eef429eab97 100644 --- a/src/test/compile-fail/issue-39388.rs +++ b/src/test/compile-fail/issue-39388.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! assign { (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected `*` or `+` $($a)* = $($b)* diff --git a/src/test/compile-fail/issue-39404.rs b/src/test/compile-fail/issue-39404.rs index 0168ae7d91017..8b49772494a66 100644 --- a/src/test/compile-fail/issue-39404.rs +++ b/src/test/compile-fail/issue-39404.rs @@ -9,6 +9,7 @@ // except according to those terms. #![deny(missing_fragment_specifier)] //~ NOTE lint level defined here +#![allow(unused_macros)] macro_rules! m { ($i) => {} } //~^ ERROR missing fragment specifier diff --git a/src/test/compile-fail/issue-5067.rs b/src/test/compile-fail/issue-5067.rs index 1c543a5fdacbb..267362f902d72 100644 --- a/src/test/compile-fail/issue-5067.rs +++ b/src/test/compile-fail/issue-5067.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! foo { ( $()* ) => {}; //~^ ERROR repetition matches empty token tree diff --git a/src/test/compile-fail/macro-expansion-tests.rs b/src/test/compile-fail/macro-expansion-tests.rs index ada06b0b3f452..06f2d86e5d9ba 100644 --- a/src/test/compile-fail/macro-expansion-tests.rs +++ b/src/test/compile-fail/macro-expansion-tests.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + mod macros_cant_escape_fns { fn f() { macro_rules! m { () => { 3 + 4 } } diff --git a/src/test/compile-fail/macro-follow.rs b/src/test/compile-fail/macro-follow.rs index 001bc42274b4d..6e80e9b574bcf 100644 --- a/src/test/compile-fail/macro-follow.rs +++ b/src/test/compile-fail/macro-follow.rs @@ -10,6 +10,8 @@ // // Check the macro follow sets (see corresponding rpass test). +#![allow(unused_macros)] + // FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)} macro_rules! follow_pat { ($p:pat ()) => {}; //~ERROR `$p:pat` is followed by `(` diff --git a/src/test/compile-fail/macro-followed-by-seq-bad.rs b/src/test/compile-fail/macro-followed-by-seq-bad.rs index 0ee2221bbc14b..21cc946ded605 100644 --- a/src/test/compile-fail/macro-followed-by-seq-bad.rs +++ b/src/test/compile-fail/macro-followed-by-seq-bad.rs @@ -11,6 +11,8 @@ // Regression test for issue #25436: check that things which can be // followed by any token also permit X* to come afterwards. +#![allow(unused_macros)] + macro_rules! foo { ( $a:expr $($b:tt)* ) => { }; //~ ERROR not allowed for `expr` fragments ( $a:ty $($b:tt)* ) => { }; //~ ERROR not allowed for `ty` fragments diff --git a/src/test/compile-fail/macro-input-future-proofing.rs b/src/test/compile-fail/macro-input-future-proofing.rs index fe758a4a6310f..e5fdba63b0f15 100644 --- a/src/test/compile-fail/macro-input-future-proofing.rs +++ b/src/test/compile-fail/macro-input-future-proofing.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! errors_everywhere { ($ty:ty <) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty` ($ty:ty < foo ,) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty` diff --git a/src/test/compile-fail/macro-shadowing.rs b/src/test/compile-fail/macro-shadowing.rs index 8381dc34a6a15..f5e7305e4ea9e 100644 --- a/src/test/compile-fail/macro-shadowing.rs +++ b/src/test/compile-fail/macro-shadowing.rs @@ -10,6 +10,8 @@ // aux-build:two_macros.rs +#![allow(unused_macros)] + macro_rules! foo { () => {} } macro_rules! macro_one { () => {} } #[macro_use(macro_two)] extern crate two_macros; diff --git a/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs b/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs index b868b79365d9f..28a69e6f9e29b 100644 --- a/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs +++ b/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + // Issue #21370 macro_rules! test { diff --git a/src/test/compile-fail/unused-macro-with-follow-violation.rs b/src/test/compile-fail/unused-macro-with-follow-violation.rs index e9d09bb6ad9cd..dda0d3fc9557d 100644 --- a/src/test/compile-fail/unused-macro-with-follow-violation.rs +++ b/src/test/compile-fail/unused-macro-with-follow-violation.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! test { ($e:expr +) => () //~ ERROR not allowed for `expr` fragments } diff --git a/src/test/compile-fail/unused-macro.rs b/src/test/compile-fail/unused-macro.rs new file mode 100644 index 0000000000000..5e401c09bda59 --- /dev/null +++ b/src/test/compile-fail/unused-macro.rs @@ -0,0 +1,39 @@ +// Copyright 2017 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. + +#![deny(unused_macros)] + +// Most simple case +macro_rules! unused { //~ ERROR: unused macro definition + () => {}; +} + +// Test macros created by macros +macro_rules! create_macro { + () => { + macro_rules! m { //~ ERROR: unused macro definition + () => {}; + } + }; +} +create_macro!(); + +#[allow(unused_macros)] +mod bar { + // Test that putting the #[deny] close to the macro's definition + // works. + + #[deny(unused_macros)] + macro_rules! unused { //~ ERROR: unused macro definition + () => {}; + } +} + +fn main() {} diff --git a/src/test/compile-fail/user-defined-macro-rules.rs b/src/test/compile-fail/user-defined-macro-rules.rs index d55cef434f8d3..02e1a585fa89d 100644 --- a/src/test/compile-fail/user-defined-macro-rules.rs +++ b/src/test/compile-fail/user-defined-macro-rules.rs @@ -8,4 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! macro_rules { () => {} } //~ ERROR user-defined macros may not be named `macro_rules` diff --git a/src/test/run-pass/issue-41803.rs b/src/test/run-pass/issue-41803.rs new file mode 100644 index 0000000000000..e18b4204584e3 --- /dev/null +++ b/src/test/run-pass/issue-41803.rs @@ -0,0 +1,30 @@ +// Copyright 2017 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. + +/// A compile-time map from identifiers to arbitrary (heterogeneous) expressions +macro_rules! ident_map { + ( $name:ident = { $($key:ident => $e:expr,)* } ) => { + macro_rules! $name { + $( + ( $key ) => { $e }; + )* + // Empty invocation expands to nothing. Needed when the map is empty. + () => {}; + } + }; +} + +ident_map!(my_map = { + main => 0, +}); + +fn main() { + my_map!(main); +} diff --git a/src/test/rustdoc/extern-impl.rs b/src/test/rustdoc/extern-impl.rs index 0e78746704fb1..5c64b4118c3ab 100644 --- a/src/test/rustdoc/extern-impl.rs +++ b/src/test/rustdoc/extern-impl.rs @@ -18,9 +18,9 @@ impl Foo { pub fn rust0() {} // @has - '//code' 'fn rust1()' pub extern "Rust" fn rust1() {} - // @has - '//code' 'extern fn c0()' + // @has - '//code' 'extern "C" fn c0()' pub extern fn c0() {} - // @has - '//code' 'extern fn c1()' + // @has - '//code' 'extern "C" fn c1()' pub extern "C" fn c1() {} // @has - '//code' 'extern "system" fn system0()' pub extern "system" fn system0() {} @@ -31,7 +31,7 @@ pub trait Bar {} // @has - '//code' 'impl Bar for fn()' impl Bar for fn() {} -// @has - '//code' 'impl Bar for extern fn()' +// @has - '//code' 'impl Bar for extern "C" fn()' impl Bar for extern fn() {} // @has - '//code' 'impl Bar for extern "system" fn()' impl Bar for extern "system" fn() {} diff --git a/src/test/rustdoc/ffi.rs b/src/test/rustdoc/ffi.rs index 3997dcd81e153..8511d461703de 100644 --- a/src/test/rustdoc/ffi.rs +++ b/src/test/rustdoc/ffi.rs @@ -13,10 +13,10 @@ extern crate rustdoc_ffi as lib; -// @has ffi/fn.foreigner.html //pre 'pub unsafe extern fn foreigner(cold_as_ice: u32)' +// @has ffi/fn.foreigner.html //pre 'pub unsafe extern "C" fn foreigner(cold_as_ice: u32)' pub use lib::foreigner; extern "C" { - // @has ffi/fn.another.html //pre 'pub unsafe extern fn another(cold_as_ice: u32)' + // @has ffi/fn.another.html //pre 'pub unsafe extern "C" fn another(cold_as_ice: u32)' pub fn another(cold_as_ice: u32); } diff --git a/src/test/rustdoc/issue-22038.rs b/src/test/rustdoc/issue-22038.rs index 6f84428b0798f..75df53589454f 100644 --- a/src/test/rustdoc/issue-22038.rs +++ b/src/test/rustdoc/issue-22038.rs @@ -10,7 +10,7 @@ extern { // @has issue_22038/fn.foo1.html \ - // '//*[@class="rust fn"]' 'pub unsafe extern fn foo1()' + // '//*[@class="rust fn"]' 'pub unsafe extern "C" fn foo1()' pub fn foo1(); } @@ -21,7 +21,7 @@ extern "system" { } // @has issue_22038/fn.bar.html \ -// '//*[@class="rust fn"]' 'pub extern fn bar()' +// '//*[@class="rust fn"]' 'pub extern "C" fn bar()' pub extern fn bar() {} // @has issue_22038/fn.baz.html \ diff --git a/src/test/rustdoc/variadic.rs b/src/test/rustdoc/variadic.rs index 1b60c2a334fa5..6ba776ba4679f 100644 --- a/src/test/rustdoc/variadic.rs +++ b/src/test/rustdoc/variadic.rs @@ -9,6 +9,6 @@ // except according to those terms. extern "C" { - // @has variadic/fn.foo.html //pre 'pub unsafe extern fn foo(x: i32, ...)' + // @has variadic/fn.foo.html //pre 'pub unsafe extern "C" fn foo(x: i32, ...)' pub fn foo(x: i32, ...); } diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index adc229aaacc54..78e0f7e619b12 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -4,7 +4,9 @@ error: no method named `count` found for type `std::iter::Filter("str").fuse().filter(|a: &str| true).count(); | ^^^^^ | - = note: the method `count` exists but the following trait bounds were not satisfied: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53] : std::ops::FnMut<(&_,)>`, `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator` + = note: the method `count` exists but the following trait bounds were not satisfied: + `[closure@$DIR/issue-36053-2.rs:17:39: 17:53] : std::ops::FnMut<(&_,)>` + `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator` error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` implements the trait `for<'r> std::ops::FnMut<(&'r str,)>`, but the trait `for<'r> std::ops::FnMut<(&'r &str,)>` is required --> $DIR/issue-36053-2.rs:17:32 diff --git a/src/test/compile-fail/method-help-unsatisfied-bound.rs b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs similarity index 87% rename from src/test/compile-fail/method-help-unsatisfied-bound.rs rename to src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs index 6416d5467c890..a4eb445555112 100644 --- a/src/test/compile-fail/method-help-unsatisfied-bound.rs +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs @@ -14,5 +14,5 @@ fn main() { let a: Result<(), Foo> = Ok(()); a.unwrap(); //~^ ERROR no method named `unwrap` found for type `std::result::Result<(), Foo>` - //~| NOTE the following trait bounds were not satisfied: `Foo : std::fmt::Debug` + //~| NOTE the method `unwrap` exists but the following trait bounds were not satisfied } diff --git a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr new file mode 100644 index 0000000000000..2bd786c20fef0 --- /dev/null +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -0,0 +1,11 @@ +error: no method named `unwrap` found for type `std::result::Result<(), Foo>` in the current scope + --> $DIR/method-help-unsatisfied-bound.rs:15:7 + | +15 | a.unwrap(); + | ^^^^^^ + | + = note: the method `unwrap` exists but the following trait bounds were not satisfied: + `Foo : std::fmt::Debug` + +error: aborting due to previous error +